From f51d753f81c0862e18af48d701a57128572883ed Mon Sep 17 00:00:00 2001 From: Christian Gmeiner Date: Fri, 3 Jun 2022 14:37:05 +0200 Subject: drm/etnaviv: print offender task information on hangcheck recovery Track the pid per submit, so we can print the name and cmdline of the task which submitted the batch that caused the gpu to hang. Signed-off-by: Christian Gmeiner Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_gem.h | 1 + drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c | 6 ++++++ drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 18 +++++++++++++++++- drivers/gpu/drm/etnaviv/etnaviv_gpu.h | 2 +- drivers/gpu/drm/etnaviv/etnaviv_sched.c | 2 +- 5 files changed, 26 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.h b/drivers/gpu/drm/etnaviv/etnaviv_gem.h index 63688e6e4580..baa81cbf701a 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.h @@ -96,6 +96,7 @@ struct etnaviv_gem_submit { int out_fence_id; struct list_head node; /* GPU active submit list */ struct etnaviv_cmdbuf cmdbuf; + struct pid *pid; /* submitting process */ bool runtime_resumed; u32 exec_state; u32 flags; diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c index 1ac916b24891..1491159d0d20 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c @@ -399,6 +399,9 @@ static void submit_cleanup(struct kref *kref) mutex_unlock(&submit->gpu->fence_lock); dma_fence_put(submit->out_fence); } + + put_pid(submit->pid); + kfree(submit->pmrs); kfree(submit); } @@ -422,6 +425,7 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, struct sync_file *sync_file = NULL; struct ww_acquire_ctx ticket; int out_fence_fd = -1; + struct pid *pid = get_pid(task_pid(current)); void *stream; int ret; @@ -519,6 +523,8 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, goto err_submit_ww_acquire; } + submit->pid = pid; + ret = etnaviv_cmdbuf_init(priv->cmdbuf_suballoc, &submit->cmdbuf, ALIGN(args->stream_size, 8) + 8); if (ret) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index 37018bc55810..7d9bf4673e2d 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -1045,12 +1045,28 @@ pm_put: } #endif -void etnaviv_gpu_recover_hang(struct etnaviv_gpu *gpu) +void etnaviv_gpu_recover_hang(struct etnaviv_gem_submit *submit) { + struct etnaviv_gpu *gpu = submit->gpu; + char *comm = NULL, *cmd = NULL; + struct task_struct *task; unsigned int i; dev_err(gpu->dev, "recover hung GPU!\n"); + task = get_pid_task(submit->pid, PIDTYPE_PID); + if (task) { + comm = kstrdup(task->comm, GFP_KERNEL); + cmd = kstrdup_quotable_cmdline(task, GFP_KERNEL); + put_task_struct(task); + } + + if (comm && cmd) + dev_err(gpu->dev, "offending task: %s (%s)\n", comm, cmd); + + kfree(cmd); + kfree(comm); + if (pm_runtime_get_sync(gpu->dev) < 0) goto pm_put; diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h index 85eddd492774..b3a0941d56fd 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h @@ -168,7 +168,7 @@ bool etnaviv_fill_identity_from_hwdb(struct etnaviv_gpu *gpu); int etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m); #endif -void etnaviv_gpu_recover_hang(struct etnaviv_gpu *gpu); +void etnaviv_gpu_recover_hang(struct etnaviv_gem_submit *submit); void etnaviv_gpu_retire(struct etnaviv_gpu *gpu); int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu, u32 fence, struct drm_etnaviv_timespec *timeout); diff --git a/drivers/gpu/drm/etnaviv/etnaviv_sched.c b/drivers/gpu/drm/etnaviv/etnaviv_sched.c index 72e2553fbc98..d29f467eee13 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_sched.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_sched.c @@ -67,7 +67,7 @@ static enum drm_gpu_sched_stat etnaviv_sched_timedout_job(struct drm_sched_job /* get the GPU back into the init state */ etnaviv_core_dump(submit); - etnaviv_gpu_recover_hang(gpu); + etnaviv_gpu_recover_hang(submit); drm_sched_resubmit_jobs(&gpu->sched); -- cgit From 6cffb1c27f2d05047c7f569c425fd56d11ae89b2 Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Wed, 6 Jul 2022 18:29:24 +0000 Subject: drm/etnaviv: Remove duplicate call to drm_gem_free_mmap_offset The docs explicitly say the drm_gem_object_release function already calls this, and this does not appear to be a prerequisite for the call to etnaviv_gem_ops.release. Signed-off-by: T.J. Mercier Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_gem.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c b/drivers/gpu/drm/etnaviv/etnaviv_gem.c index cc386f8a7116..ecb828e4e156 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c @@ -504,7 +504,6 @@ void etnaviv_gem_free_object(struct drm_gem_object *obj) kfree(mapping); } - drm_gem_free_mmap_offset(obj); etnaviv_obj->ops->release(etnaviv_obj); drm_gem_object_release(obj); -- cgit From 5a40837debaa9dcc71765d32ce1a15be068b6cc2 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Thu, 14 Jul 2022 12:31:42 +0200 Subject: drm/etnaviv: move idle mapping reaping into separate function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The same logic is already used in two different places and now it will also be needed outside of the compilation unit, so split it into a separate function. Cc: stable@vger.kernel.org # 5.19 Signed-off-by: Lucas Stach Reviewed-by: Guido Günther --- drivers/gpu/drm/etnaviv/etnaviv_mmu.c | 23 +++++++++++++++-------- drivers/gpu/drm/etnaviv/etnaviv_mmu.h | 1 + 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c index dc1aa738c4f1..55479cb8b1ac 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c @@ -135,6 +135,19 @@ static void etnaviv_iommu_remove_mapping(struct etnaviv_iommu_context *context, drm_mm_remove_node(&mapping->vram_node); } +void etnaviv_iommu_reap_mapping(struct etnaviv_vram_mapping *mapping) +{ + struct etnaviv_iommu_context *context = mapping->context; + + lockdep_assert_held(&context->lock); + WARN_ON(mapping->use); + + etnaviv_iommu_remove_mapping(context, mapping); + etnaviv_iommu_context_put(mapping->context); + mapping->context = NULL; + list_del_init(&mapping->mmu_node); +} + static int etnaviv_iommu_find_iova(struct etnaviv_iommu_context *context, struct drm_mm_node *node, size_t size) { @@ -202,10 +215,7 @@ static int etnaviv_iommu_find_iova(struct etnaviv_iommu_context *context, * this mapping. */ list_for_each_entry_safe(m, n, &list, scan_node) { - etnaviv_iommu_remove_mapping(context, m); - etnaviv_iommu_context_put(m->context); - m->context = NULL; - list_del_init(&m->mmu_node); + etnaviv_iommu_reap_mapping(m); list_del_init(&m->scan_node); } @@ -257,10 +267,7 @@ static int etnaviv_iommu_insert_exact(struct etnaviv_iommu_context *context, } list_for_each_entry_safe(m, n, &scan_list, scan_node) { - etnaviv_iommu_remove_mapping(context, m); - etnaviv_iommu_context_put(m->context); - m->context = NULL; - list_del_init(&m->mmu_node); + etnaviv_iommu_reap_mapping(m); list_del_init(&m->scan_node); } diff --git a/drivers/gpu/drm/etnaviv/etnaviv_mmu.h b/drivers/gpu/drm/etnaviv/etnaviv_mmu.h index e4a0b7d09c2e..c01a147f0dfd 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_mmu.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_mmu.h @@ -91,6 +91,7 @@ int etnaviv_iommu_map_gem(struct etnaviv_iommu_context *context, struct etnaviv_vram_mapping *mapping, u64 va); void etnaviv_iommu_unmap_gem(struct etnaviv_iommu_context *context, struct etnaviv_vram_mapping *mapping); +void etnaviv_iommu_reap_mapping(struct etnaviv_vram_mapping *mapping); int etnaviv_iommu_get_suballoc_va(struct etnaviv_iommu_context *ctx, struct etnaviv_vram_mapping *mapping, -- cgit From 332f847212e43d584019a8264895f25cf92aa647 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Thu, 14 Jul 2022 12:31:43 +0200 Subject: drm/etnaviv: reap idle mapping if it doesn't match the softpin address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a idle BO, which is held open by another process, gets freed by userspace and subsequently referenced again by e.g. importing it again, userspace may assign a different softpin VA than the last time around. As the kernel GEM object still exists, we likely have a idle mapping with the old VA still cached, if it hasn't been reaped in the meantime. As the context matches, we then simply try to resurrect this mapping by increasing the refcount. As the VA in this mapping does not match the new softpin address, we consequently fail the otherwise valid submit. Instead of failing, reap the idle mapping. Cc: stable@vger.kernel.org # 5.19 Signed-off-by: Lucas Stach Reviewed-by: Guido Günther --- drivers/gpu/drm/etnaviv/etnaviv_gem.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c b/drivers/gpu/drm/etnaviv/etnaviv_gem.c index ecb828e4e156..d45bf0368339 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c @@ -258,7 +258,12 @@ struct etnaviv_vram_mapping *etnaviv_gem_mapping_get( if (mapping->use == 0) { mutex_lock(&mmu_context->lock); if (mapping->context == mmu_context) - mapping->use += 1; + if (va && mapping->iova != va) { + etnaviv_iommu_reap_mapping(mapping); + mapping = NULL; + } else { + mapping->use += 1; + } else mapping = NULL; mutex_unlock(&mmu_context->lock); -- cgit From cc7d3fb446a91f24978a6aa59cbb578f92e22242 Mon Sep 17 00:00:00 2001 From: Doug Brown Date: Sat, 10 Sep 2022 13:29:38 -0700 Subject: drm/etnaviv: add missing quirks for GC300 The GC300's features register doesn't specify that a 2D pipe is available, and like the GC600, its idle register reports zero bits where modules aren't present. Signed-off-by: Doug Brown Reviewed-by: Christian Gmeiner Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index 7d9bf4673e2d..a96392c2dd02 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -416,6 +416,12 @@ static void etnaviv_hw_identify(struct etnaviv_gpu *gpu) if (gpu->identity.model == chipModel_GC700) gpu->identity.features &= ~chipFeatures_FAST_CLEAR; + /* These models/revisions don't have the 2D pipe bit */ + if ((gpu->identity.model == chipModel_GC500 && + gpu->identity.revision <= 2) || + gpu->identity.model == chipModel_GC300) + gpu->identity.features |= chipFeatures_PIPE_2D; + if ((gpu->identity.model == chipModel_GC500 && gpu->identity.revision < 2) || (gpu->identity.model == chipModel_GC300 && @@ -449,8 +455,9 @@ static void etnaviv_hw_identify(struct etnaviv_gpu *gpu) gpu_read(gpu, VIVS_HI_CHIP_MINOR_FEATURE_5); } - /* GC600 idle register reports zero bits where modules aren't present */ - if (gpu->identity.model == chipModel_GC600) + /* GC600/300 idle register reports zero bits where modules aren't present */ + if (gpu->identity.model == chipModel_GC600 || + gpu->identity.model == chipModel_GC300) gpu->idle_mask = VIVS_HI_IDLE_STATE_TX | VIVS_HI_IDLE_STATE_RA | VIVS_HI_IDLE_STATE_SE | -- cgit From 61a6920bb604df3a0e389a2a9479e1e233e4461d Mon Sep 17 00:00:00 2001 From: Doug Brown Date: Sat, 10 Sep 2022 13:29:39 -0700 Subject: drm/etnaviv: fix power register offset on GC300 Older GC300 revisions have their power registers at an offset of 0x200 rather than 0x100. Add new gpu_read_power and gpu_write_power functions to encapsulate accesses to the power addresses and fix the addresses. Signed-off-by: Doug Brown Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_dump.c | 7 ++++++- drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 20 ++++++++++---------- drivers/gpu/drm/etnaviv/etnaviv_gpu.h | 21 +++++++++++++++++++++ 3 files changed, 37 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_dump.c b/drivers/gpu/drm/etnaviv/etnaviv_dump.c index f418e0b75772..44b5f3c35aab 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_dump.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_dump.c @@ -83,10 +83,15 @@ static void etnaviv_core_dump_registers(struct core_dump_iterator *iter, { struct etnaviv_dump_registers *reg = iter->data; unsigned int i; + u32 read_addr; for (i = 0; i < ARRAY_SIZE(etnaviv_dump_registers); i++, reg++) { + read_addr = etnaviv_dump_registers[i]; + if (read_addr >= VIVS_PM_POWER_CONTROLS && + read_addr <= VIVS_PM_PULSE_EATER) + read_addr = gpu_fix_power_address(gpu, read_addr); reg->reg = cpu_to_le32(etnaviv_dump_registers[i]); - reg->value = cpu_to_le32(gpu_read(gpu, etnaviv_dump_registers[i])); + reg->value = cpu_to_le32(gpu_read(gpu, read_addr)); } etnaviv_core_dump_header(iter, ETDUMP_BUF_REG, reg); diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index a96392c2dd02..ed2f9c8f288c 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -590,7 +590,7 @@ static void etnaviv_gpu_enable_mlcg(struct etnaviv_gpu *gpu) u32 pmc, ppc; /* enable clock gating */ - ppc = gpu_read(gpu, VIVS_PM_POWER_CONTROLS); + ppc = gpu_read_power(gpu, VIVS_PM_POWER_CONTROLS); ppc |= VIVS_PM_POWER_CONTROLS_ENABLE_MODULE_CLOCK_GATING; /* Disable stall module clock gating for 4.3.0.1 and 4.3.0.2 revs */ @@ -598,9 +598,9 @@ static void etnaviv_gpu_enable_mlcg(struct etnaviv_gpu *gpu) gpu->identity.revision == 0x4302) ppc |= VIVS_PM_POWER_CONTROLS_DISABLE_STALL_MODULE_CLOCK_GATING; - gpu_write(gpu, VIVS_PM_POWER_CONTROLS, ppc); + gpu_write_power(gpu, VIVS_PM_POWER_CONTROLS, ppc); - pmc = gpu_read(gpu, VIVS_PM_MODULE_CONTROLS); + pmc = gpu_read_power(gpu, VIVS_PM_MODULE_CONTROLS); /* Disable PA clock gating for GC400+ without bugfix except for GC420 */ if (gpu->identity.model >= chipModel_GC400 && @@ -635,7 +635,7 @@ static void etnaviv_gpu_enable_mlcg(struct etnaviv_gpu *gpu) pmc |= VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_RA_HZ; pmc |= VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_RA_EZ; - gpu_write(gpu, VIVS_PM_MODULE_CONTROLS, pmc); + gpu_write_power(gpu, VIVS_PM_MODULE_CONTROLS, pmc); } void etnaviv_gpu_start_fe(struct etnaviv_gpu *gpu, u32 address, u16 prefetch) @@ -695,11 +695,11 @@ static void etnaviv_gpu_setup_pulse_eater(struct etnaviv_gpu *gpu) (gpu->identity.features & chipFeatures_PIPE_3D)) { /* Performance fix: disable internal DFS */ - pulse_eater = gpu_read(gpu, VIVS_PM_PULSE_EATER); + pulse_eater = gpu_read_power(gpu, VIVS_PM_PULSE_EATER); pulse_eater |= BIT(18); } - gpu_write(gpu, VIVS_PM_PULSE_EATER, pulse_eater); + gpu_write_power(gpu, VIVS_PM_PULSE_EATER, pulse_eater); } static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu) @@ -1317,9 +1317,9 @@ static void sync_point_perfmon_sample_pre(struct etnaviv_gpu *gpu, u32 val; /* disable clock gating */ - val = gpu_read(gpu, VIVS_PM_POWER_CONTROLS); + val = gpu_read_power(gpu, VIVS_PM_POWER_CONTROLS); val &= ~VIVS_PM_POWER_CONTROLS_ENABLE_MODULE_CLOCK_GATING; - gpu_write(gpu, VIVS_PM_POWER_CONTROLS, val); + gpu_write_power(gpu, VIVS_PM_POWER_CONTROLS, val); /* enable debug register */ val = gpu_read(gpu, VIVS_HI_CLOCK_CONTROL); @@ -1350,9 +1350,9 @@ static void sync_point_perfmon_sample_post(struct etnaviv_gpu *gpu, gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, val); /* enable clock gating */ - val = gpu_read(gpu, VIVS_PM_POWER_CONTROLS); + val = gpu_read_power(gpu, VIVS_PM_POWER_CONTROLS); val |= VIVS_PM_POWER_CONTROLS_ENABLE_MODULE_CLOCK_GATING; - gpu_write(gpu, VIVS_PM_POWER_CONTROLS, val); + gpu_write_power(gpu, VIVS_PM_POWER_CONTROLS, val); } diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h index b3a0941d56fd..f1204b070fb8 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h @@ -10,6 +10,7 @@ #include "etnaviv_gem.h" #include "etnaviv_mmu.h" #include "etnaviv_drv.h" +#include "common.xml.h" struct etnaviv_gem_submit; struct etnaviv_vram_mapping; @@ -159,6 +160,26 @@ static inline u32 gpu_read(struct etnaviv_gpu *gpu, u32 reg) return readl(gpu->mmio + reg); } +static inline u32 gpu_fix_power_address(struct etnaviv_gpu *gpu, u32 reg) +{ + /* Power registers in GC300 < 2.0 are offset by 0x100 */ + if (gpu->identity.model == chipModel_GC300 && + gpu->identity.revision < 0x2000) + reg += 0x100; + + return reg; +} + +static inline void gpu_write_power(struct etnaviv_gpu *gpu, u32 reg, u32 data) +{ + writel(data, gpu->mmio + gpu_fix_power_address(gpu, reg)); +} + +static inline u32 gpu_read_power(struct etnaviv_gpu *gpu, u32 reg) +{ + return readl(gpu->mmio + gpu_fix_power_address(gpu, reg)); +} + int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, u32 param, u64 *value); int etnaviv_gpu_init(struct etnaviv_gpu *gpu); -- cgit From 78a033433a5ae4fee85511ee075bc9a48312c79e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 15 Sep 2022 16:26:51 -0700 Subject: drm/i915/gt: Cleanup partial engine discovery failures If we abort driver initialisation in the middle of gt/engine discovery, some engines will be fully setup and some not. Those incompletely setup engines only have 'engine->release == NULL' and so will leak any of the common objects allocated. v2: - Drop the destroy_pinned_context() helper for now. It's not really worth it with just a single callsite at the moment. (Janusz) Signed-off-by: Chris Wilson Cc: Janusz Krzysztofik Signed-off-by: Matt Roper Reviewed-by: Janusz Krzysztofik Link: https://patchwork.freedesktop.org/patch/msgid/20220915232654.3283095-2-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/gt/intel_engine_cs.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c index 1f7188129cd1..2ddcad497fa3 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c @@ -1274,8 +1274,13 @@ int intel_engines_init(struct intel_gt *gt) return err; err = setup(engine); - if (err) + if (err) { + intel_engine_cleanup_common(engine); return err; + } + + /* The backend should now be responsible for cleanup */ + GEM_BUG_ON(engine->release == NULL); err = engine_init_common(engine); if (err) -- cgit From e23a40040819a7a3fcda3c6cedaeff80ad20c231 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Thu, 15 Sep 2022 16:26:52 -0700 Subject: drm/i915: Make GEM resume all engines Walk all GTs from i915_gem_resume when resuming engines. Cc: Andi Shyti Signed-off-by: Tvrtko Ursulin Signed-off-by: Matt Roper Reviewed-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20220915232654.3283095-3-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_pm.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_pm.c b/drivers/gpu/drm/i915/gem/i915_gem_pm.c index 3428f735e786..2c80cc8362b6 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_pm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_pm.c @@ -212,7 +212,8 @@ int i915_gem_freeze_late(struct drm_i915_private *i915) void i915_gem_resume(struct drm_i915_private *i915) { - int ret; + struct intel_gt *gt; + int ret, i, j; GEM_TRACE("%s\n", dev_name(i915->drm.dev)); @@ -224,8 +225,25 @@ void i915_gem_resume(struct drm_i915_private *i915) * guarantee that the context image is complete. So let's just reset * it and start again. */ - intel_gt_resume(to_gt(i915)); + for_each_gt(gt, i915, i) + if (intel_gt_resume(gt)) + goto err_wedged; ret = lmem_restore(i915, I915_TTM_BACKUP_ALLOW_GPU); GEM_WARN_ON(ret); + + return; + +err_wedged: + for_each_gt(gt, i915, j) { + if (!intel_gt_is_wedged(gt)) { + dev_err(i915->drm.dev, + "Failed to re-initialize GPU[%u], declaring it wedged!\n", + j); + intel_gt_set_wedged(gt); + } + + if (j == i) + break; + } } -- cgit From 4b3823ff7fa5bd000aa73384ec1f611980d00855 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Thu, 15 Sep 2022 16:26:53 -0700 Subject: drm/i915: Make GEM suspend all GTs Walk all GTs when suspending. Signed-off-by: Tvrtko Ursulin Signed-off-by: Matt Roper Reviewed-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20220915232654.3283095-4-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_pm.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_pm.c b/drivers/gpu/drm/i915/gem/i915_gem_pm.c index 2c80cc8362b6..e5bfb6be9f7a 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_pm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_pm.c @@ -22,6 +22,9 @@ void i915_gem_suspend(struct drm_i915_private *i915) { + struct intel_gt *gt; + unsigned int i; + GEM_TRACE("%s\n", dev_name(i915->drm.dev)); intel_wakeref_auto(&to_gt(i915)->userfault_wakeref, 0); @@ -36,7 +39,8 @@ void i915_gem_suspend(struct drm_i915_private *i915) * state. Fortunately, the kernel_context is disposable and we do * not rely on its state. */ - intel_gt_suspend_prepare(to_gt(i915)); + for_each_gt(gt, i915, i) + intel_gt_suspend_prepare(gt); i915_gem_drain_freed_objects(i915); } @@ -131,7 +135,9 @@ void i915_gem_suspend_late(struct drm_i915_private *i915) &i915->mm.purge_list, NULL }, **phase; + struct intel_gt *gt; unsigned long flags; + unsigned int i; bool flush = false; /* @@ -154,7 +160,8 @@ void i915_gem_suspend_late(struct drm_i915_private *i915) * machine in an unusable condition. */ - intel_gt_suspend_late(to_gt(i915)); + for_each_gt(gt, i915, i) + intel_gt_suspend_late(gt); spin_lock_irqsave(&i915->mm.obj_lock, flags); for (phase = phases; *phase; phase++) { -- cgit From f569ae759472fbe1f6fdddc7398360d43fdcc199 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Thu, 15 Sep 2022 16:26:54 -0700 Subject: drm/i915: Handle all GTs on driver (un)load paths This, along with the changes already landed in commit 1c66a12ab431 ("drm/i915: Handle each GT on init/release and suspend/resume") makes engines from all GTs actually known to the driver. To accomplish this we need to sprinkle a lot of for_each_gt calls around but is otherwise pretty un-eventuful. v2: - Consolidate adjacent GT loops in a couple places. (Daniele) Cc: Daniele Ceraolo Spurio Signed-off-by: Tvrtko Ursulin Signed-off-by: Matt Roper Reviewed-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20220915232654.3283095-5-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/i915_driver.c | 3 ++- drivers/gpu/drm/i915/i915_gem.c | 43 +++++++++++++++++++++++++++----------- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c index 01f42777b6e3..d5eb82e1e5ba 100644 --- a/drivers/gpu/drm/i915/i915_driver.c +++ b/drivers/gpu/drm/i915/i915_driver.c @@ -1647,7 +1647,8 @@ static int intel_runtime_suspend(struct device *kdev) intel_runtime_pm_enable_interrupts(dev_priv); - intel_gt_runtime_resume(to_gt(dev_priv)); + for_each_gt(gt, dev_priv, i) + intel_gt_runtime_resume(gt); enable_rpm_wakeref_asserts(rpm); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c8e14ed9c2a9..be7fede6cd6f 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1091,6 +1091,8 @@ out: int i915_gem_init(struct drm_i915_private *dev_priv) { + struct intel_gt *gt; + unsigned int i; int ret; /* We need to fallback to 4K pages if host doesn't support huge gtt. */ @@ -1122,9 +1124,11 @@ int i915_gem_init(struct drm_i915_private *dev_priv) */ intel_init_clock_gating(dev_priv); - ret = intel_gt_init(to_gt(dev_priv)); - if (ret) - goto err_unlock; + for_each_gt(gt, dev_priv, i) { + ret = intel_gt_init(gt); + if (ret) + goto err_unlock; + } return 0; @@ -1137,8 +1141,13 @@ int i915_gem_init(struct drm_i915_private *dev_priv) err_unlock: i915_gem_drain_workqueue(dev_priv); - if (ret != -EIO) - intel_uc_cleanup_firmwares(&to_gt(dev_priv)->uc); + if (ret != -EIO) { + for_each_gt(gt, dev_priv, i) { + intel_gt_driver_remove(gt); + intel_gt_driver_release(gt); + intel_uc_cleanup_firmwares(>->uc); + } + } if (ret == -EIO) { /* @@ -1146,10 +1155,12 @@ err_unlock: * as wedged. But we only want to do this when the GPU is angry, * for all other failure, such as an allocation failure, bail. */ - if (!intel_gt_is_wedged(to_gt(dev_priv))) { - i915_probe_error(dev_priv, - "Failed to initialize GPU, declaring it wedged!\n"); - intel_gt_set_wedged(to_gt(dev_priv)); + for_each_gt(gt, dev_priv, i) { + if (!intel_gt_is_wedged(gt)) { + i915_probe_error(dev_priv, + "Failed to initialize GPU, declaring it wedged!\n"); + intel_gt_set_wedged(gt); + } } /* Minimal basic recovery for KMS */ @@ -1177,10 +1188,14 @@ void i915_gem_driver_unregister(struct drm_i915_private *i915) void i915_gem_driver_remove(struct drm_i915_private *dev_priv) { + struct intel_gt *gt; + unsigned int i; + intel_wakeref_auto_fini(&to_gt(dev_priv)->userfault_wakeref); i915_gem_suspend_late(dev_priv); - intel_gt_driver_remove(to_gt(dev_priv)); + for_each_gt(gt, dev_priv, i) + intel_gt_driver_remove(gt); dev_priv->uabi_engines = RB_ROOT; /* Flush any outstanding unpin_work. */ @@ -1191,9 +1206,13 @@ void i915_gem_driver_remove(struct drm_i915_private *dev_priv) void i915_gem_driver_release(struct drm_i915_private *dev_priv) { - intel_gt_driver_release(to_gt(dev_priv)); + struct intel_gt *gt; + unsigned int i; - intel_uc_cleanup_firmwares(&to_gt(dev_priv)->uc); + for_each_gt(gt, dev_priv, i) { + intel_gt_driver_release(gt); + intel_uc_cleanup_firmwares(>->uc); + } i915_gem_drain_freed_objects(dev_priv); -- cgit From fe5979665f6408092ff6072dc894b74a192cbb53 Mon Sep 17 00:00:00 2001 From: Tilak Tangudu Date: Sat, 10 Sep 2022 07:38:42 -0700 Subject: drm/i915/debugfs: Add perf_limit_reasons in debugfs Add perf_limit_reasons in debugfs. The upper 16 perf_limit_reasons RW "log" bits are identical to the lower 16 RO "status" bits except that the "log" bits remain set until cleared, thereby ensuring the throttling occurrence is not missed. The clear fop clears the upper 16 "log" bits, the get fop gets all 32 "log" and "status" bits. v2: Expand commit message and clarify "log" and "status" bits in comment (Rodrigo) Cc: Rodrigo Vivi Signed-off-by: Ashutosh Dixit Signed-off-by: Tilak Tangudu Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20220910143844.1755324-2-ashutosh.dixit@intel.com --- drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c | 31 +++++++++++++++++++++++++++ drivers/gpu/drm/i915/i915_reg.h | 1 + 2 files changed, 32 insertions(+) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c index 40bdd4cb629f..88814f2b32c8 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c @@ -655,6 +655,36 @@ static bool rps_eval(void *data) DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(rps_boost); +static int perf_limit_reasons_get(void *data, u64 *val) +{ + struct intel_gt *gt = data; + intel_wakeref_t wakeref; + + with_intel_runtime_pm(gt->uncore->rpm, wakeref) + *val = intel_uncore_read(gt->uncore, GT0_PERF_LIMIT_REASONS); + + return 0; +} + +static int perf_limit_reasons_clear(void *data, u64 val) +{ + struct intel_gt *gt = data; + intel_wakeref_t wakeref; + + /* + * Clear the upper 16 "log" bits, the lower 16 "status" bits are + * read-only. The upper 16 "log" bits are identical to the lower 16 + * "status" bits except that the "log" bits remain set until cleared. + */ + with_intel_runtime_pm(gt->uncore->rpm, wakeref) + intel_uncore_rmw(gt->uncore, GT0_PERF_LIMIT_REASONS, + GT0_PERF_LIMIT_REASONS_LOG_MASK, 0); + + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(perf_limit_reasons_fops, perf_limit_reasons_get, + perf_limit_reasons_clear, "%llu\n"); + void intel_gt_pm_debugfs_register(struct intel_gt *gt, struct dentry *root) { static const struct intel_gt_debugfs_file files[] = { @@ -664,6 +694,7 @@ void intel_gt_pm_debugfs_register(struct intel_gt *gt, struct dentry *root) { "forcewake_user", &forcewake_user_fops, NULL}, { "llc", &llc_fops, llc_eval }, { "rps_boost", &rps_boost_fops, rps_eval }, + { "perf_limit_reasons", &perf_limit_reasons_fops, NULL }, }; intel_gt_debugfs_register_files(root, files, ARRAY_SIZE(files), gt); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index f44eec7f7a9c..2d60ecc09661 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1866,6 +1866,7 @@ #define POWER_LIMIT_4_MASK REG_BIT(8) #define POWER_LIMIT_1_MASK REG_BIT(10) #define POWER_LIMIT_2_MASK REG_BIT(11) +#define GT0_PERF_LIMIT_REASONS_LOG_MASK REG_GENMASK(31, 16) #define CHV_CLK_CTL1 _MMIO(0x101100) #define VLV_CLK_CTL2 _MMIO(0x101104) -- cgit From 1551b9164f6194ffee78935d1ff515f697619483 Mon Sep 17 00:00:00 2001 From: Ashutosh Dixit Date: Sat, 10 Sep 2022 07:38:43 -0700 Subject: drm/i915/mtl: PERF_LIMIT_REASONS changes for MTL PERF_LIMIT_REASONS register for MTL media gt is different now. v2: Avoid static inline for intel_gt_perf_limit_reasons_reg() (Jani) Cc: Jani Nikula Cc: Badal Nilawar Signed-off-by: Ashutosh Dixit Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20220910143844.1755324-3-ashutosh.dixit@intel.com --- drivers/gpu/drm/i915/gt/intel_gt.c | 6 ++++++ drivers/gpu/drm/i915/gt/intel_gt.h | 1 + drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c | 4 ++-- drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c | 6 +++--- drivers/gpu/drm/i915/i915_reg.h | 1 + 5 files changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c b/drivers/gpu/drm/i915/gt/intel_gt.c index 926a1515cd3b..abc46ba7cf1d 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt.c +++ b/drivers/gpu/drm/i915/gt/intel_gt.c @@ -230,6 +230,12 @@ static void gen6_clear_engine_error_register(struct intel_engine_cs *engine) GEN6_RING_FAULT_REG_POSTING_READ(engine); } +i915_reg_t intel_gt_perf_limit_reasons_reg(struct intel_gt *gt) +{ + return gt->type == GT_MEDIA ? + MTL_MEDIA_PERF_LIMIT_REASONS : GT0_PERF_LIMIT_REASONS; +} + void intel_gt_clear_error_registers(struct intel_gt *gt, intel_engine_mask_t engine_mask) diff --git a/drivers/gpu/drm/i915/gt/intel_gt.h b/drivers/gpu/drm/i915/gt/intel_gt.h index 2ee582e287c8..e0365d556248 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt.h +++ b/drivers/gpu/drm/i915/gt/intel_gt.h @@ -60,6 +60,7 @@ void intel_gt_driver_late_release_all(struct drm_i915_private *i915); int intel_gt_wait_for_idle(struct intel_gt *gt, long timeout); void intel_gt_check_and_clear_faults(struct intel_gt *gt); +i915_reg_t intel_gt_perf_limit_reasons_reg(struct intel_gt *gt); void intel_gt_clear_error_registers(struct intel_gt *gt, intel_engine_mask_t engine_mask); diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c index 88814f2b32c8..3157d06e8995 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c @@ -661,7 +661,7 @@ static int perf_limit_reasons_get(void *data, u64 *val) intel_wakeref_t wakeref; with_intel_runtime_pm(gt->uncore->rpm, wakeref) - *val = intel_uncore_read(gt->uncore, GT0_PERF_LIMIT_REASONS); + *val = intel_uncore_read(gt->uncore, intel_gt_perf_limit_reasons_reg(gt)); return 0; } @@ -677,7 +677,7 @@ static int perf_limit_reasons_clear(void *data, u64 val) * "status" bits except that the "log" bits remain set until cleared. */ with_intel_runtime_pm(gt->uncore->rpm, wakeref) - intel_uncore_rmw(gt->uncore, GT0_PERF_LIMIT_REASONS, + intel_uncore_rmw(gt->uncore, intel_gt_perf_limit_reasons_reg(gt), GT0_PERF_LIMIT_REASONS_LOG_MASK, 0); return 0; diff --git a/drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c b/drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c index e066cc33d9f2..54deae45d81f 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c @@ -510,7 +510,7 @@ struct intel_gt_bool_throttle_attr { struct attribute attr; ssize_t (*show)(struct device *dev, struct device_attribute *attr, char *buf); - i915_reg_t reg32; + i915_reg_t (*reg32)(struct intel_gt *gt); u32 mask; }; @@ -521,7 +521,7 @@ static ssize_t throttle_reason_bool_show(struct device *dev, struct intel_gt *gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name); struct intel_gt_bool_throttle_attr *t_attr = (struct intel_gt_bool_throttle_attr *) attr; - bool val = rps_read_mask_mmio(>->rps, t_attr->reg32, t_attr->mask); + bool val = rps_read_mask_mmio(>->rps, t_attr->reg32(gt), t_attr->mask); return sysfs_emit(buff, "%u\n", val); } @@ -530,7 +530,7 @@ static ssize_t throttle_reason_bool_show(struct device *dev, struct intel_gt_bool_throttle_attr attr_##sysfs_func__ = { \ .attr = { .name = __stringify(sysfs_func__), .mode = 0444 }, \ .show = throttle_reason_bool_show, \ - .reg32 = GT0_PERF_LIMIT_REASONS, \ + .reg32 = intel_gt_perf_limit_reasons_reg, \ .mask = mask__, \ } diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 2d60ecc09661..be4129118d7c 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1867,6 +1867,7 @@ #define POWER_LIMIT_1_MASK REG_BIT(10) #define POWER_LIMIT_2_MASK REG_BIT(11) #define GT0_PERF_LIMIT_REASONS_LOG_MASK REG_GENMASK(31, 16) +#define MTL_MEDIA_PERF_LIMIT_REASONS _MMIO(0x138030) #define CHV_CLK_CTL1 _MMIO(0x101100) #define VLV_CLK_CTL2 _MMIO(0x101104) -- cgit From 835a4d18353492577093eff7cb6fa866f6e7014f Mon Sep 17 00:00:00 2001 From: Ashutosh Dixit Date: Sat, 10 Sep 2022 07:38:44 -0700 Subject: drm/i915/rps: Freq caps for MTL For MTL, when reading from HW, RP0, RP1 (actuall RPe) and RPn freq use an entirely different set of registers with different fields, bitwidths and units. v2: Move MTL check into a separate function (Jani) Cc: Jani Nikula Cc: Badal Nilawar Signed-off-by: Ashutosh Dixit Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20220910143844.1755324-4-ashutosh.dixit@intel.com --- drivers/gpu/drm/i915/gt/intel_rps.c | 46 +++++++++++++++++++++++++++++-------- drivers/gpu/drm/i915/i915_reg.h | 9 ++++++++ 2 files changed, 46 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_rps.c b/drivers/gpu/drm/i915/gt/intel_rps.c index 6b86250c31ab..17b40b625e31 100644 --- a/drivers/gpu/drm/i915/gt/intel_rps.c +++ b/drivers/gpu/drm/i915/gt/intel_rps.c @@ -1085,15 +1085,25 @@ static u32 intel_rps_read_state_cap(struct intel_rps *rps) return intel_uncore_read(uncore, GEN6_RP_STATE_CAP); } -/** - * gen6_rps_get_freq_caps - Get freq caps exposed by HW - * @rps: the intel_rps structure - * @caps: returned freq caps - * - * Returned "caps" frequencies should be converted to MHz using - * intel_gpu_freq() - */ -void gen6_rps_get_freq_caps(struct intel_rps *rps, struct intel_rps_freq_caps *caps) +static void +mtl_get_freq_caps(struct intel_rps *rps, struct intel_rps_freq_caps *caps) +{ + struct intel_uncore *uncore = rps_to_uncore(rps); + u32 rp_state_cap = rps_to_gt(rps)->type == GT_MEDIA ? + intel_uncore_read(uncore, MTL_MEDIAP_STATE_CAP) : + intel_uncore_read(uncore, MTL_RP_STATE_CAP); + u32 rpe = rps_to_gt(rps)->type == GT_MEDIA ? + intel_uncore_read(uncore, MTL_MPE_FREQUENCY) : + intel_uncore_read(uncore, MTL_GT_RPE_FREQUENCY); + + /* MTL values are in units of 16.67 MHz */ + caps->rp0_freq = REG_FIELD_GET(MTL_RP0_CAP_MASK, rp_state_cap); + caps->min_freq = REG_FIELD_GET(MTL_RPN_CAP_MASK, rp_state_cap); + caps->rp1_freq = REG_FIELD_GET(MTL_RPE_MASK, rpe); +} + +static void +__gen6_rps_get_freq_caps(struct intel_rps *rps, struct intel_rps_freq_caps *caps) { struct drm_i915_private *i915 = rps_to_i915(rps); u32 rp_state_cap; @@ -1128,6 +1138,24 @@ void gen6_rps_get_freq_caps(struct intel_rps *rps, struct intel_rps_freq_caps *c } } +/** + * gen6_rps_get_freq_caps - Get freq caps exposed by HW + * @rps: the intel_rps structure + * @caps: returned freq caps + * + * Returned "caps" frequencies should be converted to MHz using + * intel_gpu_freq() + */ +void gen6_rps_get_freq_caps(struct intel_rps *rps, struct intel_rps_freq_caps *caps) +{ + struct drm_i915_private *i915 = rps_to_i915(rps); + + if (IS_METEORLAKE(i915)) + return mtl_get_freq_caps(rps, caps); + else + return __gen6_rps_get_freq_caps(rps, caps); +} + static void gen6_rps_init(struct intel_rps *rps) { struct drm_i915_private *i915 = rps_to_i915(rps); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index be4129118d7c..6850d27dc82c 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1856,6 +1856,15 @@ #define XEHPSDV_RP_STATE_CAP _MMIO(0x250014) #define PVC_RP_STATE_CAP _MMIO(0x281014) +#define MTL_RP_STATE_CAP _MMIO(0x138000) +#define MTL_MEDIAP_STATE_CAP _MMIO(0x138020) +#define MTL_RP0_CAP_MASK REG_GENMASK(8, 0) +#define MTL_RPN_CAP_MASK REG_GENMASK(24, 16) + +#define MTL_GT_RPE_FREQUENCY _MMIO(0x13800c) +#define MTL_MPE_FREQUENCY _MMIO(0x13802c) +#define MTL_RPE_MASK REG_GENMASK(8, 0) + #define GT0_PERF_LIMIT_REASONS _MMIO(0x1381a8) #define GT0_PERF_LIMIT_REASONS_MASK 0xde3 #define PROCHOT_MASK REG_BIT(0) -- cgit From 01f0ce3e859619ea84104d668a87ace924bd12df Mon Sep 17 00:00:00 2001 From: John Harrison Date: Mon, 12 Sep 2022 18:09:29 -0700 Subject: drm/i915/guc: Fix release build bug in 'remove log size module parameters' A patch was merged to remove the GuC log size override module parameters. That patch was broken and caused kernel error messages on boot in non CONFIG_DEBUG_GUC|GEM builds: [ 12.085121] i915 0000:00:02.0: [drm] *ERROR* Zero GuC log crash dump size! [ 12.092035] i915 0000:00:02.0: [drm] *ERROR* Zero GuC log debug size! So fit it. Fixes: f54e515c9180 ("drm/i915/guc: Remove log size module parameters") Cc: Joonas Lahtinen Cc: Jani Nikula Cc: Rodrigo Vivi Cc: Tvrtko Ursulin Cc: Alan Previn Cc: Jani Nikula Cc: Lucas De Marchi Cc: Matthew Brost Cc: Julia Lawall Cc: Chris Wilson Signed-off-by: John Harrison Reviewed-by: Daniele Ceraolo Spurio Link: https://patchwork.freedesktop.org/patch/msgid/20220913010929.2734885-2-John.C.Harrison@Intel.com --- drivers/gpu/drm/i915/gt/uc/intel_guc_log.c | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c index 55d4b8f8e33e..8e358f711b60 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c @@ -36,24 +36,6 @@ struct guc_log_section { const char *name; }; -static s32 scale_log_param(struct intel_guc_log *log, const struct guc_log_section *section, - s32 param) -{ - /* -1 means default */ - if (param < 0) - return section->default_val; - - /* Check for 32-bit overflow */ - if (param >= SZ_4K) { - drm_err(&guc_to_gt(log_to_guc(log))->i915->drm, "Size too large for GuC %s log: %dMB!", - section->name, param); - return section->default_val; - } - - /* Param units are 1MB */ - return param * SZ_1M; -} - static void _guc_log_init_sizes(struct intel_guc_log *log) { struct intel_guc *guc = log_to_guc(log); @@ -78,15 +60,10 @@ static void _guc_log_init_sizes(struct intel_guc_log *log) "capture", } }; - s32 params[GUC_LOG_SECTIONS_LIMIT] = { - GUC_LOG_DEFAULT_CRASH_BUFFER_SIZE / SZ_1M, - GUC_LOG_DEFAULT_DEBUG_BUFFER_SIZE / SZ_1M, - GUC_LOG_DEFAULT_CAPTURE_BUFFER_SIZE / SZ_1M, - }; int i; for (i = 0; i < GUC_LOG_SECTIONS_LIMIT; i++) - log->sizes[i].bytes = scale_log_param(log, sections + i, params[i]); + log->sizes[i].bytes = sections[i].default_val; /* If debug size > 1MB then bump default crash size to keep the same units */ if (log->sizes[GUC_LOG_SECTIONS_DEBUG].bytes >= SZ_1M && -- cgit From 1bed8b07342069ebfbab6794e5ce3084c3eb9bc8 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 16 Sep 2022 16:06:33 +0300 Subject: drm/i915/hotplug: move hotplug storm debugfs to intel_hotplug.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The debugfs should be where the implementation details are. v2: Rebase Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220916130634.3781122-1-jani.nikula@intel.com --- .../gpu/drm/i915/display/intel_display_debugfs.c | 160 +------------------- drivers/gpu/drm/i915/display/intel_hotplug.c | 166 +++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_hotplug.h | 1 + 3 files changed, 169 insertions(+), 158 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c index 7c7253a2541c..c5f47df0f362 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c @@ -22,6 +22,7 @@ #include "intel_fbdev.h" #include "intel_hdcp.h" #include "intel_hdmi.h" +#include "intel_hotplug.h" #include "intel_panel.h" #include "intel_pm.h" #include "intel_psr.h" @@ -1566,162 +1567,6 @@ static const struct file_operations i915_cur_wm_latency_fops = { .write = cur_wm_latency_write }; -static int i915_hpd_storm_ctl_show(struct seq_file *m, void *data) -{ - struct drm_i915_private *dev_priv = m->private; - struct intel_hotplug *hotplug = &dev_priv->display.hotplug; - - /* Synchronize with everything first in case there's been an HPD - * storm, but we haven't finished handling it in the kernel yet - */ - intel_synchronize_irq(dev_priv); - flush_work(&dev_priv->display.hotplug.dig_port_work); - flush_delayed_work(&dev_priv->display.hotplug.hotplug_work); - - seq_printf(m, "Threshold: %d\n", hotplug->hpd_storm_threshold); - seq_printf(m, "Detected: %s\n", - str_yes_no(delayed_work_pending(&hotplug->reenable_work))); - - return 0; -} - -static ssize_t i915_hpd_storm_ctl_write(struct file *file, - const char __user *ubuf, size_t len, - loff_t *offp) -{ - struct seq_file *m = file->private_data; - struct drm_i915_private *dev_priv = m->private; - struct intel_hotplug *hotplug = &dev_priv->display.hotplug; - unsigned int new_threshold; - int i; - char *newline; - char tmp[16]; - - if (len >= sizeof(tmp)) - return -EINVAL; - - if (copy_from_user(tmp, ubuf, len)) - return -EFAULT; - - tmp[len] = '\0'; - - /* Strip newline, if any */ - newline = strchr(tmp, '\n'); - if (newline) - *newline = '\0'; - - if (strcmp(tmp, "reset") == 0) - new_threshold = HPD_STORM_DEFAULT_THRESHOLD; - else if (kstrtouint(tmp, 10, &new_threshold) != 0) - return -EINVAL; - - if (new_threshold > 0) - drm_dbg_kms(&dev_priv->drm, - "Setting HPD storm detection threshold to %d\n", - new_threshold); - else - drm_dbg_kms(&dev_priv->drm, "Disabling HPD storm detection\n"); - - spin_lock_irq(&dev_priv->irq_lock); - hotplug->hpd_storm_threshold = new_threshold; - /* Reset the HPD storm stats so we don't accidentally trigger a storm */ - for_each_hpd_pin(i) - hotplug->stats[i].count = 0; - spin_unlock_irq(&dev_priv->irq_lock); - - /* Re-enable hpd immediately if we were in an irq storm */ - flush_delayed_work(&dev_priv->display.hotplug.reenable_work); - - return len; -} - -static int i915_hpd_storm_ctl_open(struct inode *inode, struct file *file) -{ - return single_open(file, i915_hpd_storm_ctl_show, inode->i_private); -} - -static const struct file_operations i915_hpd_storm_ctl_fops = { - .owner = THIS_MODULE, - .open = i915_hpd_storm_ctl_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .write = i915_hpd_storm_ctl_write -}; - -static int i915_hpd_short_storm_ctl_show(struct seq_file *m, void *data) -{ - struct drm_i915_private *dev_priv = m->private; - - seq_printf(m, "Enabled: %s\n", - str_yes_no(dev_priv->display.hotplug.hpd_short_storm_enabled)); - - return 0; -} - -static int -i915_hpd_short_storm_ctl_open(struct inode *inode, struct file *file) -{ - return single_open(file, i915_hpd_short_storm_ctl_show, - inode->i_private); -} - -static ssize_t i915_hpd_short_storm_ctl_write(struct file *file, - const char __user *ubuf, - size_t len, loff_t *offp) -{ - struct seq_file *m = file->private_data; - struct drm_i915_private *dev_priv = m->private; - struct intel_hotplug *hotplug = &dev_priv->display.hotplug; - char *newline; - char tmp[16]; - int i; - bool new_state; - - if (len >= sizeof(tmp)) - return -EINVAL; - - if (copy_from_user(tmp, ubuf, len)) - return -EFAULT; - - tmp[len] = '\0'; - - /* Strip newline, if any */ - newline = strchr(tmp, '\n'); - if (newline) - *newline = '\0'; - - /* Reset to the "default" state for this system */ - if (strcmp(tmp, "reset") == 0) - new_state = !HAS_DP_MST(dev_priv); - else if (kstrtobool(tmp, &new_state) != 0) - return -EINVAL; - - drm_dbg_kms(&dev_priv->drm, "%sabling HPD short storm detection\n", - new_state ? "En" : "Dis"); - - spin_lock_irq(&dev_priv->irq_lock); - hotplug->hpd_short_storm_enabled = new_state; - /* Reset the HPD storm stats so we don't accidentally trigger a storm */ - for_each_hpd_pin(i) - hotplug->stats[i].count = 0; - spin_unlock_irq(&dev_priv->irq_lock); - - /* Re-enable hpd immediately if we were in an irq storm */ - flush_delayed_work(&dev_priv->display.hotplug.reenable_work); - - return len; -} - -static const struct file_operations i915_hpd_short_storm_ctl_fops = { - .owner = THIS_MODULE, - .open = i915_hpd_short_storm_ctl_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .write = i915_hpd_short_storm_ctl_write, -}; - static int i915_drrs_ctl_set(void *data, u64 val) { struct drm_i915_private *dev_priv = data; @@ -1857,8 +1702,6 @@ static const struct { {"i915_dp_test_data", &i915_displayport_test_data_fops}, {"i915_dp_test_type", &i915_displayport_test_type_fops}, {"i915_dp_test_active", &i915_displayport_test_active_fops}, - {"i915_hpd_storm_ctl", &i915_hpd_storm_ctl_fops}, - {"i915_hpd_short_storm_ctl", &i915_hpd_short_storm_ctl_fops}, {"i915_drrs_ctl", &i915_drrs_ctl_fops}, {"i915_edp_psr_debug", &i915_edp_psr_debug_fops}, }; @@ -1882,6 +1725,7 @@ void intel_display_debugfs_register(struct drm_i915_private *i915) intel_dmc_debugfs_register(i915); intel_fbc_debugfs_register(i915); + intel_hpd_debugfs_register(i915); skl_watermark_ipc_debugfs_register(i915); } diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.c b/drivers/gpu/drm/i915/display/intel_hotplug.c index f7a2f485b177..4faae25d76c0 100644 --- a/drivers/gpu/drm/i915/display/intel_hotplug.c +++ b/drivers/gpu/drm/i915/display/intel_hotplug.c @@ -767,3 +767,169 @@ void intel_hpd_enable(struct drm_i915_private *dev_priv, enum hpd_pin pin) dev_priv->display.hotplug.stats[pin].state = HPD_ENABLED; spin_unlock_irq(&dev_priv->irq_lock); } + +static int i915_hpd_storm_ctl_show(struct seq_file *m, void *data) +{ + struct drm_i915_private *dev_priv = m->private; + struct intel_hotplug *hotplug = &dev_priv->display.hotplug; + + /* Synchronize with everything first in case there's been an HPD + * storm, but we haven't finished handling it in the kernel yet + */ + intel_synchronize_irq(dev_priv); + flush_work(&dev_priv->display.hotplug.dig_port_work); + flush_delayed_work(&dev_priv->display.hotplug.hotplug_work); + + seq_printf(m, "Threshold: %d\n", hotplug->hpd_storm_threshold); + seq_printf(m, "Detected: %s\n", + str_yes_no(delayed_work_pending(&hotplug->reenable_work))); + + return 0; +} + +static ssize_t i915_hpd_storm_ctl_write(struct file *file, + const char __user *ubuf, size_t len, + loff_t *offp) +{ + struct seq_file *m = file->private_data; + struct drm_i915_private *dev_priv = m->private; + struct intel_hotplug *hotplug = &dev_priv->display.hotplug; + unsigned int new_threshold; + int i; + char *newline; + char tmp[16]; + + if (len >= sizeof(tmp)) + return -EINVAL; + + if (copy_from_user(tmp, ubuf, len)) + return -EFAULT; + + tmp[len] = '\0'; + + /* Strip newline, if any */ + newline = strchr(tmp, '\n'); + if (newline) + *newline = '\0'; + + if (strcmp(tmp, "reset") == 0) + new_threshold = HPD_STORM_DEFAULT_THRESHOLD; + else if (kstrtouint(tmp, 10, &new_threshold) != 0) + return -EINVAL; + + if (new_threshold > 0) + drm_dbg_kms(&dev_priv->drm, + "Setting HPD storm detection threshold to %d\n", + new_threshold); + else + drm_dbg_kms(&dev_priv->drm, "Disabling HPD storm detection\n"); + + spin_lock_irq(&dev_priv->irq_lock); + hotplug->hpd_storm_threshold = new_threshold; + /* Reset the HPD storm stats so we don't accidentally trigger a storm */ + for_each_hpd_pin(i) + hotplug->stats[i].count = 0; + spin_unlock_irq(&dev_priv->irq_lock); + + /* Re-enable hpd immediately if we were in an irq storm */ + flush_delayed_work(&dev_priv->display.hotplug.reenable_work); + + return len; +} + +static int i915_hpd_storm_ctl_open(struct inode *inode, struct file *file) +{ + return single_open(file, i915_hpd_storm_ctl_show, inode->i_private); +} + +static const struct file_operations i915_hpd_storm_ctl_fops = { + .owner = THIS_MODULE, + .open = i915_hpd_storm_ctl_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = i915_hpd_storm_ctl_write +}; + +static int i915_hpd_short_storm_ctl_show(struct seq_file *m, void *data) +{ + struct drm_i915_private *dev_priv = m->private; + + seq_printf(m, "Enabled: %s\n", + str_yes_no(dev_priv->display.hotplug.hpd_short_storm_enabled)); + + return 0; +} + +static int +i915_hpd_short_storm_ctl_open(struct inode *inode, struct file *file) +{ + return single_open(file, i915_hpd_short_storm_ctl_show, + inode->i_private); +} + +static ssize_t i915_hpd_short_storm_ctl_write(struct file *file, + const char __user *ubuf, + size_t len, loff_t *offp) +{ + struct seq_file *m = file->private_data; + struct drm_i915_private *dev_priv = m->private; + struct intel_hotplug *hotplug = &dev_priv->display.hotplug; + char *newline; + char tmp[16]; + int i; + bool new_state; + + if (len >= sizeof(tmp)) + return -EINVAL; + + if (copy_from_user(tmp, ubuf, len)) + return -EFAULT; + + tmp[len] = '\0'; + + /* Strip newline, if any */ + newline = strchr(tmp, '\n'); + if (newline) + *newline = '\0'; + + /* Reset to the "default" state for this system */ + if (strcmp(tmp, "reset") == 0) + new_state = !HAS_DP_MST(dev_priv); + else if (kstrtobool(tmp, &new_state) != 0) + return -EINVAL; + + drm_dbg_kms(&dev_priv->drm, "%sabling HPD short storm detection\n", + new_state ? "En" : "Dis"); + + spin_lock_irq(&dev_priv->irq_lock); + hotplug->hpd_short_storm_enabled = new_state; + /* Reset the HPD storm stats so we don't accidentally trigger a storm */ + for_each_hpd_pin(i) + hotplug->stats[i].count = 0; + spin_unlock_irq(&dev_priv->irq_lock); + + /* Re-enable hpd immediately if we were in an irq storm */ + flush_delayed_work(&dev_priv->display.hotplug.reenable_work); + + return len; +} + +static const struct file_operations i915_hpd_short_storm_ctl_fops = { + .owner = THIS_MODULE, + .open = i915_hpd_short_storm_ctl_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = i915_hpd_short_storm_ctl_write, +}; + +void intel_hpd_debugfs_register(struct drm_i915_private *i915) +{ + struct drm_minor *minor = i915->drm.primary; + + debugfs_create_file("i915_hpd_storm_ctl", 0644, minor->debugfs_root, + i915, &i915_hpd_storm_ctl_fops); + debugfs_create_file("i915_hpd_short_storm_ctl", 0644, minor->debugfs_root, + i915, &i915_hpd_short_storm_ctl_fops); +} diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.h b/drivers/gpu/drm/i915/display/intel_hotplug.h index b87e95d606e6..aa84e381d6c3 100644 --- a/drivers/gpu/drm/i915/display/intel_hotplug.h +++ b/drivers/gpu/drm/i915/display/intel_hotplug.h @@ -28,5 +28,6 @@ enum hpd_pin intel_hpd_pin_default(struct drm_i915_private *dev_priv, enum port port); bool intel_hpd_disable(struct drm_i915_private *dev_priv, enum hpd_pin pin); void intel_hpd_enable(struct drm_i915_private *dev_priv, enum hpd_pin pin); +void intel_hpd_debugfs_register(struct drm_i915_private *i915); #endif /* __INTEL_HOTPLUG_H__ */ -- cgit From dd890d428fe157f661e19e17c12349c785a97d4b Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 16 Sep 2022 16:06:34 +0300 Subject: drm/i915/hotplug: refactor hotplug init slightly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename intel_hpd_init_work() to the more generic intel_hpd_init_early(), and move the hotplug storm initialization there. This lets us move the HPD_STORM_DEFAULT_THRESHOLD macro to intel_hotplug.c too. Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220916130634.3781122-2-jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_hotplug.c | 22 +++++++++++++++++----- drivers/gpu/drm/i915/display/intel_hotplug.h | 2 +- drivers/gpu/drm/i915/i915_drv.h | 3 --- drivers/gpu/drm/i915/i915_irq.c | 11 +---------- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.c b/drivers/gpu/drm/i915/display/intel_hotplug.c index 4faae25d76c0..352a1b53b63e 100644 --- a/drivers/gpu/drm/i915/display/intel_hotplug.c +++ b/drivers/gpu/drm/i915/display/intel_hotplug.c @@ -90,6 +90,9 @@ enum hpd_pin intel_hpd_pin_default(struct drm_i915_private *dev_priv, return HPD_PORT_A + port - PORT_A; } +/* Threshold == 5 for long IRQs, 50 for short */ +#define HPD_STORM_DEFAULT_THRESHOLD 50 + #define HPD_STORM_DETECT_PERIOD 1000 #define HPD_STORM_REENABLE_DELAY (2 * 60 * 1000) #define HPD_RETRY_DELAY 1000 @@ -711,14 +714,23 @@ void intel_hpd_poll_disable(struct drm_i915_private *dev_priv) schedule_work(&dev_priv->display.hotplug.poll_init_work); } -void intel_hpd_init_work(struct drm_i915_private *dev_priv) +void intel_hpd_init_early(struct drm_i915_private *i915) { - INIT_DELAYED_WORK(&dev_priv->display.hotplug.hotplug_work, + INIT_DELAYED_WORK(&i915->display.hotplug.hotplug_work, i915_hotplug_work_func); - INIT_WORK(&dev_priv->display.hotplug.dig_port_work, i915_digport_work_func); - INIT_WORK(&dev_priv->display.hotplug.poll_init_work, i915_hpd_poll_init_work); - INIT_DELAYED_WORK(&dev_priv->display.hotplug.reenable_work, + INIT_WORK(&i915->display.hotplug.dig_port_work, i915_digport_work_func); + INIT_WORK(&i915->display.hotplug.poll_init_work, i915_hpd_poll_init_work); + INIT_DELAYED_WORK(&i915->display.hotplug.reenable_work, intel_hpd_irq_storm_reenable_work); + + i915->display.hotplug.hpd_storm_threshold = HPD_STORM_DEFAULT_THRESHOLD; + /* If we have MST support, we want to avoid doing short HPD IRQ storm + * detection, as short HPD storms will occur as a natural part of + * sideband messaging with MST. + * On older platforms however, IRQ storms can occur with both long and + * short pulses, as seen on some G4x systems. + */ + i915->display.hotplug.hpd_short_storm_enabled = !HAS_DP_MST(i915); } void intel_hpd_cancel_work(struct drm_i915_private *dev_priv) diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.h b/drivers/gpu/drm/i915/display/intel_hotplug.h index aa84e381d6c3..424ae5dbf5a0 100644 --- a/drivers/gpu/drm/i915/display/intel_hotplug.h +++ b/drivers/gpu/drm/i915/display/intel_hotplug.h @@ -22,7 +22,7 @@ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv, u32 pin_mask, u32 long_mask); void intel_hpd_trigger_irq(struct intel_digital_port *dig_port); void intel_hpd_init(struct drm_i915_private *dev_priv); -void intel_hpd_init_work(struct drm_i915_private *dev_priv); +void intel_hpd_init_early(struct drm_i915_private *i915); void intel_hpd_cancel_work(struct drm_i915_private *dev_priv); enum hpd_pin intel_hpd_pin_default(struct drm_i915_private *dev_priv, enum port port); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 48f1ce9362a5..ea1ca3e6d68e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -75,9 +75,6 @@ struct intel_limit; struct intel_overlay_error_state; struct vlv_s0ix_state; -/* Threshold == 5 for long IRQs, 50 for short */ -#define HPD_STORM_DEFAULT_THRESHOLD 50 - #define I915_GEM_GPU_DOMAINS \ (I915_GEM_DOMAIN_RENDER | \ I915_GEM_DOMAIN_SAMPLER | \ diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 515648cd1233..8ffd81243a19 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -4399,7 +4399,7 @@ void intel_irq_init(struct drm_i915_private *dev_priv) intel_hpd_init_pins(dev_priv); - intel_hpd_init_work(dev_priv); + intel_hpd_init_early(dev_priv); dev->vblank_disable_immediate = true; @@ -4413,15 +4413,6 @@ void intel_irq_init(struct drm_i915_private *dev_priv) if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) dev_priv->display_irqs_enabled = false; - dev_priv->display.hotplug.hpd_storm_threshold = HPD_STORM_DEFAULT_THRESHOLD; - /* If we have MST support, we want to avoid doing short HPD IRQ storm - * detection, as short HPD storms will occur as a natural part of - * sideband messaging with MST. - * On older platforms however, IRQ storms can occur with both long and - * short pulses, as seen on some G4x systems. - */ - dev_priv->display.hotplug.hpd_short_storm_enabled = !HAS_DP_MST(dev_priv); - if (HAS_GMCH(dev_priv)) { if (I915_HAS_HOTPLUG(dev_priv)) dev_priv->display.funcs.hotplug = &i915_hpd_funcs; -- cgit From 48176104003058e2ba540fd815ec46c350d65926 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 16 Sep 2022 14:38:50 +0300 Subject: drm/i915/display: remove ipc_enabled from struct drm_i915_private MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ipc_enabled member was supposed to be moved under the display wm sub-struct, but due to a rebase fail only the new one was added and the old one was left behind. Finish the job. Fixes: 70296670f672 ("drm/i915/display: move IPC under display wm sub-struct") Cc: Ville Syrjälä Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220916113850.3712354-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ea1ca3e6d68e..cc6ca550d8eb 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -391,8 +391,6 @@ struct drm_i915_private { */ u8 snps_phy_failed_calibration; - bool ipc_enabled; - struct i915_pmu pmu; struct i915_drm_clients clients; -- cgit From 14f2f9bf34b180aa90b2088836f5153cb56db95e Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Fri, 9 Sep 2022 17:16:31 -0700 Subject: drm/i915/mtl: Add MTL forcewake support MTL has separate forcewake tables for the primary/render GT and the media GT; each GT's intel_uncore will use a separate forcewake table and should only initialize the domains that are relevant to that GT. The GT ack register also moves to a new location of (GSI base + 0xDFC) on this platform. Note that although our uncore handlers take care of transparently redirecting all register accesses in the media GT's GSI range to their new offset at 0x380000, the forcewake ranges listed in the table should use the final, post-translation offsets. NOTE: There are two ranges in the media IP that have multicast registers where the two register instances reside in different power wells (either VD0 or VD2). We don't have an easy way to deal with this today (and in fact we don't even access these register ranges in the driver today), so for now we just mark those ranges as FORCEWAKE_ALL which will cause all of the media power wells to be grabbed, ensuring proper operation. If we start reading/writing in those ranges in the future, we can re-visit whether it's worth adding extra steering complexity into our forcewake support. Bspec: 67788, 67789, 52077 Cc: Radhakrishna Sripada Signed-off-by: Matt Roper Reviewed-by: Harish Chegondi Link: https://patchwork.freedesktop.org/patch/msgid/20220910001631.1986601-1-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/gt/intel_gt_regs.h | 5 + drivers/gpu/drm/i915/intel_uncore.c | 258 ++++++++++++++++++++++++-- drivers/gpu/drm/i915/intel_uncore.h | 2 + drivers/gpu/drm/i915/selftests/intel_uncore.c | 4 + 4 files changed, 258 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_regs.h b/drivers/gpu/drm/i915/gt/intel_gt_regs.h index 2275ee47da95..1cbb7226400b 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_regs.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_regs.h @@ -39,6 +39,9 @@ #define FORCEWAKE_ACK_RENDER_GEN9 _MMIO(0xd84) #define FORCEWAKE_ACK_MEDIA_GEN9 _MMIO(0xd88) +#define FORCEWAKE_ACK_GSC _MMIO(0xdf8) +#define FORCEWAKE_ACK_GT_MTL _MMIO(0xdfc) + #define MCFG_MCR_SELECTOR _MMIO(0xfd0) #define SF_MCR_SELECTOR _MMIO(0xfd8) #define GEN8_MCR_SELECTOR _MMIO(0xfdc) @@ -898,6 +901,8 @@ #define FORCEWAKE_MEDIA_VDBOX_GEN11(n) _MMIO(0xa540 + (n) * 4) #define FORCEWAKE_MEDIA_VEBOX_GEN11(n) _MMIO(0xa560 + (n) * 4) +#define FORCEWAKE_REQ_GSC _MMIO(0xa618) + #define CHV_POWER_SS0_SIG1 _MMIO(0xa720) #define CHV_POWER_SS0_SIG2 _MMIO(0xa724) #define CHV_POWER_SS1_SIG1 _MMIO(0xa728) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 5d3405cb5930..c058cdc6d8a0 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -104,6 +104,7 @@ static const char * const forcewake_domain_names[] = { "vebox1", "vebox2", "vebox3", + "gsc", }; const char * @@ -888,10 +889,13 @@ void assert_forcewakes_active(struct intel_uncore *uncore, spin_unlock_irq(&uncore->lock); } -/* We give fast paths for the really cool registers */ +/* + * We give fast paths for the really cool registers. The second range includes + * media domains (and the GSC starting from Xe_LPM+) + */ #define NEEDS_FORCE_WAKE(reg) ({ \ u32 __reg = (reg); \ - __reg < 0x40000 || __reg >= GEN11_BSD_RING_BASE; \ + __reg < 0x40000 || __reg >= 0x116000; \ }) static int fw_range_cmp(u32 offset, const struct intel_forcewake_range *entry) @@ -1131,6 +1135,45 @@ static const struct i915_range pvc_shadowed_regs[] = { { .start = 0x1F8510, .end = 0x1F8550 }, }; +static const struct i915_range mtl_shadowed_regs[] = { + { .start = 0x2030, .end = 0x2030 }, + { .start = 0x2510, .end = 0x2550 }, + { .start = 0xA008, .end = 0xA00C }, + { .start = 0xA188, .end = 0xA188 }, + { .start = 0xA278, .end = 0xA278 }, + { .start = 0xA540, .end = 0xA56C }, + { .start = 0xC050, .end = 0xC050 }, + { .start = 0xC340, .end = 0xC340 }, + { .start = 0xC4C8, .end = 0xC4C8 }, + { .start = 0xC4E0, .end = 0xC4E0 }, + { .start = 0xC600, .end = 0xC600 }, + { .start = 0xC658, .end = 0xC658 }, + { .start = 0xCFD4, .end = 0xCFDC }, + { .start = 0x22030, .end = 0x22030 }, + { .start = 0x22510, .end = 0x22550 }, +}; + +static const struct i915_range xelpmp_shadowed_regs[] = { + { .start = 0x1C0030, .end = 0x1C0030 }, + { .start = 0x1C0510, .end = 0x1C0550 }, + { .start = 0x1C8030, .end = 0x1C8030 }, + { .start = 0x1C8510, .end = 0x1C8550 }, + { .start = 0x1D0030, .end = 0x1D0030 }, + { .start = 0x1D0510, .end = 0x1D0550 }, + { .start = 0x38A008, .end = 0x38A00C }, + { .start = 0x38A188, .end = 0x38A188 }, + { .start = 0x38A278, .end = 0x38A278 }, + { .start = 0x38A540, .end = 0x38A56C }, + { .start = 0x38A618, .end = 0x38A618 }, + { .start = 0x38C050, .end = 0x38C050 }, + { .start = 0x38C340, .end = 0x38C340 }, + { .start = 0x38C4C8, .end = 0x38C4C8 }, + { .start = 0x38C4E0, .end = 0x38C4E4 }, + { .start = 0x38C600, .end = 0x38C600 }, + { .start = 0x38C658, .end = 0x38C658 }, + { .start = 0x38CFD4, .end = 0x38CFDC }, +}; + static int mmio_range_cmp(u32 key, const struct i915_range *range) { if (key < range->start) @@ -1679,6 +1722,162 @@ static const struct intel_forcewake_range __pvc_fw_ranges[] = { GEN_FW_RANGE(0x3e0000, 0x3effff, FORCEWAKE_GT), }; +static const struct intel_forcewake_range __mtl_fw_ranges[] = { + GEN_FW_RANGE(0x0, 0xaff, 0), + GEN_FW_RANGE(0xb00, 0xbff, FORCEWAKE_GT), + GEN_FW_RANGE(0xc00, 0xfff, 0), + GEN_FW_RANGE(0x1000, 0x1fff, FORCEWAKE_GT), + GEN_FW_RANGE(0x2000, 0x26ff, FORCEWAKE_RENDER), + GEN_FW_RANGE(0x2700, 0x2fff, FORCEWAKE_GT), + GEN_FW_RANGE(0x3000, 0x3fff, FORCEWAKE_RENDER), + GEN_FW_RANGE(0x4000, 0x51ff, FORCEWAKE_GT), /* + 0x4000 - 0x48ff: render + 0x4900 - 0x51ff: reserved */ + GEN_FW_RANGE(0x5200, 0x7fff, FORCEWAKE_RENDER), /* + 0x5200 - 0x53ff: render + 0x5400 - 0x54ff: reserved + 0x5500 - 0x7fff: render */ + GEN_FW_RANGE(0x8000, 0x813f, FORCEWAKE_GT), + GEN_FW_RANGE(0x8140, 0x817f, FORCEWAKE_RENDER), /* + 0x8140 - 0x815f: render + 0x8160 - 0x817f: reserved */ + GEN_FW_RANGE(0x8180, 0x81ff, 0), + GEN_FW_RANGE(0x8200, 0x94cf, FORCEWAKE_GT), /* + 0x8200 - 0x87ff: gt + 0x8800 - 0x8dff: reserved + 0x8e00 - 0x8f7f: gt + 0x8f80 - 0x8fff: reserved + 0x9000 - 0x947f: gt + 0x9480 - 0x94cf: reserved */ + GEN_FW_RANGE(0x94d0, 0x955f, FORCEWAKE_RENDER), + GEN_FW_RANGE(0x9560, 0x967f, 0), /* + 0x9560 - 0x95ff: always on + 0x9600 - 0x967f: reserved */ + GEN_FW_RANGE(0x9680, 0x97ff, FORCEWAKE_RENDER), /* + 0x9680 - 0x96ff: render + 0x9700 - 0x97ff: reserved */ + GEN_FW_RANGE(0x9800, 0xcfff, FORCEWAKE_GT), /* + 0x9800 - 0xb4ff: gt + 0xb500 - 0xbfff: reserved + 0xc000 - 0xcfff: gt */ + GEN_FW_RANGE(0xd000, 0xd7ff, 0), /* + 0xd000 - 0xd3ff: always on + 0xd400 - 0xd7ff: reserved */ + GEN_FW_RANGE(0xd800, 0xd87f, FORCEWAKE_RENDER), + GEN_FW_RANGE(0xd880, 0xdbff, FORCEWAKE_GT), + GEN_FW_RANGE(0xdc00, 0xdcff, FORCEWAKE_RENDER), + GEN_FW_RANGE(0xdd00, 0xde7f, FORCEWAKE_GT), /* + 0xdd00 - 0xddff: gt + 0xde00 - 0xde7f: reserved */ + GEN_FW_RANGE(0xde80, 0xe8ff, FORCEWAKE_RENDER), /* + 0xde80 - 0xdfff: render + 0xe000 - 0xe0ff: reserved + 0xe100 - 0xe8ff: render */ + GEN_FW_RANGE(0xe900, 0xe9ff, FORCEWAKE_GT), + GEN_FW_RANGE(0xea00, 0x147ff, 0), /* + 0xea00 - 0x11fff: reserved + 0x12000 - 0x127ff: always on + 0x12800 - 0x147ff: reserved */ + GEN_FW_RANGE(0x14800, 0x19fff, FORCEWAKE_GT), /* + 0x14800 - 0x153ff: gt + 0x15400 - 0x19fff: reserved */ + GEN_FW_RANGE(0x1a000, 0x21fff, FORCEWAKE_RENDER), /* + 0x1a000 - 0x1bfff: render + 0x1c000 - 0x21fff: reserved */ + GEN_FW_RANGE(0x22000, 0x23fff, FORCEWAKE_GT), + GEN_FW_RANGE(0x24000, 0x2ffff, 0), /* + 0x24000 - 0x2407f: always on + 0x24080 - 0x2ffff: reserved */ + GEN_FW_RANGE(0x30000, 0x3ffff, FORCEWAKE_GT) +}; + +/* + * Note that the register ranges here are the final offsets after + * translation of the GSI block to the 0x380000 offset. + * + * NOTE: There are a couple MCR ranges near the bottom of this table + * that need to power up either VD0 or VD2 depending on which replicated + * instance of the register we're trying to access. Our forcewake logic + * at the moment doesn't have a good way to take steering into consideration, + * and the driver doesn't even access any registers in those ranges today, + * so for now we just mark those ranges as FORCEWAKE_ALL. That will ensure + * proper operation if we do start using the ranges in the future, and we + * can determine at that time whether it's worth adding extra complexity to + * the forcewake handling to take steering into consideration. + */ +static const struct intel_forcewake_range __xelpmp_fw_ranges[] = { + GEN_FW_RANGE(0x0, 0x115fff, 0), /* render GT range */ + GEN_FW_RANGE(0x116000, 0x11ffff, FORCEWAKE_GSC), /* + 0x116000 - 0x117fff: gsc + 0x118000 - 0x119fff: reserved + 0x11a000 - 0x11efff: gsc + 0x11f000 - 0x11ffff: reserved */ + GEN_FW_RANGE(0x120000, 0x1bffff, 0), /* non-GT range */ + GEN_FW_RANGE(0x1c0000, 0x1c7fff, FORCEWAKE_MEDIA_VDBOX0), /* + 0x1c0000 - 0x1c3dff: VD0 + 0x1c3e00 - 0x1c3eff: reserved + 0x1c3f00 - 0x1c3fff: VD0 + 0x1c4000 - 0x1c7fff: reserved */ + GEN_FW_RANGE(0x1c8000, 0x1cbfff, FORCEWAKE_MEDIA_VEBOX0), /* + 0x1c8000 - 0x1ca0ff: VE0 + 0x1ca100 - 0x1cbfff: reserved */ + GEN_FW_RANGE(0x1cc000, 0x1cffff, FORCEWAKE_MEDIA_VDBOX0), /* + 0x1cc000 - 0x1cdfff: VD0 + 0x1ce000 - 0x1cffff: reserved */ + GEN_FW_RANGE(0x1d0000, 0x1d7fff, FORCEWAKE_MEDIA_VDBOX2), /* + 0x1d0000 - 0x1d3dff: VD2 + 0x1d3e00 - 0x1d3eff: reserved + 0x1d4000 - 0x1d7fff: VD2 */ + GEN_FW_RANGE(0x1d8000, 0x1da0ff, FORCEWAKE_MEDIA_VEBOX1), + GEN_FW_RANGE(0x1da100, 0x380aff, 0), /* + 0x1da100 - 0x23ffff: reserved + 0x240000 - 0x37ffff: non-GT range + 0x380000 - 0x380aff: reserved */ + GEN_FW_RANGE(0x380b00, 0x380bff, FORCEWAKE_GT), + GEN_FW_RANGE(0x380c00, 0x380fff, 0), + GEN_FW_RANGE(0x381000, 0x38817f, FORCEWAKE_GT), /* + 0x381000 - 0x381fff: gt + 0x382000 - 0x383fff: reserved + 0x384000 - 0x384aff: gt + 0x384b00 - 0x3851ff: reserved + 0x385200 - 0x3871ff: gt + 0x387200 - 0x387fff: reserved + 0x388000 - 0x38813f: gt + 0x388140 - 0x38817f: reserved */ + GEN_FW_RANGE(0x388180, 0x3882ff, 0), /* + 0x388180 - 0x3881ff: always on + 0x388200 - 0x3882ff: reserved */ + GEN_FW_RANGE(0x388300, 0x38955f, FORCEWAKE_GT), /* + 0x388300 - 0x38887f: gt + 0x388880 - 0x388fff: reserved + 0x389000 - 0x38947f: gt + 0x389480 - 0x38955f: reserved */ + GEN_FW_RANGE(0x389560, 0x389fff, 0), /* + 0x389560 - 0x3895ff: always on + 0x389600 - 0x389fff: reserved */ + GEN_FW_RANGE(0x38a000, 0x38cfff, FORCEWAKE_GT), /* + 0x38a000 - 0x38afff: gt + 0x38b000 - 0x38bfff: reserved + 0x38c000 - 0x38cfff: gt */ + GEN_FW_RANGE(0x38d000, 0x38d11f, 0), + GEN_FW_RANGE(0x38d120, 0x391fff, FORCEWAKE_GT), /* + 0x38d120 - 0x38dfff: gt + 0x38e000 - 0x38efff: reserved + 0x38f000 - 0x38ffff: gt + 0x389000 - 0x391fff: reserved */ + GEN_FW_RANGE(0x392000, 0x392fff, 0), /* + 0x392000 - 0x3927ff: always on + 0x392800 - 0x292fff: reserved */ + GEN_FW_RANGE(0x393000, 0x3931ff, FORCEWAKE_GT), + GEN_FW_RANGE(0x393200, 0x39323f, FORCEWAKE_ALL), /* instance-based, see note above */ + GEN_FW_RANGE(0x393240, 0x3933ff, FORCEWAKE_GT), + GEN_FW_RANGE(0x393400, 0x3934ff, FORCEWAKE_ALL), /* instance-based, see note above */ + GEN_FW_RANGE(0x393500, 0x393c7f, 0), /* + 0x393500 - 0x393bff: reserved + 0x393c00 - 0x393c7f: always on */ + GEN_FW_RANGE(0x393c80, 0x393dff, FORCEWAKE_GT), +}; + static void ilk_dummy_write(struct intel_uncore *uncore) { @@ -2021,6 +2220,7 @@ static int __fw_domain_init(struct intel_uncore *uncore, BUILD_BUG_ON(FORCEWAKE_MEDIA_VEBOX1 != (1 << FW_DOMAIN_ID_MEDIA_VEBOX1)); BUILD_BUG_ON(FORCEWAKE_MEDIA_VEBOX2 != (1 << FW_DOMAIN_ID_MEDIA_VEBOX2)); BUILD_BUG_ON(FORCEWAKE_MEDIA_VEBOX3 != (1 << FW_DOMAIN_ID_MEDIA_VEBOX3)); + BUILD_BUG_ON(FORCEWAKE_GSC != (1 << FW_DOMAIN_ID_GSC)); d->mask = BIT(domain_id); @@ -2085,17 +2285,26 @@ static int intel_uncore_fw_domains_init(struct intel_uncore *uncore) (ret ?: (ret = __fw_domain_init((uncore__), (id__), (set__), (ack__)))) if (GRAPHICS_VER(i915) >= 11) { - /* we'll prune the domains of missing engines later */ - intel_engine_mask_t emask = INTEL_INFO(i915)->platform_engine_mask; + intel_engine_mask_t emask; int i; + /* we'll prune the domains of missing engines later */ + emask = uncore->gt->info.engine_mask; + uncore->fw_get_funcs = &uncore_get_fallback; - fw_domain_init(uncore, FW_DOMAIN_ID_RENDER, - FORCEWAKE_RENDER_GEN9, - FORCEWAKE_ACK_RENDER_GEN9); - fw_domain_init(uncore, FW_DOMAIN_ID_GT, - FORCEWAKE_GT_GEN9, - FORCEWAKE_ACK_GT_GEN9); + if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 70)) + fw_domain_init(uncore, FW_DOMAIN_ID_GT, + FORCEWAKE_GT_GEN9, + FORCEWAKE_ACK_GT_MTL); + else + fw_domain_init(uncore, FW_DOMAIN_ID_GT, + FORCEWAKE_GT_GEN9, + FORCEWAKE_ACK_GT_GEN9); + + if (RCS_MASK(uncore->gt) || CCS_MASK(uncore->gt)) + fw_domain_init(uncore, FW_DOMAIN_ID_RENDER, + FORCEWAKE_RENDER_GEN9, + FORCEWAKE_ACK_RENDER_GEN9); for (i = 0; i < I915_MAX_VCS; i++) { if (!__HAS_ENGINE(emask, _VCS(i))) @@ -2113,6 +2322,10 @@ static int intel_uncore_fw_domains_init(struct intel_uncore *uncore) FORCEWAKE_MEDIA_VEBOX_GEN11(i), FORCEWAKE_ACK_MEDIA_VEBOX_GEN11(i)); } + + if (uncore->gt->type == GT_MEDIA) + fw_domain_init(uncore, FW_DOMAIN_ID_GSC, + FORCEWAKE_REQ_GSC, FORCEWAKE_ACK_GSC); } else if (IS_GRAPHICS_VER(i915, 9, 10)) { uncore->fw_get_funcs = &uncore_get_fallback; fw_domain_init(uncore, FW_DOMAIN_ID_RENDER, @@ -2300,6 +2513,22 @@ static void uncore_raw_init(struct intel_uncore *uncore) } } +static int uncore_media_forcewake_init(struct intel_uncore *uncore) +{ + struct drm_i915_private *i915 = uncore->i915; + + if (MEDIA_VER(i915) >= 13) { + ASSIGN_FW_DOMAINS_TABLE(uncore, __xelpmp_fw_ranges); + ASSIGN_SHADOW_TABLE(uncore, xelpmp_shadowed_regs); + ASSIGN_WRITE_MMIO_VFUNCS(uncore, fwtable); + } else { + MISSING_CASE(MEDIA_VER(i915)); + return -ENODEV; + } + + return 0; +} + static int uncore_forcewake_init(struct intel_uncore *uncore) { struct drm_i915_private *i915 = uncore->i915; @@ -2314,7 +2543,14 @@ static int uncore_forcewake_init(struct intel_uncore *uncore) ASSIGN_READ_MMIO_VFUNCS(uncore, fwtable); - if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 60)) { + if (uncore->gt->type == GT_MEDIA) + return uncore_media_forcewake_init(uncore); + + if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 70)) { + ASSIGN_FW_DOMAINS_TABLE(uncore, __mtl_fw_ranges); + ASSIGN_SHADOW_TABLE(uncore, mtl_shadowed_regs); + ASSIGN_WRITE_MMIO_VFUNCS(uncore, fwtable); + } else if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 60)) { ASSIGN_FW_DOMAINS_TABLE(uncore, __pvc_fw_ranges); ASSIGN_SHADOW_TABLE(uncore, pvc_shadowed_regs); ASSIGN_WRITE_MMIO_VFUNCS(uncore, fwtable); diff --git a/drivers/gpu/drm/i915/intel_uncore.h b/drivers/gpu/drm/i915/intel_uncore.h index 5022bac80b67..7e1b3b89f689 100644 --- a/drivers/gpu/drm/i915/intel_uncore.h +++ b/drivers/gpu/drm/i915/intel_uncore.h @@ -62,6 +62,7 @@ enum forcewake_domain_id { FW_DOMAIN_ID_MEDIA_VEBOX1, FW_DOMAIN_ID_MEDIA_VEBOX2, FW_DOMAIN_ID_MEDIA_VEBOX3, + FW_DOMAIN_ID_GSC, FW_DOMAIN_ID_COUNT }; @@ -82,6 +83,7 @@ enum forcewake_domains { FORCEWAKE_MEDIA_VEBOX1 = BIT(FW_DOMAIN_ID_MEDIA_VEBOX1), FORCEWAKE_MEDIA_VEBOX2 = BIT(FW_DOMAIN_ID_MEDIA_VEBOX2), FORCEWAKE_MEDIA_VEBOX3 = BIT(FW_DOMAIN_ID_MEDIA_VEBOX3), + FORCEWAKE_GSC = BIT(FW_DOMAIN_ID_GSC), FORCEWAKE_ALL = BIT(FW_DOMAIN_ID_COUNT) - 1, }; diff --git a/drivers/gpu/drm/i915/selftests/intel_uncore.c b/drivers/gpu/drm/i915/selftests/intel_uncore.c index fda9bb79c049..e4281508d580 100644 --- a/drivers/gpu/drm/i915/selftests/intel_uncore.c +++ b/drivers/gpu/drm/i915/selftests/intel_uncore.c @@ -70,6 +70,8 @@ static int intel_shadow_table_check(void) { gen12_shadowed_regs, ARRAY_SIZE(gen12_shadowed_regs) }, { dg2_shadowed_regs, ARRAY_SIZE(dg2_shadowed_regs) }, { pvc_shadowed_regs, ARRAY_SIZE(pvc_shadowed_regs) }, + { mtl_shadowed_regs, ARRAY_SIZE(mtl_shadowed_regs) }, + { xelpmp_shadowed_regs, ARRAY_SIZE(xelpmp_shadowed_regs) }, }; const struct i915_range *range; unsigned int i, j; @@ -117,6 +119,8 @@ int intel_uncore_mock_selftests(void) { __gen12_fw_ranges, ARRAY_SIZE(__gen12_fw_ranges), true }, { __xehp_fw_ranges, ARRAY_SIZE(__xehp_fw_ranges), true }, { __pvc_fw_ranges, ARRAY_SIZE(__pvc_fw_ranges), true }, + { __mtl_fw_ranges, ARRAY_SIZE(__mtl_fw_ranges), true }, + { __xelpmp_fw_ranges, ARRAY_SIZE(__xelpmp_fw_ranges), true }, }; int err, i; -- cgit From 1cec34442408a77ba5396b19725fed2c398005c3 Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Fri, 16 Sep 2022 11:24:02 +0200 Subject: drm/i915/gem: Flush contexts on driver release Due to i915_perf assuming that it can use the i915_gem_context reference to protect its i915->gem.contexts.list iteration, we need to defer removal of the context from the list until last reference to the context is put. However, there is a risk of triggering kernel warning on contexts list not empty at driver release time if we deleagate that task to a worker for i915_gem_context_release_work(), unless that work is flushed first. Unfortunately, it is not flushed on driver release. Fix it. Instead of additionally calling flush_workqueue(), either directly or via a new dedicated wrapper around it, replace last call to i915_gem_drain_freed_objects() with existing i915_gem_drain_workqueue() that performs both tasks. Fixes: 75eefd82581f ("drm/i915: Release i915_gem_context from a worker") Suggested-by: Chris Wilson Signed-off-by: Janusz Krzysztofik Reviewed-by: Andi Shyti Cc: stable@kernel.org # v5.16+ Signed-off-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20220916092403.201355-2-janusz.krzysztofik@linux.intel.com --- drivers/gpu/drm/i915/i915_gem.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index be7fede6cd6f..4539431a3c3e 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1214,7 +1214,8 @@ void i915_gem_driver_release(struct drm_i915_private *dev_priv) intel_uc_cleanup_firmwares(>->uc); } - i915_gem_drain_freed_objects(dev_priv); + /* Flush any outstanding work, including i915_gem_context.release_work. */ + i915_gem_drain_workqueue(dev_priv); drm_WARN_ON(&dev_priv->drm, !list_empty(&dev_priv->gem.contexts.list)); } -- cgit From ad3aa7c31efa5a09b0dba42e66cfdf77e0db7dc2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 16 Sep 2022 11:24:03 +0200 Subject: drm/i915/gem: Really move i915_gem_context.link under ref protection i915_perf assumes that it can use the i915_gem_context reference to protect its i915->gem.contexts.list iteration. However, this requires that we do not remove the context from the list until after we drop the final reference and release the struct. If, as currently, we remove the context from the list during context_close(), the link.next pointer may be poisoned while we are holding the context reference and cause a GPF: [ 4070.573157] i915 0000:00:02.0: [drm:i915_perf_open_ioctl [i915]] filtering on ctx_id=0x1fffff ctx_id_mask=0x1fffff [ 4070.574881] general protection fault, probably for non-canonical address 0xdead000000000100: 0000 [#1] PREEMPT SMP [ 4070.574897] CPU: 1 PID: 284392 Comm: amd_performance Tainted: G E 5.17.9 #180 [ 4070.574903] Hardware name: Intel Corporation NUC7i5BNK/NUC7i5BNB, BIOS BNKBL357.86A.0052.2017.0918.1346 09/18/2017 [ 4070.574907] RIP: 0010:oa_configure_all_contexts.isra.0+0x222/0x350 [i915] [ 4070.574982] Code: 08 e8 32 6e 10 e1 4d 8b 6d 50 b8 ff ff ff ff 49 83 ed 50 f0 41 0f c1 04 24 83 f8 01 0f 84 e3 00 00 00 85 c0 0f 8e fa 00 00 00 <49> 8b 45 50 48 8d 70 b0 49 8d 45 50 48 39 44 24 10 0f 85 34 fe ff [ 4070.574990] RSP: 0018:ffffc90002077b78 EFLAGS: 00010202 [ 4070.574995] RAX: 0000000000000002 RBX: 0000000000000002 RCX: 0000000000000000 [ 4070.575000] RDX: 0000000000000001 RSI: ffffc90002077b20 RDI: ffff88810ddc7c68 [ 4070.575004] RBP: 0000000000000001 R08: ffff888103242648 R09: fffffffffffffffc [ 4070.575008] R10: ffffffff82c50bc0 R11: 0000000000025c80 R12: ffff888101bf1860 [ 4070.575012] R13: dead0000000000b0 R14: ffffc90002077c04 R15: ffff88810be5cabc [ 4070.575016] FS: 00007f1ed50c0780(0000) GS:ffff88885ec80000(0000) knlGS:0000000000000000 [ 4070.575021] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 4070.575025] CR2: 00007f1ed5590280 CR3: 000000010ef6f005 CR4: 00000000003706e0 [ 4070.575029] Call Trace: [ 4070.575033] [ 4070.575037] lrc_configure_all_contexts+0x13e/0x150 [i915] [ 4070.575103] gen8_enable_metric_set+0x4d/0x90 [i915] [ 4070.575164] i915_perf_open_ioctl+0xbc0/0x1500 [i915] [ 4070.575224] ? asm_common_interrupt+0x1e/0x40 [ 4070.575232] ? i915_oa_init_reg_state+0x110/0x110 [i915] [ 4070.575290] drm_ioctl_kernel+0x85/0x110 [ 4070.575296] ? update_load_avg+0x5f/0x5e0 [ 4070.575302] drm_ioctl+0x1d3/0x370 [ 4070.575307] ? i915_oa_init_reg_state+0x110/0x110 [i915] [ 4070.575382] ? gen8_gt_irq_handler+0x46/0x130 [i915] [ 4070.575445] __x64_sys_ioctl+0x3c4/0x8d0 [ 4070.575451] ? __do_softirq+0xaa/0x1d2 [ 4070.575456] do_syscall_64+0x35/0x80 [ 4070.575461] entry_SYSCALL_64_after_hwframe+0x44/0xae [ 4070.575467] RIP: 0033:0x7f1ed5c10397 [ 4070.575471] Code: 3c 1c e8 1c ff ff ff 85 c0 79 87 49 c7 c4 ff ff ff ff 5b 5d 4c 89 e0 41 5c c3 66 0f 1f 84 00 00 00 00 00 b8 10 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d a9 da 0d 00 f7 d8 64 89 01 48 [ 4070.575478] RSP: 002b:00007ffd65c8d7a8 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 [ 4070.575484] RAX: ffffffffffffffda RBX: 0000000000000006 RCX: 00007f1ed5c10397 [ 4070.575488] RDX: 00007ffd65c8d7c0 RSI: 0000000040106476 RDI: 0000000000000006 [ 4070.575492] RBP: 00005620972f9c60 R08: 000000000000000a R09: 0000000000000005 [ 4070.575496] R10: 000000000000000d R11: 0000000000000246 R12: 000000000000000a [ 4070.575500] R13: 000000000000000d R14: 0000000000000000 R15: 00007ffd65c8d7c0 [ 4070.575505] [ 4070.575507] Modules linked in: nls_ascii(E) nls_cp437(E) vfat(E) fat(E) i915(E) x86_pkg_temp_thermal(E) intel_powerclamp(E) crct10dif_pclmul(E) crc32_pclmul(E) crc32c_intel(E) aesni_intel(E) crypto_simd(E) intel_gtt(E) cryptd(E) ttm(E) rapl(E) intel_cstate(E) drm_kms_helper(E) cfbfillrect(E) syscopyarea(E) cfbimgblt(E) intel_uncore(E) sysfillrect(E) mei_me(E) sysimgblt(E) i2c_i801(E) fb_sys_fops(E) mei(E) intel_pch_thermal(E) i2c_smbus(E) cfbcopyarea(E) video(E) button(E) efivarfs(E) autofs4(E) [ 4070.575549] ---[ end trace 0000000000000000 ]--- v3: fix incorrect syntax of spin_lock() replacing spin_lock_irqsave() v2: irqsave not required in a worker, neither conversion to irq safe elsewhere (Tvrtko), - perf: it's safe to call gen8_configure_context() even if context has been closed, no need to check, - drop unrelated cleanup (Andi, Tvrtko) Reported-by: Mark Janes Closes: https://gitlab.freedesktop.org/drm/intel/issues/6222 References: a4e7ccdac38e ("drm/i915: Move context management under GEM") Fixes: f8246cf4d9a9 ("drm/i915/gem: Drop free_work for GEM contexts") Signed-off-by: Chris Wilson Reviewed-by: Andi Shyti Signed-off-by: Janusz Krzysztofik Cc: Tvrtko Ursulin Cc: # v5.12+ Signed-off-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20220916092403.201355-3-janusz.krzysztofik@linux.intel.com --- drivers/gpu/drm/i915/gem/i915_gem_context.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c index dabdfe09f5e5..0bcde53c50c6 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c @@ -1269,6 +1269,10 @@ static void i915_gem_context_release_work(struct work_struct *work) trace_i915_context_free(ctx); GEM_BUG_ON(!i915_gem_context_is_closed(ctx)); + spin_lock(&ctx->i915->gem.contexts.lock); + list_del(&ctx->link); + spin_unlock(&ctx->i915->gem.contexts.lock); + if (ctx->syncobj) drm_syncobj_put(ctx->syncobj); @@ -1521,10 +1525,6 @@ static void context_close(struct i915_gem_context *ctx) ctx->file_priv = ERR_PTR(-EBADF); - spin_lock(&ctx->i915->gem.contexts.lock); - list_del(&ctx->link); - spin_unlock(&ctx->i915->gem.contexts.lock); - client = ctx->client; if (client) { spin_lock(&client->ctx_lock); -- cgit From 429a09553559297cc4e021fff2253f4035d3be2e Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 16 Sep 2022 23:41:32 +0300 Subject: drm/i915: WARN if a port should use VBT provided vswing tables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don't parse the VBT vswing/preemphassis tables at all currently. Let's WARN if a port wants to use them so we get a heads up that whether we really need to implement this stuff or not. My current stash contains no VBTs with this bit set. v2: Move to print_ddi_port() (Jani) Reviewed-by: Rodrigo Vivi Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220916204132.10469-1-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_bios.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index 28bdb936cd1f..4c543e8205ca 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -2676,6 +2676,14 @@ static void print_ddi_port(const struct intel_bios_encoder_data *devdata, drm_dbg_kms(&i915->drm, "Port %c VBT DP max link rate: %d\n", port_name(port), dp_max_link_rate); + + /* + * FIXME need to implement support for VBT + * vswing/preemph tables should this ever trigger. + */ + drm_WARN(&i915->drm, child->use_vbt_vswing, + "Port %c asks to use VBT vswing/preemph tables\n", + port_name(port)); } static void parse_ddi_port(struct intel_bios_encoder_data *devdata) -- cgit From bff0d857053bdacbde1e0deea3b468de3a2b7234 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 20 Jun 2022 21:29:16 +0300 Subject: drm/i915/fbc: Move flip_pending assignmnt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the flip_pending assignment into __intel_fbc_post_update() from intel_fbc_post_update(). Now mirrors the pre_update() side. The only reason the assignment was in the higher level function is that we used to call __intel_fbc_post_update() from elsewhere as well. That got cleaned up in commit b39d2c620242 ("drm/i915/fbc: Call intel_fbc_activate() directly from frontbuffer flush") Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220620182917.10765-1-ville.syrjala@linux.intel.com Reviewed-by: Mika Kahola --- drivers/gpu/drm/i915/display/intel_fbc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c index f38175304928..4f81a5f4fa35 100644 --- a/drivers/gpu/drm/i915/display/intel_fbc.c +++ b/drivers/gpu/drm/i915/display/intel_fbc.c @@ -1303,6 +1303,8 @@ static void __intel_fbc_post_update(struct intel_fbc *fbc) drm_WARN_ON(&i915->drm, !mutex_is_locked(&fbc->lock)); + fbc->flip_pending = false; + if (!fbc->busy_bits) intel_fbc_activate(fbc); else @@ -1324,10 +1326,8 @@ void intel_fbc_post_update(struct intel_atomic_state *state, mutex_lock(&fbc->lock); - if (fbc->state.plane == plane) { - fbc->flip_pending = false; + if (fbc->state.plane == plane) __intel_fbc_post_update(fbc); - } mutex_unlock(&fbc->lock); } -- cgit From 9045c0529c40c1a9227d58cfb494033c82274a7d Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 20 Jun 2022 21:29:17 +0300 Subject: drm/i915/fbc: Use lockdep_assert_held() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the mutex_is_locked() stuff with lockdep_assert_held() since that's what it's there for. Also sprinkle these around so that we have more or less mirrored coverage for the enable vs. disable instead of the current situation where the asserts seem to be more or less randomly thrown around. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220620182917.10765-2-ville.syrjala@linux.intel.com Reviewed-by: Mika Kahola --- drivers/gpu/drm/i915/display/intel_fbc.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c index 4f81a5f4fa35..6bd8ff02a60b 100644 --- a/drivers/gpu/drm/i915/display/intel_fbc.c +++ b/drivers/gpu/drm/i915/display/intel_fbc.c @@ -670,6 +670,7 @@ static void intel_fbc_nuke(struct intel_fbc *fbc) { struct drm_i915_private *i915 = fbc->i915; + lockdep_assert_held(&fbc->lock); drm_WARN_ON(&i915->drm, fbc->flip_pending); trace_intel_fbc_nuke(fbc->state.plane); @@ -679,6 +680,8 @@ static void intel_fbc_nuke(struct intel_fbc *fbc) static void intel_fbc_activate(struct intel_fbc *fbc) { + lockdep_assert_held(&fbc->lock); + intel_fbc_hw_activate(fbc); intel_fbc_nuke(fbc); @@ -687,9 +690,7 @@ static void intel_fbc_activate(struct intel_fbc *fbc) static void intel_fbc_deactivate(struct intel_fbc *fbc, const char *reason) { - struct drm_i915_private *i915 = fbc->i915; - - drm_WARN_ON(&i915->drm, !mutex_is_locked(&fbc->lock)); + lockdep_assert_held(&fbc->lock); if (fbc->active) intel_fbc_hw_deactivate(fbc); @@ -1227,6 +1228,8 @@ static bool __intel_fbc_pre_update(struct intel_atomic_state *state, struct intel_fbc *fbc = plane->fbc; bool need_vblank_wait = false; + lockdep_assert_held(&fbc->lock); + fbc->flip_pending = true; if (intel_fbc_can_flip_nuke(state, crtc, plane)) @@ -1284,7 +1287,7 @@ static void __intel_fbc_disable(struct intel_fbc *fbc) struct drm_i915_private *i915 = fbc->i915; struct intel_plane *plane = fbc->state.plane; - drm_WARN_ON(&i915->drm, !mutex_is_locked(&fbc->lock)); + lockdep_assert_held(&fbc->lock); drm_WARN_ON(&i915->drm, fbc->active); drm_dbg_kms(&i915->drm, "Disabling FBC on [PLANE:%d:%s]\n", @@ -1299,9 +1302,7 @@ static void __intel_fbc_disable(struct intel_fbc *fbc) static void __intel_fbc_post_update(struct intel_fbc *fbc) { - struct drm_i915_private *i915 = fbc->i915; - - drm_WARN_ON(&i915->drm, !mutex_is_locked(&fbc->lock)); + lockdep_assert_held(&fbc->lock); fbc->flip_pending = false; @@ -1437,6 +1438,8 @@ static void __intel_fbc_enable(struct intel_atomic_state *state, intel_atomic_get_new_plane_state(state, plane); struct intel_fbc *fbc = plane->fbc; + lockdep_assert_held(&fbc->lock); + if (fbc->state.plane) { if (fbc->state.plane != plane) return; -- cgit From 0d2d201095e9f141d6a9fb44320afce761f8b5c2 Mon Sep 17 00:00:00 2001 From: Ashutosh Dixit Date: Mon, 19 Sep 2022 09:24:01 -0700 Subject: drm/i915: Perf_limit_reasons are only available for Gen11+ Register GT0_PERF_LIMIT_REASONS (0x1381a8) is available only for Gen11+. Therefore ensure perf_limit_reasons sysfs/debugfs files are created only for Gen11+. Otherwise on Gen < 5 accessing these files results in the following oops: <1> [88.829420] BUG: unable to handle page fault for address: ffffc90000bb81a8 <1> [88.829438] #PF: supervisor read access in kernel mode <1> [88.829447] #PF: error_code(0x0000) - not-present page Bspec: 20008 Bug: https://gitlab.freedesktop.org/drm/intel/-/issues/6863 Fixes: fe5979665f64 ("drm/i915/debugfs: Add perf_limit_reasons in debugfs") Fixes: fa68bff7cf27 ("drm/i915/gt: Add sysfs throttle frequency interfaces") Signed-off-by: Ashutosh Dixit Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20220919162401.2077713-1-ashutosh.dixit@intel.com --- drivers/gpu/drm/i915/gt/intel_gt.c | 4 ++++ drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c | 10 +++++++++- drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c | 15 +++++++++++---- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c b/drivers/gpu/drm/i915/gt/intel_gt.c index abc46ba7cf1d..5343a9141f25 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt.c +++ b/drivers/gpu/drm/i915/gt/intel_gt.c @@ -232,6 +232,10 @@ static void gen6_clear_engine_error_register(struct intel_engine_cs *engine) i915_reg_t intel_gt_perf_limit_reasons_reg(struct intel_gt *gt) { + /* GT0_PERF_LIMIT_REASONS is available only for Gen11+ */ + if (GRAPHICS_VER(gt->i915) < 11) + return INVALID_MMIO_REG; + return gt->type == GT_MEDIA ? MTL_MEDIA_PERF_LIMIT_REASONS : GT0_PERF_LIMIT_REASONS; } diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c index 3157d06e8995..9fd4d9255a97 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c @@ -682,6 +682,14 @@ static int perf_limit_reasons_clear(void *data, u64 val) return 0; } + +static bool perf_limit_reasons_eval(void *data) +{ + struct intel_gt *gt = data; + + return i915_mmio_reg_valid(intel_gt_perf_limit_reasons_reg(gt)); +} + DEFINE_SIMPLE_ATTRIBUTE(perf_limit_reasons_fops, perf_limit_reasons_get, perf_limit_reasons_clear, "%llu\n"); @@ -694,7 +702,7 @@ void intel_gt_pm_debugfs_register(struct intel_gt *gt, struct dentry *root) { "forcewake_user", &forcewake_user_fops, NULL}, { "llc", &llc_fops, llc_eval }, { "rps_boost", &rps_boost_fops, rps_eval }, - { "perf_limit_reasons", &perf_limit_reasons_fops, NULL }, + { "perf_limit_reasons", &perf_limit_reasons_fops, perf_limit_reasons_eval }, }; intel_gt_debugfs_register_files(root, files, ARRAY_SIZE(files), gt); diff --git a/drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c b/drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c index 54deae45d81f..904160952369 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c @@ -545,8 +545,7 @@ static INTEL_GT_RPS_BOOL_ATTR_RO(throttle_reason_ratl, RATL_MASK); static INTEL_GT_RPS_BOOL_ATTR_RO(throttle_reason_vr_thermalert, VR_THERMALERT_MASK); static INTEL_GT_RPS_BOOL_ATTR_RO(throttle_reason_vr_tdc, VR_TDC_MASK); -static const struct attribute *freq_attrs[] = { - &dev_attr_punit_req_freq_mhz.attr, +static const struct attribute *throttle_reason_attrs[] = { &attr_throttle_reason_status.attr, &attr_throttle_reason_pl1.attr, &attr_throttle_reason_pl2.attr, @@ -791,12 +790,20 @@ void intel_gt_sysfs_pm_init(struct intel_gt *gt, struct kobject *kobj) if (!is_object_gt(kobj)) return; - ret = sysfs_create_files(kobj, freq_attrs); + ret = sysfs_create_file(kobj, &dev_attr_punit_req_freq_mhz.attr); if (ret) drm_warn(>->i915->drm, - "failed to create gt%u throttle sysfs files (%pe)", + "failed to create gt%u punit_req_freq_mhz sysfs (%pe)", gt->info.id, ERR_PTR(ret)); + if (i915_mmio_reg_valid(intel_gt_perf_limit_reasons_reg(gt))) { + ret = sysfs_create_files(kobj, throttle_reason_attrs); + if (ret) + drm_warn(>->i915->drm, + "failed to create gt%u throttle sysfs files (%pe)", + gt->info.id, ERR_PTR(ret)); + } + if (HAS_MEDIA_RATIO_MODE(gt->i915) && intel_uc_uses_guc_slpc(>->uc)) { ret = sysfs_create_files(kobj, media_perf_power_attrs); if (ret) -- cgit From fb7818989976317cc2e78008aa2df7b9fe423c86 Mon Sep 17 00:00:00 2001 From: Nirmoy Das Date: Tue, 20 Sep 2022 19:06:28 +0200 Subject: drm/i915: Do not cleanup obj with NULL bo->resource For delayed BO release i915_ttm_delete_mem_notify() gets called twice, once with proper bo->resource and another time with NULL. We shouldn't do anything for the 2nd time as we already cleaned up the obj once. References: https://gitlab.freedesktop.org/drm/intel/-/issues/6850 Fixes: ad74457a6b5a96 ("drm/i915/dgfx: Release mmap on rpm suspend") Signed-off-by: Nirmoy Das Reviewed-by: Matthew Auld Signed-off-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20220920170628.3391-1-nirmoy.das@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c index dea6e378946f..72ba56e638c8 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c @@ -550,7 +550,7 @@ static void i915_ttm_delete_mem_notify(struct ttm_buffer_object *bo) struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo); intel_wakeref_t wakeref = 0; - if (likely(obj)) { + if (bo->resource && likely(obj)) { /* ttm_bo_release() already has dma_resv_lock */ if (i915_ttm_cpu_maps_iomem(bo->resource)) wakeref = intel_runtime_pm_get(&to_i915(obj->base.dev)->runtime_pm); -- cgit From 07a70f38e9c33b3c614668b12a847f9fe65a4e25 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Thu, 15 Sep 2022 18:43:45 -0700 Subject: drm/i915: Split GAM and MSLICE steering Although the bspec lists several MMIO ranges as "MSLICE," it turns out that a subset of these are of a "GAM" subclass that has unique rules and doesn't followed regular mslice steering behavior. * Xe_HP SDV: GAM ranges must always be steered to 0,0. These registers share the regular steering control register (0xFDC) with other steering types * DG2: GAM ranges must always be steered to 1,0. GAM registers have a dedicated steering control register (0xFE0) so we can set the value once at startup and rely on implicit steering. Technically the hardware default should already be set to 1,0 properly, but it never hurts to ensure that in the driver. Bspec: 66534 Signed-off-by: Matt Roper Reviewed-by: Prathap Kumar Valsan Link: https://patchwork.freedesktop.org/patch/msgid/20220916014345.3317739-1-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/gt/intel_gt_mcr.c | 24 ++++++++++++++++++++++-- drivers/gpu/drm/i915/gt/intel_gt_regs.h | 1 + drivers/gpu/drm/i915/gt/intel_gt_types.h | 1 + drivers/gpu/drm/i915/gt/intel_workarounds.c | 10 ++++++++++ 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_mcr.c b/drivers/gpu/drm/i915/gt/intel_gt_mcr.c index e79405a45312..a2047a68ea7a 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_mcr.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_mcr.c @@ -40,6 +40,7 @@ static const char * const intel_steering_types[] = { "L3BANK", "MSLICE", "LNCF", + "GAM", "INSTANCE 0", }; @@ -48,14 +49,23 @@ static const struct intel_mmio_range icl_l3bank_steering_table[] = { {}, }; +/* + * Although the bspec lists more "MSLICE" ranges than shown here, some of those + * are of a "GAM" subclass that has special rules. Thus we use a separate + * GAM table farther down for those. + */ static const struct intel_mmio_range xehpsdv_mslice_steering_table[] = { - { 0x004000, 0x004AFF }, - { 0x00C800, 0x00CFFF }, { 0x00DD00, 0x00DDFF }, { 0x00E900, 0x00FFFF }, /* 0xEA00 - OxEFFF is unused */ {}, }; +static const struct intel_mmio_range xehpsdv_gam_steering_table[] = { + { 0x004000, 0x004AFF }, + { 0x00C800, 0x00CFFF }, + {}, +}; + static const struct intel_mmio_range xehpsdv_lncf_steering_table[] = { { 0x00B000, 0x00B0FF }, { 0x00D800, 0x00D8FF }, @@ -114,9 +124,15 @@ void intel_gt_mcr_init(struct intel_gt *gt) } else if (IS_DG2(i915)) { gt->steering_table[MSLICE] = xehpsdv_mslice_steering_table; gt->steering_table[LNCF] = dg2_lncf_steering_table; + /* + * No need to hook up the GAM table since it has a dedicated + * steering control register on DG2 and can use implicit + * steering. + */ } else if (IS_XEHPSDV(i915)) { gt->steering_table[MSLICE] = xehpsdv_mslice_steering_table; gt->steering_table[LNCF] = xehpsdv_lncf_steering_table; + gt->steering_table[GAM] = xehpsdv_gam_steering_table; } else if (GRAPHICS_VER(i915) >= 11 && GRAPHICS_VER_FULL(i915) < IP_VER(12, 50)) { gt->steering_table[L3BANK] = icl_l3bank_steering_table; @@ -351,6 +367,10 @@ static void get_nonterminated_steering(struct intel_gt *gt, *group = __ffs(gt->info.mslice_mask) << 1; *instance = 0; /* unused */ break; + case GAM: + *group = IS_DG2(gt->i915) ? 1 : 0; + *instance = 0; + break; case INSTANCE0: /* * There are a lot of MCR types for which instance (0, 0) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_regs.h b/drivers/gpu/drm/i915/gt/intel_gt_regs.h index 1cbb7226400b..755a2c101269 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_regs.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_regs.h @@ -45,6 +45,7 @@ #define MCFG_MCR_SELECTOR _MMIO(0xfd0) #define SF_MCR_SELECTOR _MMIO(0xfd8) #define GEN8_MCR_SELECTOR _MMIO(0xfdc) +#define GAM_MCR_SELECTOR _MMIO(0xfe0) #define GEN8_MCR_SLICE(slice) (((slice) & 3) << 26) #define GEN8_MCR_SLICE_MASK GEN8_MCR_SLICE(3) #define GEN8_MCR_SUBSLICE(subslice) (((subslice) & 3) << 24) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_types.h b/drivers/gpu/drm/i915/gt/intel_gt_types.h index f19c2de77ff6..30003d68fd51 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_types.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_types.h @@ -59,6 +59,7 @@ enum intel_steering_type { L3BANK, MSLICE, LNCF, + GAM, /* * On some platforms there are multiple types of MCR registers that diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c index 6d2003d598e6..d04652a3b4e5 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds.c +++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c @@ -1181,6 +1181,9 @@ xehp_init_mcr(struct intel_gt *gt, struct i915_wa_list *wal) gt->steering_table[MSLICE] = NULL; } + if (IS_XEHPSDV(gt->i915) && slice_mask & BIT(0)) + gt->steering_table[GAM] = NULL; + slice = __ffs(slice_mask); subslice = intel_sseu_find_first_xehp_dss(sseu, GEN_DSS_PER_GSLICE, slice) % GEN_DSS_PER_GSLICE; @@ -1198,6 +1201,13 @@ xehp_init_mcr(struct intel_gt *gt, struct i915_wa_list *wal) */ __set_mcr_steering(wal, MCFG_MCR_SELECTOR, 0, 2); __set_mcr_steering(wal, SF_MCR_SELECTOR, 0, 2); + + /* + * On DG2, GAM registers have a dedicated steering control register + * and must always be programmed to a hardcoded groupid of "1." + */ + if (IS_DG2(gt->i915)) + __set_mcr_steering(wal, GAM_MCR_SELECTOR, 1, 0); } static void -- cgit From e5f415bfc5c2c94fbb124f8aabfc638168a44cf4 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Fri, 16 Sep 2022 10:36:06 -0700 Subject: drm/i915: Add missing mask when reading GEN12_DSMBASE DSMBASE register is defined so BDSM bitfield contains the bits 63 to 20 of the base address of stolen. For the supported platforms bits 0-19 are zero but that may not be true in future. Add the missing mask. v2: Use REG_GENMASK64() Acked-by: Aravind Iddamsetty Reviewed-by: Caz Yokoyama Reviewed-by: Wayne Boyer Signed-off-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20220915-stolen-v2-1-20ff797de047@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_stolen.c | 2 +- drivers/gpu/drm/i915/i915_reg.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c index ed4a67ddab19..d24268595460 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c @@ -809,7 +809,7 @@ i915_gem_stolen_lmem_setup(struct drm_i915_private *i915, u16 type, return ERR_PTR(-ENODEV); /* Use DSM base address instead for stolen memory */ - dsm_base = intel_uncore_read64(uncore, GEN12_DSMBASE); + dsm_base = intel_uncore_read64(uncore, GEN12_DSMBASE) & GEN12_BDSM_MASK; if (IS_DG1(uncore->i915)) { lmem_size = pci_resource_len(pdev, 2); if (WARN_ON(lmem_size < dsm_base)) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 6850d27dc82c..d51e291d310a 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -8501,6 +8501,7 @@ enum skl_power_gate { #define GEN12_GSMBASE _MMIO(0x108100) #define GEN12_DSMBASE _MMIO(0x1080C0) +#define GEN12_BDSM_MASK REG_GENMASK64(63, 20) #define XEHP_CLOCK_GATE_DIS _MMIO(0x101014) #define SGSI_SIDECLK_DIS REG_BIT(17) -- cgit From 3d99597c6496b9319f7522e0d073afab314d518a Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Fri, 16 Sep 2022 10:36:07 -0700 Subject: drm/i915: Split i915_gem_init_stolen() Add some helpers: adjust_stolen(), request_smem_stolen_() and init_reserved_stolen() that are now called by i915_gem_init_stolen() to initialize each part of the Data Stolen Memory region. Main goal is to split the reserved part within the stolen, also known as WOPCM, as its calculation changes often per platform and is a big source of confusion when handling stolen memory. Reviewed-by: Wayne Boyer Signed-off-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20220915-stolen-v2-2-20ff797de047@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_stolen.c | 143 +++++++++++++++++------------ 1 file changed, 85 insertions(+), 58 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c index d24268595460..9e0747bff0c5 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c @@ -75,22 +75,26 @@ void i915_gem_stolen_remove_node(struct drm_i915_private *i915, mutex_unlock(&i915->mm.stolen_lock); } -static int i915_adjust_stolen(struct drm_i915_private *i915, - struct resource *dsm) +static bool valid_stolen_size(struct resource *dsm) +{ + return dsm->start != 0 && dsm->end > dsm->start; +} + +static int adjust_stolen(struct drm_i915_private *i915, + struct resource *dsm) { struct i915_ggtt *ggtt = to_gt(i915)->ggtt; struct intel_uncore *uncore = ggtt->vm.gt->uncore; - struct resource *r; - if (dsm->start == 0 || dsm->end <= dsm->start) + if (!valid_stolen_size(dsm)) return -EINVAL; /* + * Make sure we don't clobber the GTT if it's within stolen memory + * * TODO: We have yet too encounter the case where the GTT wasn't at the * end of stolen. With that assumption we could simplify this. */ - - /* Make sure we don't clobber the GTT if it's within stolen memory */ if (GRAPHICS_VER(i915) <= 4 && !IS_G33(i915) && !IS_PINEVIEW(i915) && !IS_G4X(i915)) { struct resource stolen[2] = {*dsm, *dsm}; @@ -129,10 +133,20 @@ static int i915_adjust_stolen(struct drm_i915_private *i915, } } + if (!valid_stolen_size(dsm)) + return -EINVAL; + + return 0; +} + +static int request_smem_stolen(struct drm_i915_private *i915, + struct resource *dsm) +{ + struct resource *r; + /* - * With stolen lmem, we don't need to check if the address range - * overlaps with the non-stolen system memory range, since lmem is local - * to the gpu. + * With stolen lmem, we don't need to request system memory for the + * address range since it's local to the gpu. */ if (HAS_LMEM(i915)) return 0; @@ -390,39 +404,22 @@ static void icl_get_stolen_reserved(struct drm_i915_private *i915, } } -static int i915_gem_init_stolen(struct intel_memory_region *mem) +/* + * Initialize i915->dsm_reserved to contain the reserved space within the Data + * Stolen Memory. This is a range on the top of DSM that is reserved, not to + * be used by driver, so must be excluded from the region passed to the + * allocator later. In the spec this is also called as WOPCM. + * + * Our expectation is that the reserved space is at the top of the stolen + * region, as it has been the case for every platform, and *never* at the + * bottom, so the calculation here can be simplified. + */ +static int init_reserved_stolen(struct drm_i915_private *i915) { - struct drm_i915_private *i915 = mem->i915; struct intel_uncore *uncore = &i915->uncore; resource_size_t reserved_base, stolen_top; - resource_size_t reserved_total, reserved_size; - - mutex_init(&i915->mm.stolen_lock); - - if (intel_vgpu_active(i915)) { - drm_notice(&i915->drm, - "%s, disabling use of stolen memory\n", - "iGVT-g active"); - return 0; - } - - if (i915_vtd_active(i915) && GRAPHICS_VER(i915) < 8) { - drm_notice(&i915->drm, - "%s, disabling use of stolen memory\n", - "DMAR active"); - return 0; - } - - if (resource_size(&mem->region) == 0) - return 0; - - i915->dsm = mem->region; - - if (i915_adjust_stolen(i915, &i915->dsm)) - return 0; - - GEM_BUG_ON(i915->dsm.start == 0); - GEM_BUG_ON(i915->dsm.end <= i915->dsm.start); + resource_size_t reserved_size; + int ret = 0; stolen_top = i915->dsm.end + 1; reserved_base = stolen_top; @@ -453,17 +450,16 @@ static int i915_gem_init_stolen(struct intel_memory_region *mem) &reserved_base, &reserved_size); } - /* - * Our expectation is that the reserved space is at the top of the - * stolen region and *never* at the bottom. If we see !reserved_base, - * it likely means we failed to read the registers correctly. - */ + /* No reserved stolen */ + if (reserved_base == stolen_top) + goto bail_out; + if (!reserved_base) { drm_err(&i915->drm, "inconsistent reservation %pa + %pa; ignoring\n", &reserved_base, &reserved_size); - reserved_base = stolen_top; - reserved_size = 0; + ret = -EINVAL; + goto bail_out; } i915->dsm_reserved = @@ -473,19 +469,55 @@ static int i915_gem_init_stolen(struct intel_memory_region *mem) drm_err(&i915->drm, "Stolen reserved area %pR outside stolen memory %pR\n", &i915->dsm_reserved, &i915->dsm); + ret = -EINVAL; + goto bail_out; + } + + return 0; + +bail_out: + i915->dsm_reserved = + (struct resource)DEFINE_RES_MEM(reserved_base, 0); + + return ret; +} + +static int i915_gem_init_stolen(struct intel_memory_region *mem) +{ + struct drm_i915_private *i915 = mem->i915; + + mutex_init(&i915->mm.stolen_lock); + + if (intel_vgpu_active(i915)) { + drm_notice(&i915->drm, + "%s, disabling use of stolen memory\n", + "iGVT-g active"); + return 0; + } + + if (i915_vtd_active(i915) && GRAPHICS_VER(i915) < 8) { + drm_notice(&i915->drm, + "%s, disabling use of stolen memory\n", + "DMAR active"); return 0; } + if (adjust_stolen(i915, &mem->region)) + return 0; + + if (request_smem_stolen(i915, &mem->region)) + return 0; + + i915->dsm = mem->region; + + if (init_reserved_stolen(i915)) + return 0; + /* Exclude the reserved region from driver use */ - mem->region.end = reserved_base - 1; + mem->region.end = i915->dsm_reserved.start - 1; mem->io_size = min(mem->io_size, resource_size(&mem->region)); - /* It is possible for the reserved area to end before the end of stolen - * memory, so just consider the start. */ - reserved_total = stolen_top - reserved_base; - - i915->stolen_usable_size = - resource_size(&i915->dsm) - reserved_total; + i915->stolen_usable_size = resource_size(&mem->region); drm_dbg(&i915->drm, "Memory reserved for graphics device: %lluK, usable: %lluK\n", @@ -757,11 +789,6 @@ static int init_stolen_lmem(struct intel_memory_region *mem) if (GEM_WARN_ON(resource_size(&mem->region) == 0)) return -ENODEV; - /* - * TODO: For stolen lmem we mostly just care about populating the dsm - * related bits and setting up the drm_mm allocator for the range. - * Perhaps split up i915_gem_init_stolen() for this. - */ err = i915_gem_init_stolen(mem); if (err) return err; -- cgit From c40bd3b14f72446115241563ee0ce7273aa04f35 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Fri, 16 Sep 2022 10:36:08 -0700 Subject: drm/i915/dgfx: Make failure to setup stolen non-fatal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no reason to consider the setup of Data Stolen Memory fatal on dgfx and non-fatal on integrated. Move the debug and error propagation around so both have the same behavior: non-fatal. Before this change, loading i915 on a system with TGL + DG2 would result in just TGL succeeding the initialization (without stolen). Now loading i915 on the same system with an injected failure in i915_gem_init_stolen(): $ dmesg | grep stolen i915 0000:00:02.0: [drm] Injected failure, disabling use of stolen memory i915 0000:00:02.0: [drm:init_stolen_smem [i915]] Skip stolen region: failed to setup i915 0000:03:00.0: [drm] Injected failure, disabling use of stolen memory i915 0000:03:00.0: [drm:init_stolen_lmem [i915]] Skip stolen region: failed to setup Both GPUs are still available: $ sudo build/tools/lsgpu card1 Intel Dg2 (Gen12) drm:/dev/dri/card1 └─renderD129 drm:/dev/dri/renderD129 card0 Intel Tigerlake (Gen12) drm:/dev/dri/card0 └─renderD128 drm:/dev/dri/renderD128 Reviewed-by: Wayne Boyer Signed-off-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20220915-stolen-v2-3-20ff797de047@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_stolen.c | 51 +++++++++++++++--------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c index 9e0747bff0c5..a89bb5ed6c51 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c @@ -492,26 +492,26 @@ static int i915_gem_init_stolen(struct intel_memory_region *mem) drm_notice(&i915->drm, "%s, disabling use of stolen memory\n", "iGVT-g active"); - return 0; + return -ENOSPC; } if (i915_vtd_active(i915) && GRAPHICS_VER(i915) < 8) { drm_notice(&i915->drm, "%s, disabling use of stolen memory\n", "DMAR active"); - return 0; + return -ENOSPC; } if (adjust_stolen(i915, &mem->region)) - return 0; + return -ENOSPC; if (request_smem_stolen(i915, &mem->region)) - return 0; + return -ENOSPC; i915->dsm = mem->region; if (init_reserved_stolen(i915)) - return 0; + return -ENOSPC; /* Exclude the reserved region from driver use */ mem->region.end = i915->dsm_reserved.start - 1; @@ -525,7 +525,7 @@ static int i915_gem_init_stolen(struct intel_memory_region *mem) (u64)i915->stolen_usable_size >> 10); if (i915->stolen_usable_size == 0) - return 0; + return -ENOSPC; /* Basic memrange allocator for stolen space. */ drm_mm_init(&i915->mm.stolen, 0, i915->stolen_usable_size); @@ -763,11 +763,17 @@ i915_gem_object_create_stolen(struct drm_i915_private *i915, static int init_stolen_smem(struct intel_memory_region *mem) { + int err; + /* * Initialise stolen early so that we may reserve preallocated * objects for the BIOS to KMS transition. */ - return i915_gem_init_stolen(mem); + err = i915_gem_init_stolen(mem); + if (err) + drm_dbg(&mem->i915->drm, "Skip stolen region: failed to setup\n"); + + return 0; } static int release_stolen_smem(struct intel_memory_region *mem) @@ -784,21 +790,25 @@ static const struct intel_memory_region_ops i915_region_stolen_smem_ops = { static int init_stolen_lmem(struct intel_memory_region *mem) { + struct drm_i915_private *i915 = mem->i915; int err; if (GEM_WARN_ON(resource_size(&mem->region) == 0)) - return -ENODEV; + return 0; err = i915_gem_init_stolen(mem); - if (err) - return err; + if (err) { + drm_dbg(&mem->i915->drm, "Skip stolen region: failed to setup\n"); + return 0; + } - if (mem->io_size && !io_mapping_init_wc(&mem->iomap, - mem->io_start, - mem->io_size)) { - err = -EIO; + if (mem->io_size && + !io_mapping_init_wc(&mem->iomap, mem->io_start, mem->io_size)) goto err_cleanup; - } + + drm_dbg(&i915->drm, "Stolen Local memory IO start: %pa\n", + &mem->io_start); + drm_dbg(&i915->drm, "Stolen Local DSM base: %pa\n", &mem->region.start); return 0; @@ -869,16 +879,6 @@ i915_gem_stolen_lmem_setup(struct drm_i915_private *i915, u16 type, if (IS_ERR(mem)) return mem; - /* - * TODO: consider creating common helper to just print all the - * interesting stuff from intel_memory_region, which we can use for all - * our probed regions. - */ - - drm_dbg(&i915->drm, "Stolen Local memory IO start: %pa\n", - &mem->io_start); - drm_dbg(&i915->drm, "Stolen Local DSM base: %pa\n", &dsm_base); - intel_memory_region_set_name(mem, "stolen-local"); mem->private = true; @@ -903,6 +903,7 @@ i915_gem_stolen_smem_setup(struct drm_i915_private *i915, u16 type, intel_memory_region_set_name(mem, "stolen-system"); mem->private = true; + return mem; } -- cgit From 783f6f852cc061e59962e53aa9824aa785de0d8c Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Wed, 7 Sep 2022 16:08:41 -0700 Subject: drm/i915: Noop lrc_init_wa_ctx() on recent/future platforms Except for graphics version 8 and 9, nothing is done in lrc_init_wa_ctx(). Assume this won't be needed on future platforms as well and remove the warning. Note that this function is not called for anything below version 8 since those don't use either guc or execlist, i.e. HAS_EXECLISTS() is false. Reviewed-by: Balasubramani Vivekanandan Signed-off-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20220907230841.1703574-1-lucas.demarchi@intel.com --- drivers/gpu/drm/i915/gt/intel_lrc.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.c b/drivers/gpu/drm/i915/gt/intel_lrc.c index 3955292483a6..82d899f170fb 100644 --- a/drivers/gpu/drm/i915/gt/intel_lrc.c +++ b/drivers/gpu/drm/i915/gt/intel_lrc.c @@ -1718,24 +1718,16 @@ void lrc_init_wa_ctx(struct intel_engine_cs *engine) unsigned int i; int err; - if (!(engine->flags & I915_ENGINE_HAS_RCS_REG_STATE)) + if (GRAPHICS_VER(engine->i915) >= 11 || + !(engine->flags & I915_ENGINE_HAS_RCS_REG_STATE)) return; - switch (GRAPHICS_VER(engine->i915)) { - case 12: - case 11: - return; - case 9: + if (GRAPHICS_VER(engine->i915) == 9) { wa_bb_fn[0] = gen9_init_indirectctx_bb; wa_bb_fn[1] = NULL; - break; - case 8: + } else if (GRAPHICS_VER(engine->i915) == 8) { wa_bb_fn[0] = gen8_init_indirectctx_bb; wa_bb_fn[1] = NULL; - break; - default: - MISSING_CASE(GRAPHICS_VER(engine->i915)); - return; } err = lrc_create_wa_ctx(engine); -- cgit From 559f701db082a26f057463e14480cdf3306b1d91 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 16 Sep 2022 19:52:04 +0300 Subject: drm/i915: Nuke stale plane cdclk ratio FIXMEs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The plane ratio stuff got implemented in commit bb6ae9e653dc ("drm/i915: Allow planes to declare their minimum acceptable cdclk") so these FIXMEs have no business being here. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220916165206.1499-1-ville.syrjala@linux.intel.com Reviewed-by: Luca Coelho --- drivers/gpu/drm/i915/display/intel_cdclk.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index ed05070b7307..a12e86d92783 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -2464,10 +2464,6 @@ static int bdw_modeset_calc_cdclk(struct intel_cdclk_state *cdclk_state) if (min_cdclk < 0) return min_cdclk; - /* - * FIXME should also account for plane ratio - * once 64bpp pixel formats are supported. - */ cdclk = bdw_calc_cdclk(min_cdclk); cdclk_state->logical.cdclk = cdclk; @@ -2534,10 +2530,6 @@ static int skl_modeset_calc_cdclk(struct intel_cdclk_state *cdclk_state) vco = skl_dpll0_vco(cdclk_state); - /* - * FIXME should also account for plane ratio - * once 64bpp pixel formats are supported. - */ cdclk = skl_calc_cdclk(min_cdclk, vco); cdclk_state->logical.vco = vco; -- cgit From 958349ff710b79d85f35be73d1b09991f67b3423 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 16 Sep 2022 19:52:05 +0300 Subject: drm/i915/fbc: Remove stale FIXME MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the old tales about 90/270 degree rotation effectively preventing FBC. That hasn't been true since we stopped demanding the fence is present in commit 691f7ba58d52 ("drm/i915/display/fbc: Make fences a nice-to-have for GEN9+") Also fix up the multiline comment formatting while at it. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220916165206.1499-2-ville.syrjala@linux.intel.com Reviewed-by: Luca Coeho --- drivers/gpu/drm/i915/display/intel_fbc.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c index 6bd8ff02a60b..64b371f9a5fd 100644 --- a/drivers/gpu/drm/i915/display/intel_fbc.c +++ b/drivers/gpu/drm/i915/display/intel_fbc.c @@ -1010,7 +1010,8 @@ static bool intel_fbc_is_fence_ok(const struct intel_plane_state *plane_state) { struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev); - /* The use of a CPU fence is one of two ways to detect writes by the + /* + * The use of a CPU fence is one of two ways to detect writes by the * CPU to the scanout and trigger updates to the FBC. * * The other method is by software tracking (see @@ -1020,12 +1021,6 @@ static bool intel_fbc_is_fence_ok(const struct intel_plane_state *plane_state) * Note that is possible for a tiled surface to be unmappable (and * so have no fence associated with it) due to aperture constraints * at the time of pinning. - * - * FIXME with 90/270 degree rotation we should use the fence on - * the normal GTT view (the rotated view doesn't even have a - * fence). Would need changes to the FBC fence Y offset as well. - * For now this will effectively disable FBC with 90/270 degree - * rotation. */ return DISPLAY_VER(i915) >= 9 || (plane_state->flags & PLANE_HAS_FENCE && -- cgit From 7d33fd02dd943c7f8003e95930d15d92529fe917 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Thu, 30 Jun 2022 13:57:16 +0100 Subject: drm/i915/selftests: Remove flush_scheduled_work() from live_execlists There are ongoing efforts to remove usages of flush_scheduled_work() from drivers in order to avoid several cases of potentential problems when flushing is done from certain contexts. Remove the call from the live_execlists selftest. Its purpose was to be thorough and sync with the execlists capture state handling, but that is not strictly required for the test to function and can be removed. Signed-off-by: Tvrtko Ursulin Cc: Tetsuo Handa Reviewed-by: Nirmoy Das Link: https://patchwork.freedesktop.org/patch/msgid/20220630125716.50835-1-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/gt/selftest_execlists.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/selftest_execlists.c b/drivers/gpu/drm/i915/gt/selftest_execlists.c index 1e08b2473b99..56b7d5b5fea0 100644 --- a/drivers/gpu/drm/i915/gt/selftest_execlists.c +++ b/drivers/gpu/drm/i915/gt/selftest_execlists.c @@ -85,8 +85,6 @@ static int wait_for_reset(struct intel_engine_cs *engine, break; } while (time_before(jiffies, timeout)); - flush_scheduled_work(); - if (rq->fence.error != -EIO) { pr_err("%s: hanging request %llx:%lld not reset\n", engine->name, -- cgit From 45810b4c5c33f785053169f053f282fbfd04e93e Mon Sep 17 00:00:00 2001 From: Matt Atwood Date: Tue, 20 Sep 2022 13:43:59 -0700 Subject: drm/i915/dg2: introduce Wa_22015475538 Wa_22015475538 applies to all DG2 (and ATSM) skus. The workaround implementation is identical to Wa_16011620976. LSC_CHICKEN_BIT_0_UDW is a general render register instead of rcs so adding this move to the proper wa init function. bspec:54077 Signed-off-by: Matt Atwood Reviewed-by: Matt Roper Signed-off-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20220920204359.103370-1-matthew.s.atwood@intel.com --- drivers/gpu/drm/i915/gt/intel_workarounds.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c index d04652a3b4e5..ff5220694f46 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds.c +++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c @@ -2118,9 +2118,6 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) if (IS_DG2_GRAPHICS_STEP(i915, G11, STEP_A0, STEP_B0)) { /* Wa_14013392000:dg2_g11 */ wa_masked_en(wal, GEN7_ROW_CHICKEN2, GEN12_ENABLE_LARGE_GRF_MODE); - - /* Wa_16011620976:dg2_g11 */ - wa_write_or(wal, LSC_CHICKEN_BIT_0_UDW, DIS_CHAIN_2XSIMD8); } if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_B0, STEP_FOREVER) || @@ -2790,6 +2787,14 @@ general_render_compute_wa_init(struct intel_engine_cs *engine, struct i915_wa_li wa_write_or(wal, VDBX_MOD_CTRL, FORCE_MISS_FTLB); wa_write_or(wal, VEBX_MOD_CTRL, FORCE_MISS_FTLB); } + + if (IS_DG2(i915)) { + /* + * Wa_16011620976:dg2_g11 + * Wa_22015475538:dg2 + */ + wa_write_or(wal, LSC_CHICKEN_BIT_0_UDW, DIS_CHAIN_2XSIMD8); + } } static void -- cgit From d37c120b73128690434cc093952439eef9d56af1 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Fri, 16 Sep 2022 12:40:31 +0200 Subject: drm/etnaviv: don't truncate physical page address While the interface for the MMU mapping takes phys_addr_t to hold a full 64bit address when necessary and MMUv2 is able to map physical addresses with up to 40bit, etnaviv_iommu_map() truncates the address to 32bits. Fix this by using the correct type. Fixes: 931e97f3afd8 ("drm/etnaviv: mmuv2: support 40 bit phys address") Signed-off-by: Lucas Stach Reviewed-by: Philipp Zabel --- drivers/gpu/drm/etnaviv/etnaviv_mmu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c index 55479cb8b1ac..67bdce5326c6 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c @@ -80,10 +80,10 @@ static int etnaviv_iommu_map(struct etnaviv_iommu_context *context, u32 iova, return -EINVAL; for_each_sgtable_dma_sg(sgt, sg, i) { - u32 pa = sg_dma_address(sg) - sg->offset; + phys_addr_t pa = sg_dma_address(sg) - sg->offset; size_t bytes = sg_dma_len(sg) + sg->offset; - VERB("map[%d]: %08x %08x(%zx)", i, iova, pa, bytes); + VERB("map[%d]: %08x %pap(%zx)", i, iova, &pa, bytes); ret = etnaviv_context_map(context, da, pa, bytes, prot); if (ret) -- cgit From 4bce244272513ebb4d13c570e9fbca28497015b2 Mon Sep 17 00:00:00 2001 From: Marco Felsch Date: Fri, 26 Aug 2022 21:07:28 +0200 Subject: drm/etnaviv: disable tx clock gating for GC7000 rev6203 The i.MX8MN SoC errata sheet mentions ERR050226: "GPU: Texture L2 Cache idle signal may incorrectly clock gate the texture engine in GPU". The workaround is to disable the corresponding clock gatings. While on it move the clock gating check for rev6202 into the same check to bundle them. Signed-off-by: Marco Felsch Reviewed-by: Christian Gmeiner Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index ed2f9c8f288c..51320eeebfcf 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -623,14 +623,15 @@ static void etnaviv_gpu_enable_mlcg(struct etnaviv_gpu *gpu) /* Disable TX clock gating on affected core revisions. */ if (etnaviv_is_model_rev(gpu, GC4000, 0x5222) || - etnaviv_is_model_rev(gpu, GC2000, 0x5108)) + etnaviv_is_model_rev(gpu, GC2000, 0x5108) || + etnaviv_is_model_rev(gpu, GC2000, 0x6202) || + etnaviv_is_model_rev(gpu, GC2000, 0x6203)) pmc |= VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_TX; - /* Disable SE, RA and TX clock gating on affected core revisions. */ + /* Disable SE and RA clock gating on affected core revisions. */ if (etnaviv_is_model_rev(gpu, GC7000, 0x6202)) pmc |= VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_SE | - VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_RA | - VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_TX; + VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_RA; pmc |= VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_RA_HZ; pmc |= VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_RA_EZ; -- cgit From c2c7075225ef7366a1ccc1cf4b7205c391ec7c9b Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Thu, 15 Sep 2022 18:46:46 -0700 Subject: drm/i915: Read graphics/media/display arch version from hw Going forward, the hardware teams no longer consider new platforms to have a "generation" in the way we've defined it for past platforms. Instead, each IP block (graphics, media, display) will have their own architecture major.minor versions and stepping ID's which should be read directly from a register in the MMIO space. Bspec: 63361, 64111 v2: - Move the IP version readout to intel_device_info.c - Convert the macro into a function v3: - Move subplatform init to runtime early init - Cache runtime ver, release info to compare with hardware values. - Use IP_VER for snaity check(MattR) v4: - Minor doccumentation changes. - Normalize HAS_GMD_ID macro value.(JaniN) Signed-off-by: Matt Roper Signed-off-by: Rodrigo Vivi Reviewed-by: Lucas De Marchi Signed-off-by: Radhakrishna Sripada Link: https://patchwork.freedesktop.org/patch/msgid/20220916014648.1310346-2-radhakrishna.sripada@intel.com --- drivers/gpu/drm/i915/gt/intel_gt_regs.h | 3 ++ drivers/gpu/drm/i915/i915_driver.c | 3 +- drivers/gpu/drm/i915/i915_drv.h | 2 + drivers/gpu/drm/i915/i915_pci.c | 1 + drivers/gpu/drm/i915/i915_reg.h | 7 ++++ drivers/gpu/drm/i915/intel_device_info.c | 67 +++++++++++++++++++++++++++++++- drivers/gpu/drm/i915/intel_device_info.h | 8 +++- 7 files changed, 88 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_regs.h b/drivers/gpu/drm/i915/gt/intel_gt_regs.h index 94f9ddcfb3a5..94a060685922 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_regs.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_regs.h @@ -39,6 +39,9 @@ #define FORCEWAKE_ACK_RENDER_GEN9 _MMIO(0xd84) #define FORCEWAKE_ACK_MEDIA_GEN9 _MMIO(0xd88) +#define GMD_ID_GRAPHICS _MMIO(0xd8c) +#define GMD_ID_MEDIA _MMIO(MTL_MEDIA_GSI_BASE + 0xd8c) + #define MCFG_MCR_SELECTOR _MMIO(0xfd0) #define SF_MCR_SELECTOR _MMIO(0xfd8) #define GEN8_MCR_SELECTOR _MMIO(0xfdc) diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c index 3e1d2a10e9da..f1e06758db19 100644 --- a/drivers/gpu/drm/i915/i915_driver.c +++ b/drivers/gpu/drm/i915/i915_driver.c @@ -324,7 +324,8 @@ static int i915_driver_early_probe(struct drm_i915_private *dev_priv) if (i915_inject_probe_failure(dev_priv)) return -ENODEV; - intel_device_info_subplatform_init(dev_priv); + intel_device_info_runtime_init_early(dev_priv); + intel_step_init(dev_priv); intel_uncore_mmio_debug_init_early(&dev_priv->mmio_debug); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index cc6ca550d8eb..e18b66b8640b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -930,6 +930,8 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915, #define HAS_GMCH(dev_priv) (INTEL_INFO(dev_priv)->display.has_gmch) +#define HAS_GMD_ID(i915) (INTEL_INFO(i915)->has_gmd_id) + #define HAS_LSPCON(dev_priv) (IS_DISPLAY_VER(dev_priv, 9, 10)) #define HAS_L3_CCS_READ(i915) (INTEL_INFO(i915)->has_l3_ccs_read) diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c index 1576cbcf2254..6b563461b314 100644 --- a/drivers/gpu/drm/i915/i915_pci.c +++ b/drivers/gpu/drm/i915/i915_pci.c @@ -1128,6 +1128,7 @@ static const struct intel_device_info mtl_info = { PLATFORM(INTEL_METEORLAKE), .display.has_modular_fia = 1, .has_flat_ccs = 0, + .has_gmd_id = 1, .has_snoop = 1, .__runtime.memory_regions = REGION_SMEM | REGION_STOLEN_LMEM, .__runtime.platform_engine_mask = BIT(RCS0) | BIT(BCS0) | BIT(CCS0), diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 3053c175cf9b..a4f0129c3f6f 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -5839,6 +5839,11 @@ #define ICL_DSSM_CDCLK_PLL_REFCLK_19_2MHz (1 << 29) #define ICL_DSSM_CDCLK_PLL_REFCLK_38_4MHz (2 << 29) +#define GMD_ID_DISPLAY _MMIO(0x510a0) +#define GMD_ID_ARCH_MASK REG_GENMASK(31, 22) +#define GMD_ID_RELEASE_MASK REG_GENMASK(21, 14) +#define GMD_ID_STEP REG_GENMASK(5, 0) + /*GEN11 chicken */ #define _PIPEA_CHICKEN 0x70038 #define _PIPEB_CHICKEN 0x71038 @@ -8356,4 +8361,6 @@ enum skl_power_gate { #define MTL_TRAS_MASK REG_GENMASK(16, 8) #define MTL_TRDPRE_MASK REG_GENMASK(7, 0) +#define MTL_MEDIA_GSI_BASE 0x380000 + #endif /* _I915_REG_H_ */ diff --git a/drivers/gpu/drm/i915/intel_device_info.c b/drivers/gpu/drm/i915/intel_device_info.c index 1434dc33cf49..2018eaaa45f5 100644 --- a/drivers/gpu/drm/i915/intel_device_info.c +++ b/drivers/gpu/drm/i915/intel_device_info.c @@ -29,6 +29,7 @@ #include "display/intel_cdclk.h" #include "display/intel_de.h" +#include "gt/intel_gt_regs.h" #include "intel_device_info.h" #include "i915_drv.h" #include "i915_utils.h" @@ -231,7 +232,7 @@ static bool find_devid(u16 id, const u16 *p, unsigned int num) return false; } -void intel_device_info_subplatform_init(struct drm_i915_private *i915) +static void intel_device_info_subplatform_init(struct drm_i915_private *i915) { const struct intel_device_info *info = INTEL_INFO(i915); const struct intel_runtime_info *rinfo = RUNTIME_INFO(i915); @@ -288,6 +289,70 @@ void intel_device_info_subplatform_init(struct drm_i915_private *i915) RUNTIME_INFO(i915)->platform_mask[pi] |= mask; } +static void ip_ver_read(struct drm_i915_private *i915, u32 offset, struct ip_version *ip) +{ + struct pci_dev *pdev = to_pci_dev(i915->drm.dev); + void __iomem *addr; + u32 val; + u8 expected_ver = ip->ver; + u8 expected_rel = ip->rel; + + addr = pci_iomap_range(pdev, 0, offset, sizeof(u32)); + if (drm_WARN_ON(&i915->drm, !addr)) + return; + + val = ioread32(addr); + pci_iounmap(pdev, addr); + + ip->ver = REG_FIELD_GET(GMD_ID_ARCH_MASK, val); + ip->rel = REG_FIELD_GET(GMD_ID_RELEASE_MASK, val); + ip->step = REG_FIELD_GET(GMD_ID_STEP, val); + + /* Sanity check against expected versions from device info */ + if (IP_VER(ip->ver, ip->rel) < IP_VER(expected_ver, expected_rel)) + drm_dbg(&i915->drm, + "Hardware reports GMD IP version %u.%u (REG[0x%x] = 0x%08x) but minimum expected is %u.%u\n", + ip->ver, ip->rel, offset, val, expected_ver, expected_rel); +} + +/* + * Setup the graphics version for the current device. This must be done before + * any code that performs checks on GRAPHICS_VER or DISPLAY_VER, so this + * function should be called very early in the driver initialization sequence. + * + * Regular MMIO access is not yet setup at the point this function is called so + * we peek at the appropriate MMIO offset directly. The GMD_ID register is + * part of an 'always on' power well by design, so we don't need to worry about + * forcewake while reading it. + */ +static void intel_ipver_early_init(struct drm_i915_private *i915) +{ + struct intel_runtime_info *runtime = RUNTIME_INFO(i915); + + if (!HAS_GMD_ID(i915)) + return; + + ip_ver_read(i915, i915_mmio_reg_offset(GMD_ID_GRAPHICS), + &runtime->graphics.ip); + ip_ver_read(i915, i915_mmio_reg_offset(GMD_ID_DISPLAY), + &runtime->display.ip); + ip_ver_read(i915, i915_mmio_reg_offset(GMD_ID_MEDIA), + &runtime->media.ip); +} + +/** + * intel_device_info_runtime_init_early - initialize early runtime info + * @i915: the i915 device + * + * Determine early intel_device_info fields at runtime. This function needs + * to be called before the MMIO has been setup. + */ +void intel_device_info_runtime_init_early(struct drm_i915_private *i915) +{ + intel_ipver_early_init(i915); + intel_device_info_subplatform_init(i915); +} + /** * intel_device_info_runtime_init - initialize runtime info * @dev_priv: the i915 device diff --git a/drivers/gpu/drm/i915/intel_device_info.h b/drivers/gpu/drm/i915/intel_device_info.h index b6b971606727..8e494c59f9a1 100644 --- a/drivers/gpu/drm/i915/intel_device_info.h +++ b/drivers/gpu/drm/i915/intel_device_info.h @@ -152,6 +152,7 @@ enum intel_ppgtt_type { func(has_4tile); \ func(has_flat_ccs); \ func(has_global_mocs); \ + func(has_gmd_id); \ func(has_gt_uc); \ func(has_heci_pxp); \ func(has_heci_gscfi); \ @@ -196,9 +197,14 @@ enum intel_ppgtt_type { struct ip_version { u8 ver; u8 rel; + u8 step; }; struct intel_runtime_info { + /* + * Single "graphics" IP version that represents + * render, compute and copy behavior. + */ struct { struct ip_version ip; } graphics; @@ -304,7 +310,7 @@ struct intel_driver_caps { const char *intel_platform_name(enum intel_platform platform); -void intel_device_info_subplatform_init(struct drm_i915_private *dev_priv); +void intel_device_info_runtime_init_early(struct drm_i915_private *dev_priv); void intel_device_info_runtime_init(struct drm_i915_private *dev_priv); void intel_device_info_print(const struct intel_device_info *info, -- cgit From 944ca7d8b12f9ed4abaa4e63223b62bd9b653b5c Mon Sep 17 00:00:00 2001 From: José Roberto de Souza Date: Thu, 15 Sep 2022 18:46:47 -0700 Subject: drm/i915: Parse and set stepping for platforms with GMD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Expand the current stepping convention to accommodate the GMD stepping info. Typically GMD step maps to letter stepping by "A + step %4" and number to "A + step /4" i.e, GMD step 0 maps to STEP_A0, 1 to _A1, 2 to _A2, 3 to _A3, 4 to STEP_B0... Future platforms might break this formulae and may require a table mapping to decode GMD step compatible with the convention. v2: - Pass the updated ip version structure v3: - Skip using GMD to step table(MattR) Cc: Balasubramani Vivekanandan Cc: Matt Roper Reviewed-by: Lucas De Marchi Signed-off-by: Radhakrishna Sripada Signed-off-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20220916014648.1310346-3-radhakrishna.sripada@intel.com --- drivers/gpu/drm/i915/intel_step.c | 25 +++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_step.h | 28 +++++++++++++++++++++++++++- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_step.c b/drivers/gpu/drm/i915/intel_step.c index 42b3133d8387..91e7c51991b0 100644 --- a/drivers/gpu/drm/i915/intel_step.c +++ b/drivers/gpu/drm/i915/intel_step.c @@ -135,6 +135,19 @@ static const struct intel_step_info adlp_n_revids[] = { [0x0] = { COMMON_GT_MEDIA_STEP(A0), .display_step = STEP_D0 }, }; +static u8 gmd_to_intel_step(struct drm_i915_private *i915, + struct ip_version *gmd) +{ + u8 step = gmd->step + STEP_A0; + + if (step >= STEP_FUTURE) { + drm_dbg(&i915->drm, "Using future steppings\n"); + return STEP_FUTURE; + } + + return step; +} + static void pvc_step_init(struct drm_i915_private *i915, int pci_revid); void intel_step_init(struct drm_i915_private *i915) @@ -144,6 +157,18 @@ void intel_step_init(struct drm_i915_private *i915) int revid = INTEL_REVID(i915); struct intel_step_info step = {}; + if (HAS_GMD_ID(i915)) { + step.graphics_step = gmd_to_intel_step(i915, + &RUNTIME_INFO(i915)->graphics.ip); + step.media_step = gmd_to_intel_step(i915, + &RUNTIME_INFO(i915)->media.ip); + step.display_step = gmd_to_intel_step(i915, + &RUNTIME_INFO(i915)->display.ip); + RUNTIME_INFO(i915)->step = step; + + return; + } + if (IS_PONTEVECCHIO(i915)) { pvc_step_init(i915, revid); return; diff --git a/drivers/gpu/drm/i915/intel_step.h b/drivers/gpu/drm/i915/intel_step.h index a6b12bfa9744..96dfca4cba73 100644 --- a/drivers/gpu/drm/i915/intel_step.h +++ b/drivers/gpu/drm/i915/intel_step.h @@ -11,6 +11,10 @@ struct drm_i915_private; struct intel_step_info { + /* + * It is expected to have 4 number steps per letter. Deviation from + * the expectation breaks gmd_to_intel_step(). + */ u8 graphics_step; /* Represents the compute tile on Xe_HPC */ u8 display_step; u8 media_step; @@ -23,21 +27,43 @@ struct intel_step_info { func(A0) \ func(A1) \ func(A2) \ + func(A3) \ func(B0) \ func(B1) \ func(B2) \ func(B3) \ func(C0) \ func(C1) \ + func(C2) \ + func(C3) \ func(D0) \ func(D1) \ + func(D2) \ + func(D3) \ func(E0) \ + func(E1) \ + func(E2) \ + func(E3) \ func(F0) \ + func(F1) \ + func(F2) \ + func(F3) \ func(G0) \ + func(G1) \ + func(G2) \ + func(G3) \ func(H0) \ + func(H1) \ + func(H2) \ + func(H3) \ func(I0) \ func(I1) \ - func(J0) + func(I2) \ + func(I3) \ + func(J0) \ + func(J1) \ + func(J2) \ + func(J3) /* * Symbolic steppings that do not match the hardware. These are valid both as gt -- cgit From 8146d588bfc822b5377dfc0a227af77a57f7177f Mon Sep 17 00:00:00 2001 From: Niranjana Vishwanathapura Date: Thu, 22 Sep 2022 14:39:16 -0700 Subject: drm/i915: Remove unused function parameter The function parameter 'exclude' in funciton i915_sw_fence_await_reservation() is not used. Remove it. Reviewed-by: Tvrtko Ursulin Signed-off-by: Niranjana Vishwanathapura Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20220922213916.12112-1-niranjana.vishwanathapura@intel.com --- drivers/gpu/drm/i915/display/intel_atomic_plane.c | 5 ++--- drivers/gpu/drm/i915/gem/i915_gem_clflush.c | 2 +- drivers/gpu/drm/i915/i915_sw_fence.c | 1 - drivers/gpu/drm/i915/i915_sw_fence.h | 1 - 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_atomic_plane.c b/drivers/gpu/drm/i915/display/intel_atomic_plane.c index aaa6708256d5..ecb8d71d36c0 100644 --- a/drivers/gpu/drm/i915/display/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/display/intel_atomic_plane.c @@ -1005,7 +1005,7 @@ intel_prepare_plane_fb(struct drm_plane *_plane, */ if (intel_crtc_needs_modeset(crtc_state)) { ret = i915_sw_fence_await_reservation(&state->commit_ready, - old_obj->base.resv, NULL, + old_obj->base.resv, false, 0, GFP_KERNEL); if (ret < 0) @@ -1039,8 +1039,7 @@ intel_prepare_plane_fb(struct drm_plane *_plane, struct dma_fence *fence; ret = i915_sw_fence_await_reservation(&state->commit_ready, - obj->base.resv, NULL, - false, + obj->base.resv, false, i915_fence_timeout(dev_priv), GFP_KERNEL); if (ret < 0) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_clflush.c b/drivers/gpu/drm/i915/gem/i915_gem_clflush.c index 0512afdd20d8..b3b398fe689c 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_clflush.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_clflush.c @@ -113,7 +113,7 @@ bool i915_gem_clflush_object(struct drm_i915_gem_object *obj, clflush = clflush_work_create(obj); if (clflush) { i915_sw_fence_await_reservation(&clflush->base.chain, - obj->base.resv, NULL, true, + obj->base.resv, true, i915_fence_timeout(i915), I915_FENCE_GFP); dma_resv_add_fence(obj->base.resv, &clflush->base.dma, diff --git a/drivers/gpu/drm/i915/i915_sw_fence.c b/drivers/gpu/drm/i915/i915_sw_fence.c index 6fc0d1b89690..cc2a8821d22a 100644 --- a/drivers/gpu/drm/i915/i915_sw_fence.c +++ b/drivers/gpu/drm/i915/i915_sw_fence.c @@ -571,7 +571,6 @@ int __i915_sw_fence_await_dma_fence(struct i915_sw_fence *fence, int i915_sw_fence_await_reservation(struct i915_sw_fence *fence, struct dma_resv *resv, - const struct dma_fence_ops *exclude, bool write, unsigned long timeout, gfp_t gfp) diff --git a/drivers/gpu/drm/i915/i915_sw_fence.h b/drivers/gpu/drm/i915/i915_sw_fence.h index 619fc5a22f0c..f752bfc7c6e1 100644 --- a/drivers/gpu/drm/i915/i915_sw_fence.h +++ b/drivers/gpu/drm/i915/i915_sw_fence.h @@ -91,7 +91,6 @@ int i915_sw_fence_await_dma_fence(struct i915_sw_fence *fence, int i915_sw_fence_await_reservation(struct i915_sw_fence *fence, struct dma_resv *resv, - const struct dma_fence_ops *exclude, bool write, unsigned long timeout, gfp_t gfp); -- cgit From 71690148dbcf2331a54e40da26970402bd07a527 Mon Sep 17 00:00:00 2001 From: Gustavo Sousa Date: Thu, 22 Sep 2022 13:49:49 -0300 Subject: drm/i915: Move hotplug inversion logic into separate helper Use *_hpd_invert() helpers whenever possible to isolate logic specific to hotplug inversion from common HPD setup logic to improve readability and maintainability of the source code. While we only define dg1_hpd_invert() here, future platforms are likely to have different hotplug inversion needs, thus it makes sense grouping different implementations under a common suffix. v2: Fix coding style and prefer to use small *_hdp_invert() helpers instead of a generic one. CC: Jani Nikula CC: Lucas De Marchi Signed-off-by: Gustavo Sousa Reviewed-by: Jani Nikula Signed-off-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20220922164949.163985-1-gustavo.sousa@intel.com --- drivers/gpu/drm/i915/i915_irq.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 8ffd81243a19..8c301b1682b4 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -3411,17 +3411,18 @@ static u32 gen11_hotplug_enables(struct drm_i915_private *i915, } } -static void dg1_hpd_irq_setup(struct drm_i915_private *dev_priv) +static void dg1_hpd_invert(struct drm_i915_private *i915) { - u32 val; - - val = intel_uncore_read(&dev_priv->uncore, SOUTH_CHICKEN1); - val |= (INVERT_DDIA_HPD | - INVERT_DDIB_HPD | - INVERT_DDIC_HPD | - INVERT_DDID_HPD); - intel_uncore_write(&dev_priv->uncore, SOUTH_CHICKEN1, val); + u32 val = (INVERT_DDIA_HPD | + INVERT_DDIB_HPD | + INVERT_DDIC_HPD | + INVERT_DDID_HPD); + intel_uncore_rmw(&i915->uncore, SOUTH_CHICKEN1, 0, val); +} +static void dg1_hpd_irq_setup(struct drm_i915_private *dev_priv) +{ + dg1_hpd_invert(dev_priv); icp_hpd_irq_setup(dev_priv); } -- cgit From d09aa852585aa12e8ca0aff1425c9806a6f42772 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 14 Sep 2022 19:35:14 +0300 Subject: drm/i915: move i915_coherent_map_type() to i915_gem_pages.c and un-inline The inline function has no place in i915_drv.h. Move it away, un-inline, and untangle some header dependencies while at it. Cc: Matthew Auld Cc: Tvrtko Ursulin Signed-off-by: Jani Nikula Acked-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20220914163514.1837467-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_dpt.c | 1 + drivers/gpu/drm/i915/gem/i915_gem_object.h | 4 ++++ drivers/gpu/drm/i915/gem/i915_gem_pages.c | 12 ++++++++++++ drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c | 1 + drivers/gpu/drm/i915/gt/intel_gsc.c | 1 + drivers/gpu/drm/i915/gt/intel_migrate.c | 1 + drivers/gpu/drm/i915/gt/selftest_migrate.c | 1 + drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c | 1 + drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c | 1 + drivers/gpu/drm/i915/i915_drv.h | 13 ------------- drivers/gpu/drm/i915/selftests/i915_gem_gtt.c | 1 + 11 files changed, 24 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dpt.c b/drivers/gpu/drm/i915/display/intel_dpt.c index ac587647e1f5..ad1a37b515fb 100644 --- a/drivers/gpu/drm/i915/display/intel_dpt.c +++ b/drivers/gpu/drm/i915/display/intel_dpt.c @@ -5,6 +5,7 @@ #include "gem/i915_gem_domain.h" #include "gem/i915_gem_internal.h" +#include "gem/i915_gem_lmem.h" #include "gt/gen8_ppgtt.h" #include "i915_drv.h" diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.h b/drivers/gpu/drm/i915/gem/i915_gem_object.h index 7317d4102955..a3b7551a57fc 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.h @@ -482,6 +482,10 @@ void *__must_check i915_gem_object_pin_map(struct drm_i915_gem_object *obj, void *__must_check i915_gem_object_pin_map_unlocked(struct drm_i915_gem_object *obj, enum i915_map_type type); +enum i915_map_type i915_coherent_map_type(struct drm_i915_private *i915, + struct drm_i915_gem_object *obj, + bool always_coherent); + void __i915_gem_object_flush_map(struct drm_i915_gem_object *obj, unsigned long offset, unsigned long size); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_pages.c b/drivers/gpu/drm/i915/gem/i915_gem_pages.c index 8357dbdcab5c..b8b6da951c74 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_pages.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_pages.c @@ -466,6 +466,18 @@ void *i915_gem_object_pin_map_unlocked(struct drm_i915_gem_object *obj, return ret; } +enum i915_map_type i915_coherent_map_type(struct drm_i915_private *i915, + struct drm_i915_gem_object *obj, + bool always_coherent) +{ + if (i915_gem_object_is_lmem(obj)) + return I915_MAP_WC; + if (HAS_LLC(i915) || always_coherent) + return I915_MAP_WB; + else + return I915_MAP_WC; +} + void __i915_gem_object_flush_map(struct drm_i915_gem_object *obj, unsigned long offset, unsigned long size) diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c index 55bf23dc0e54..f16164de2482 100644 --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c @@ -8,6 +8,7 @@ #include #include "gem/i915_gem_internal.h" +#include "gem/i915_gem_lmem.h" #include "gem/i915_gem_region.h" #include "gem/i915_gem_ttm.h" #include "gem/i915_gem_ttm_move.h" diff --git a/drivers/gpu/drm/i915/gt/intel_gsc.c b/drivers/gpu/drm/i915/gt/intel_gsc.c index 7af6db3194dd..d56f75b605d8 100644 --- a/drivers/gpu/drm/i915/gt/intel_gsc.c +++ b/drivers/gpu/drm/i915/gt/intel_gsc.c @@ -7,6 +7,7 @@ #include #include "i915_drv.h" #include "i915_reg.h" +#include "gem/i915_gem_lmem.h" #include "gem/i915_gem_region.h" #include "gt/intel_gsc.h" #include "gt/intel_gt.h" diff --git a/drivers/gpu/drm/i915/gt/intel_migrate.c b/drivers/gpu/drm/i915/gt/intel_migrate.c index aaaf1906026c..b405a04135ca 100644 --- a/drivers/gpu/drm/i915/gt/intel_migrate.c +++ b/drivers/gpu/drm/i915/gt/intel_migrate.c @@ -10,6 +10,7 @@ #include "intel_gtt.h" #include "intel_migrate.h" #include "intel_ring.h" +#include "gem/i915_gem_lmem.h" struct insert_pte_data { u64 offset; diff --git a/drivers/gpu/drm/i915/gt/selftest_migrate.c b/drivers/gpu/drm/i915/gt/selftest_migrate.c index 2b0c87999949..0dc5309c90a4 100644 --- a/drivers/gpu/drm/i915/gt/selftest_migrate.c +++ b/drivers/gpu/drm/i915/gt/selftest_migrate.c @@ -6,6 +6,7 @@ #include #include "gem/i915_gem_internal.h" +#include "gem/i915_gem_lmem.h" #include "selftests/i915_random.h" diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c index 74cbe8eaf531..657f0beb8e06 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c @@ -5,6 +5,7 @@ #include +#include "gem/i915_gem_lmem.h" #include "gt/intel_engine_regs.h" #include "gt/intel_gt.h" #include "gt/intel_gt_mcr.h" diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index 22ba66e48a9b..ca6f47496869 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -6,6 +6,7 @@ #include #include "gem/i915_gem_context.h" +#include "gem/i915_gem_lmem.h" #include "gt/gen8_engine_cs.h" #include "gt/intel_breadcrumbs.h" #include "gt/intel_context.h" diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b11c212f1b0d..cf6d0c102d54 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -51,7 +51,6 @@ #include "display/intel_opregion.h" #include "gem/i915_gem_context_types.h" -#include "gem/i915_gem_lmem.h" #include "gem/i915_gem_shrinker.h" #include "gem/i915_gem_stolen.h" @@ -1508,16 +1507,4 @@ mkwrite_device_info(struct drm_i915_private *dev_priv) return (struct intel_device_info *)INTEL_INFO(dev_priv); } -static inline enum i915_map_type -i915_coherent_map_type(struct drm_i915_private *i915, - struct drm_i915_gem_object *obj, bool always_coherent) -{ - if (i915_gem_object_is_lmem(obj)) - return I915_MAP_WC; - if (HAS_LLC(i915) || always_coherent) - return I915_MAP_WB; - else - return I915_MAP_WC; -} - #endif diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c index e050a2de5fd1..ea2cf1080979 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c @@ -27,6 +27,7 @@ #include "gem/i915_gem_context.h" #include "gem/i915_gem_internal.h" +#include "gem/i915_gem_lmem.h" #include "gem/i915_gem_region.h" #include "gem/selftests/mock_context.h" #include "gt/intel_context.h" -- cgit From 107ba1a2c705f4358f2602ec2f2fd821bb651f42 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 21 Sep 2022 15:52:58 +0200 Subject: drm/i915/gt: Restrict forced preemption to the active context When we submit a new pair of contexts to ELSP for execution, we start a timer by which point we expect the HW to have switched execution to the pending contexts. If the promotion to the new pair of contexts has not occurred, we declare the executing context to have hung and force the preemption to take place by resetting the engine and resubmitting the new contexts. This can lead to an unfair situation where almost all of the preemption timeout is consumed by the first context which just switches into the second context immediately prior to the timer firing and triggering the preemption reset (assuming that the timer interrupts before we process the CS events for the context switch). The second context hasn't yet had a chance to yield to the incoming ELSP (and send the ACk for the promotion) and so ends up being blamed for the reset. If we see that a context switch has occurred since setting the preemption timeout, but have not yet received the ACK for the ELSP promotion, rearm the preemption timer and check again. This is especially significant if the first context was not schedulable and so we used the shortest timer possible, greatly increasing the chance of accidentally blaming the second innocent context. Fixes: 3a7a92aba8fb ("drm/i915/execlists: Force preemption") Fixes: d12acee84ffb ("drm/i915/execlists: Cancel banned contexts on schedule-out") Reported-by: Tvrtko Ursulin Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Cc: Andi Shyti Reviewed-by: Andrzej Hajda Tested-by: Andrzej Hajda Cc: # v5.5+ Signed-off-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20220921135258.1714873-1-andrzej.hajda@intel.com --- drivers/gpu/drm/i915/gt/intel_engine_types.h | 15 +++++++++++++++ .../gpu/drm/i915/gt/intel_execlists_submission.c | 21 ++++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gt/intel_engine_types.h b/drivers/gpu/drm/i915/gt/intel_engine_types.h index 633a7e5dba3b..6b5d4ea22b67 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_types.h +++ b/drivers/gpu/drm/i915/gt/intel_engine_types.h @@ -165,6 +165,21 @@ struct intel_engine_execlists { */ struct timer_list preempt; + /** + * @preempt_target: active request at the time of the preemption request + * + * We force a preemption to occur if the pending contexts have not + * been promoted to active upon receipt of the CS ack event within + * the timeout. This timeout maybe chosen based on the target, + * using a very short timeout if the context is no longer schedulable. + * That short timeout may not be applicable to other contexts, so + * if a context switch should happen within before the preemption + * timeout, we may shoot early at an innocent context. To prevent this, + * we record which context was active at the time of the preemption + * request and only reset that context upon the timeout. + */ + const struct i915_request *preempt_target; + /** * @ccid: identifier for contexts submitted to this engine */ diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c index aab240ea1d25..428da98c5356 100644 --- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c +++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c @@ -1241,6 +1241,9 @@ static unsigned long active_preempt_timeout(struct intel_engine_cs *engine, if (!rq) return 0; + /* Only allow ourselves to force reset the currently active context */ + engine->execlists.preempt_target = rq; + /* Force a fast reset for terminated contexts (ignoring sysfs!) */ if (unlikely(intel_context_is_banned(rq->context) || bad_request(rq))) return INTEL_CONTEXT_BANNED_PREEMPT_TIMEOUT_MS; @@ -2427,8 +2430,24 @@ static void execlists_submission_tasklet(struct tasklet_struct *t) GEM_BUG_ON(inactive - post > ARRAY_SIZE(post)); if (unlikely(preempt_timeout(engine))) { + const struct i915_request *rq = *engine->execlists.active; + + /* + * If after the preempt-timeout expired, we are still on the + * same active request/context as before we initiated the + * preemption, reset the engine. + * + * However, if we have processed a CS event to switch contexts, + * but not yet processed the CS event for the pending + * preemption, reset the timer allowing the new context to + * gracefully exit. + */ cancel_timer(&engine->execlists.preempt); - engine->execlists.error_interrupt |= ERROR_PREEMPT; + if (rq == engine->execlists.preempt_target) + engine->execlists.error_interrupt |= ERROR_PREEMPT; + else + set_timer_ms(&engine->execlists.preempt, + active_preempt_timeout(engine, rq)); } if (unlikely(READ_ONCE(engine->execlists.error_interrupt))) { -- cgit From 60c0df33da03c5aebcc5fb46363a1b58c784570e Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 12 Sep 2022 14:18:00 +0300 Subject: drm/i915: Drop pointless middle man variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No need for the 'procmon' variable here. Just return the correct thing from the switch statement directly. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220912111814.17466-2-ville.syrjala@linux.intel.com Reviewed-by: Luca Coelho Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_combo_phy.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_combo_phy.c b/drivers/gpu/drm/i915/display/intel_combo_phy.c index 64890f39c3cc..71d7aece1dc6 100644 --- a/drivers/gpu/drm/i915/display/intel_combo_phy.c +++ b/drivers/gpu/drm/i915/display/intel_combo_phy.c @@ -53,7 +53,6 @@ static const struct icl_procmon { static const struct icl_procmon * icl_get_procmon_ref_values(struct drm_i915_private *dev_priv, enum phy phy) { - const struct icl_procmon *procmon; u32 val; val = intel_de_read(dev_priv, ICL_PORT_COMP_DW3(phy)); @@ -62,23 +61,16 @@ icl_get_procmon_ref_values(struct drm_i915_private *dev_priv, enum phy phy) MISSING_CASE(val); fallthrough; case VOLTAGE_INFO_0_85V | PROCESS_INFO_DOT_0: - procmon = &icl_procmon_values[PROCMON_0_85V_DOT_0]; - break; + return &icl_procmon_values[PROCMON_0_85V_DOT_0]; case VOLTAGE_INFO_0_95V | PROCESS_INFO_DOT_0: - procmon = &icl_procmon_values[PROCMON_0_95V_DOT_0]; - break; + return &icl_procmon_values[PROCMON_0_95V_DOT_0]; case VOLTAGE_INFO_0_95V | PROCESS_INFO_DOT_1: - procmon = &icl_procmon_values[PROCMON_0_95V_DOT_1]; - break; + return &icl_procmon_values[PROCMON_0_95V_DOT_1]; case VOLTAGE_INFO_1_05V | PROCESS_INFO_DOT_0: - procmon = &icl_procmon_values[PROCMON_1_05V_DOT_0]; - break; + return &icl_procmon_values[PROCMON_1_05V_DOT_0]; case VOLTAGE_INFO_1_05V | PROCESS_INFO_DOT_1: - procmon = &icl_procmon_values[PROCMON_1_05V_DOT_1]; - break; + return &icl_procmon_values[PROCMON_1_05V_DOT_1]; } - - return procmon; } static void icl_set_procmon_ref_values(struct drm_i915_private *dev_priv, -- cgit From 6a08cbda458e824ac824dddc6a07ed50efd0af70 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 12 Sep 2022 14:18:01 +0300 Subject: drm/i915: Clean up transcoder_to_stream_enc_status() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop the pointless middle man variable and just return the correct thing directly. And while at it change the return type to u32 since this is a register value we're returning. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220912111814.17466-3-ville.syrjala@linux.intel.com Reviewed-by: Luca Coelho Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_dp_hdcp.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp_hdcp.c b/drivers/gpu/drm/i915/display/intel_dp_hdcp.c index 88689124c013..35360dd543ac 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_hdcp.c +++ b/drivers/gpu/drm/i915/display/intel_dp_hdcp.c @@ -19,28 +19,20 @@ #include "intel_hdcp.h" #include "intel_hdcp_regs.h" -static unsigned int transcoder_to_stream_enc_status(enum transcoder cpu_transcoder) +static u32 transcoder_to_stream_enc_status(enum transcoder cpu_transcoder) { - u32 stream_enc_mask; - switch (cpu_transcoder) { case TRANSCODER_A: - stream_enc_mask = HDCP_STATUS_STREAM_A_ENC; - break; + return HDCP_STATUS_STREAM_A_ENC; case TRANSCODER_B: - stream_enc_mask = HDCP_STATUS_STREAM_B_ENC; - break; + return HDCP_STATUS_STREAM_B_ENC; case TRANSCODER_C: - stream_enc_mask = HDCP_STATUS_STREAM_C_ENC; - break; + return HDCP_STATUS_STREAM_C_ENC; case TRANSCODER_D: - stream_enc_mask = HDCP_STATUS_STREAM_D_ENC; - break; + return HDCP_STATUS_STREAM_D_ENC; default: - stream_enc_mask = 0; + return 0; } - - return stream_enc_mask; } static void intel_dp_hdcp_wait_for_cp_irq(struct intel_hdcp *hdcp, int timeout) -- cgit From 10c8cbeebd81d2e01437d59a4e47dc3de5925113 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 12 Sep 2022 14:18:02 +0300 Subject: drm/i915: Drop pointless 'budget' variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just return the thing directly from the switch statement. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220912111814.17466-4-ville.syrjala@linux.intel.com Reviewed-by: Luca Coelho Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_dpll_mgr.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c index e5fb66a5dd02..60b3277a857b 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c @@ -708,8 +708,6 @@ struct hsw_wrpll_rnp { static unsigned hsw_wrpll_get_budget_for_freq(int clock) { - unsigned budget; - switch (clock) { case 25175000: case 25200000: @@ -742,21 +740,18 @@ static unsigned hsw_wrpll_get_budget_for_freq(int clock) case 222750000: case 296703000: case 297000000: - budget = 0; - break; + return 0; case 233500000: case 245250000: case 247750000: case 253250000: case 298000000: - budget = 1500; - break; + return 1500; case 169128000: case 169500000: case 179500000: case 202000000: - budget = 2000; - break; + return 2000; case 256250000: case 262500000: case 270000000: @@ -766,18 +761,13 @@ static unsigned hsw_wrpll_get_budget_for_freq(int clock) case 281250000: case 286000000: case 291750000: - budget = 4000; - break; + return 4000; case 267250000: case 268500000: - budget = 5000; - break; + return 5000; default: - budget = 1000; - break; + return 1000; } - - return budget; } static void hsw_wrpll_update_rnp(u64 freq2k, unsigned int budget, -- cgit From 49fd54034a523a9241cd73cda6da485112bf4414 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 12 Sep 2022 14:18:03 +0300 Subject: drm/i915: Use BIT() when dealing with output types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most places that deal with output types already use BIT() but a few places still use manual shifts. Convert the stragglers over to BIT(). Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220912111814.17466-5-ville.syrjala@linux.intel.com Reviewed-by: Luca Coelho Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/g4x_hdmi.c | 4 ++-- drivers/gpu/drm/i915/display/intel_crt.c | 2 +- drivers/gpu/drm/i915/display/intel_display.c | 4 ++-- drivers/gpu/drm/i915/display/intel_display_types.h | 9 +++++---- drivers/gpu/drm/i915/display/intel_dvo.c | 4 ++-- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/display/g4x_hdmi.c b/drivers/gpu/drm/i915/display/g4x_hdmi.c index 5fbd2ae95869..5606c667e422 100644 --- a/drivers/gpu/drm/i915/display/g4x_hdmi.c +++ b/drivers/gpu/drm/i915/display/g4x_hdmi.c @@ -585,7 +585,7 @@ void g4x_hdmi_init(struct drm_i915_private *dev_priv, } else { intel_encoder->pipe_mask = ~0; } - intel_encoder->cloneable = 1 << INTEL_OUTPUT_ANALOG; + intel_encoder->cloneable = BIT(INTEL_OUTPUT_ANALOG); intel_encoder->hpd_pin = intel_hpd_pin_default(dev_priv, port); /* * BSpec is unclear about HDMI+HDMI cloning on g4x, but it seems @@ -593,7 +593,7 @@ void g4x_hdmi_init(struct drm_i915_private *dev_priv, * only one port anyway, nothing is lost by allowing it. */ if (IS_G4X(dev_priv)) - intel_encoder->cloneable |= 1 << INTEL_OUTPUT_HDMI; + intel_encoder->cloneable |= BIT(INTEL_OUTPUT_HDMI); dig_port->hdmi.hdmi_reg = hdmi_reg; dig_port->dp.output_reg = INVALID_MMIO_REG; diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c index 4a8ff2f97608..eba58345619a 100644 --- a/drivers/gpu/drm/i915/display/intel_crt.c +++ b/drivers/gpu/drm/i915/display/intel_crt.c @@ -1044,7 +1044,7 @@ void intel_crt_init(struct drm_i915_private *dev_priv) intel_connector_attach_encoder(intel_connector, &crt->base); crt->base.type = INTEL_OUTPUT_ANALOG; - crt->base.cloneable = (1 << INTEL_OUTPUT_DVO) | (1 << INTEL_OUTPUT_HDMI); + crt->base.cloneable = BIT(INTEL_OUTPUT_DVO) | BIT(INTEL_OUTPUT_HDMI); if (IS_I830(dev_priv)) crt->base.pipe_mask = BIT(PIPE_A); else diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index de3b4fb5d0a5..3f72d0cd6d1e 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -4572,8 +4572,8 @@ static bool encoders_cloneable(const struct intel_encoder *a, const struct intel_encoder *b) { /* masks could be asymmetric, so check both ways */ - return a == b || (a->cloneable & (1 << b->type) && - b->cloneable & (1 << a->type)); + return a == b || (a->cloneable & BIT(b->type) && + b->cloneable & BIT(a->type)); } static bool check_single_encoder_cloning(struct intel_atomic_state *state, diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 0d502003228b..c09cb8b89ad7 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -2040,15 +2040,16 @@ static inline bool intel_crtc_has_type(const struct intel_crtc_state *crtc_state, enum intel_output_type type) { - return crtc_state->output_types & (1 << type); + return crtc_state->output_types & BIT(type); } + static inline bool intel_crtc_has_dp_encoder(const struct intel_crtc_state *crtc_state) { return crtc_state->output_types & - ((1 << INTEL_OUTPUT_DP) | - (1 << INTEL_OUTPUT_DP_MST) | - (1 << INTEL_OUTPUT_EDP)); + (BIT(INTEL_OUTPUT_DP) | + BIT(INTEL_OUTPUT_DP_MST) | + BIT(INTEL_OUTPUT_EDP)); } static inline bool diff --git a/drivers/gpu/drm/i915/display/intel_dvo.c b/drivers/gpu/drm/i915/display/intel_dvo.c index 5572e43026e4..167c9b7318f8 100644 --- a/drivers/gpu/drm/i915/display/intel_dvo.c +++ b/drivers/gpu/drm/i915/display/intel_dvo.c @@ -491,8 +491,8 @@ void intel_dvo_init(struct drm_i915_private *dev_priv) intel_encoder->pipe_mask = ~0; if (dvo->type != INTEL_DVO_CHIP_LVDS) - intel_encoder->cloneable = (1 << INTEL_OUTPUT_ANALOG) | - (1 << INTEL_OUTPUT_DVO); + intel_encoder->cloneable = BIT(INTEL_OUTPUT_ANALOG) | + BIT(INTEL_OUTPUT_DVO); switch (dvo->type) { case INTEL_DVO_CHIP_TMDS: -- cgit From 5e800d92313497a5a9fc7053890e870888181192 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 12 Sep 2022 14:18:04 +0300 Subject: drm/i915: Pass intel_encoder to to_lvds_encoder() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most of our encoder type cast stuff already operates on intel_encoder rather than drm_encoder. Switch to_lvds_encoder() over as well. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220912111814.17466-6-ville.syrjala@linux.intel.com Reviewed-by: Luca Coelho Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_lvds.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c index 9aa38e8141b5..6fef829e855b 100644 --- a/drivers/gpu/drm/i915/display/intel_lvds.c +++ b/drivers/gpu/drm/i915/display/intel_lvds.c @@ -78,9 +78,9 @@ struct intel_lvds_encoder { struct intel_connector *attached_connector; }; -static struct intel_lvds_encoder *to_lvds_encoder(struct drm_encoder *encoder) +static struct intel_lvds_encoder *to_lvds_encoder(struct intel_encoder *encoder) { - return container_of(encoder, struct intel_lvds_encoder, base.base); + return container_of(encoder, struct intel_lvds_encoder, base); } bool intel_lvds_port_enabled(struct drm_i915_private *dev_priv, @@ -103,7 +103,7 @@ static bool intel_lvds_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base); + struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(encoder); intel_wakeref_t wakeref; bool ret; @@ -123,7 +123,7 @@ static void intel_lvds_get_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base); + struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(encoder); u32 tmp, flags = 0; pipe_config->output_types |= BIT(INTEL_OUTPUT_LVDS); @@ -229,7 +229,7 @@ static void intel_pre_enable_lvds(struct intel_atomic_state *state, const struct intel_crtc_state *pipe_config, const struct drm_connector_state *conn_state) { - struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base); + struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(encoder); struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc); const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; @@ -312,7 +312,7 @@ static void intel_enable_lvds(struct intel_atomic_state *state, const struct drm_connector_state *conn_state) { struct drm_device *dev = encoder->base.dev; - struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base); + struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(encoder); struct drm_i915_private *dev_priv = to_i915(dev); intel_de_write(dev_priv, lvds_encoder->reg, @@ -334,7 +334,7 @@ static void intel_disable_lvds(struct intel_atomic_state *state, const struct intel_crtc_state *old_crtc_state, const struct drm_connector_state *old_conn_state) { - struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base); + struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(encoder); struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); intel_de_write(dev_priv, PP_CONTROL(0), @@ -413,7 +413,7 @@ static int intel_lvds_compute_config(struct intel_encoder *intel_encoder, { struct drm_i915_private *dev_priv = to_i915(intel_encoder->base.dev); struct intel_lvds_encoder *lvds_encoder = - to_lvds_encoder(&intel_encoder->base); + to_lvds_encoder(intel_encoder); struct intel_connector *intel_connector = lvds_encoder->attached_connector; struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; @@ -775,7 +775,7 @@ bool intel_is_dual_link_lvds(struct drm_i915_private *dev_priv) { struct intel_encoder *encoder = intel_get_lvds_encoder(dev_priv); - return encoder && to_lvds_encoder(&encoder->base)->is_dual_link; + return encoder && to_lvds_encoder(encoder)->is_dual_link; } static bool compute_is_dual_link_lvds(struct intel_lvds_encoder *lvds_encoder) -- cgit From 6f7dd8e7d9f6039aa5c286726a941cf5344a784d Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 12 Sep 2022 14:18:05 +0300 Subject: drm/i915: Extract intel_edp_backlight_setup() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pull the eDP backlight setup into its own function. No reason to pollute intel_edp_init_connector() with all the mundane details. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220912111814.17466-7-ville.syrjala@linux.intel.com Reviewed-by: Luca Coelho Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_dp.c | 51 +++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index c9be61d2348e..d24a336de81f 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -5206,6 +5206,35 @@ intel_edp_add_properties(struct intel_dp *intel_dp) fixed_mode->vdisplay); } +static void intel_edp_backlight_setup(struct intel_dp *intel_dp, + struct intel_connector *connector) +{ + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + enum pipe pipe = INVALID_PIPE; + + if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) { + /* + * Figure out the current pipe for the initial backlight setup. + * If the current pipe isn't valid, try the PPS pipe, and if that + * fails just assume pipe A. + */ + pipe = vlv_active_pipe(intel_dp); + + if (pipe != PIPE_A && pipe != PIPE_B) + pipe = intel_dp->pps.pps_pipe; + + if (pipe != PIPE_A && pipe != PIPE_B) + pipe = PIPE_A; + + drm_dbg_kms(&i915->drm, + "[CONNECTOR:%d:%s] using pipe %c for initial backlight setup\n", + connector->base.base.id, connector->base.name, + pipe_name(pipe)); + } + + intel_backlight_setup(connector, pipe); +} + static bool intel_edp_init_connector(struct intel_dp *intel_dp, struct intel_connector *intel_connector) { @@ -5215,7 +5244,6 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, struct drm_display_mode *fixed_mode; struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; bool has_dpcd; - enum pipe pipe = INVALID_PIPE; struct edid *edid; if (!intel_dp_is_edp(intel_dp)) @@ -5290,28 +5318,9 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, mutex_unlock(&dev->mode_config.mutex); - if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { - /* - * Figure out the current pipe for the initial backlight setup. - * If the current pipe isn't valid, try the PPS pipe, and if that - * fails just assume pipe A. - */ - pipe = vlv_active_pipe(intel_dp); - - if (pipe != PIPE_A && pipe != PIPE_B) - pipe = intel_dp->pps.pps_pipe; - - if (pipe != PIPE_A && pipe != PIPE_B) - pipe = PIPE_A; - - drm_dbg_kms(&dev_priv->drm, - "using pipe %c for initial backlight setup\n", - pipe_name(pipe)); - } - intel_panel_init(intel_connector); - intel_backlight_setup(intel_connector, pipe); + intel_edp_backlight_setup(intel_dp, intel_connector); intel_edp_add_properties(intel_dp); -- cgit From d7e4a2574520950613d29370ddd41c54a041589a Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 12 Sep 2022 14:18:06 +0300 Subject: drm/i915: Extract intel_tv_add_properties() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pull all the TV connector property setup into its own neat function. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220912111814.17466-8-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_tv.c | 80 ++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 37 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_tv.c b/drivers/gpu/drm/i915/display/intel_tv.c index dcf89d701f0f..2b985bfc7fc2 100644 --- a/drivers/gpu/drm/i915/display/intel_tv.c +++ b/drivers/gpu/drm/i915/display/intel_tv.c @@ -1880,6 +1880,48 @@ static const struct drm_encoder_funcs intel_tv_enc_funcs = { .destroy = intel_encoder_destroy, }; +static void intel_tv_add_properties(struct drm_connector *connector) +{ + struct drm_i915_private *i915 = to_i915(connector->dev); + struct drm_connector_state *conn_state = connector->state; + const char *tv_format_names[ARRAY_SIZE(tv_modes)]; + int i; + + /* BIOS margin values */ + conn_state->tv.margins.left = 54; + conn_state->tv.margins.top = 36; + conn_state->tv.margins.right = 46; + conn_state->tv.margins.bottom = 37; + + conn_state->tv.mode = 0; + + /* Create TV properties then attach current values */ + for (i = 0; i < ARRAY_SIZE(tv_modes); i++) { + /* 1080p50/1080p60 not supported on gen3 */ + if (DISPLAY_VER(i915) == 3 && tv_modes[i].oversample == 1) + break; + + tv_format_names[i] = tv_modes[i].name; + } + drm_mode_create_tv_properties(&i915->drm, i, tv_format_names); + + drm_object_attach_property(&connector->base, + i915->drm.mode_config.tv_mode_property, + conn_state->tv.mode); + drm_object_attach_property(&connector->base, + i915->drm.mode_config.tv_left_margin_property, + conn_state->tv.margins.left); + drm_object_attach_property(&connector->base, + i915->drm.mode_config.tv_top_margin_property, + conn_state->tv.margins.top); + drm_object_attach_property(&connector->base, + i915->drm.mode_config.tv_right_margin_property, + conn_state->tv.margins.right); + drm_object_attach_property(&connector->base, + i915->drm.mode_config.tv_bottom_margin_property, + conn_state->tv.margins.bottom); +} + void intel_tv_init(struct drm_i915_private *dev_priv) { @@ -1889,9 +1931,6 @@ intel_tv_init(struct drm_i915_private *dev_priv) struct intel_encoder *intel_encoder; struct intel_connector *intel_connector; u32 tv_dac_on, tv_dac_off, save_tv_dac; - const char *tv_format_names[ARRAY_SIZE(tv_modes)]; - int i, initial_mode = 0; - struct drm_connector_state *state; if ((intel_de_read(dev_priv, TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED) return; @@ -1937,7 +1976,6 @@ intel_tv_init(struct drm_i915_private *dev_priv) intel_encoder = &intel_tv->base; connector = &intel_connector->base; - state = connector->state; /* * The documentation, for the older chipsets at least, recommend @@ -1974,41 +2012,9 @@ intel_tv_init(struct drm_i915_private *dev_priv) intel_encoder->cloneable = 0; intel_tv->type = DRM_MODE_CONNECTOR_Unknown; - /* BIOS margin values */ - state->tv.margins.left = 54; - state->tv.margins.top = 36; - state->tv.margins.right = 46; - state->tv.margins.bottom = 37; - - state->tv.mode = initial_mode; - drm_connector_helper_add(connector, &intel_tv_connector_helper_funcs); connector->interlace_allowed = false; connector->doublescan_allowed = false; - /* Create TV properties then attach current values */ - for (i = 0; i < ARRAY_SIZE(tv_modes); i++) { - /* 1080p50/1080p60 not supported on gen3 */ - if (DISPLAY_VER(dev_priv) == 3 && - tv_modes[i].oversample == 1) - break; - - tv_format_names[i] = tv_modes[i].name; - } - drm_mode_create_tv_properties(dev, i, tv_format_names); - - drm_object_attach_property(&connector->base, dev->mode_config.tv_mode_property, - state->tv.mode); - drm_object_attach_property(&connector->base, - dev->mode_config.tv_left_margin_property, - state->tv.margins.left); - drm_object_attach_property(&connector->base, - dev->mode_config.tv_top_margin_property, - state->tv.margins.top); - drm_object_attach_property(&connector->base, - dev->mode_config.tv_right_margin_property, - state->tv.margins.right); - drm_object_attach_property(&connector->base, - dev->mode_config.tv_bottom_margin_property, - state->tv.margins.bottom); + intel_tv_add_properties(connector); } -- cgit From 9c7183a326521769bbddf155ea8f16aa9473de0c Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 12 Sep 2022 14:18:07 +0300 Subject: drm/i915: Extract intel_dp_mst_add_properties() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the DP MST connector property setup into its own function so it's not spread all over intel_dp_add_mst_connector(). Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220912111814.17466-9-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_dp_mst.c | 46 +++++++++++++++++++---------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 03604a37931c..cd4e61026d98 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -793,7 +793,35 @@ static bool intel_dp_mst_get_hw_state(struct intel_connector *connector) return false; } -static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, const char *pathprop) +static int intel_dp_mst_add_properties(struct intel_dp *intel_dp, + struct drm_connector *connector, + const char *pathprop) +{ + struct drm_i915_private *i915 = to_i915(connector->dev); + + drm_object_attach_property(&connector->base, + i915->drm.mode_config.path_property, 0); + drm_object_attach_property(&connector->base, + i915->drm.mode_config.tile_property, 0); + + intel_attach_force_audio_property(connector); + intel_attach_broadcast_rgb_property(connector); + + /* + * Reuse the prop from the SST connector because we're + * not allowed to create new props after device registration. + */ + connector->max_bpc_property = + intel_dp->attached_connector->base.max_bpc_property; + if (connector->max_bpc_property) + drm_connector_attach_max_bpc_property(connector, 6, 12); + + return drm_connector_set_path_property(connector, pathprop); +} + +static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port, + const char *pathprop) { struct intel_dp *intel_dp = container_of(mgr, struct intel_dp, mst_mgr); struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); @@ -833,28 +861,14 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo goto err; } - drm_object_attach_property(&connector->base, dev->mode_config.path_property, 0); - drm_object_attach_property(&connector->base, dev->mode_config.tile_property, 0); - - ret = drm_connector_set_path_property(connector, pathprop); + ret = intel_dp_mst_add_properties(intel_dp, connector, pathprop); if (ret) goto err; - intel_attach_force_audio_property(connector); - intel_attach_broadcast_rgb_property(connector); - ret = intel_dp_hdcp_init(dig_port, intel_connector); if (ret) drm_dbg_kms(&dev_priv->drm, "[%s:%d] HDCP MST init failed, skipping.\n", connector->name, connector->base.id); - /* - * Reuse the prop from the SST connector because we're - * not allowed to create new props after device registration. - */ - connector->max_bpc_property = - intel_dp->attached_connector->base.max_bpc_property; - if (connector->max_bpc_property) - drm_connector_attach_max_bpc_property(connector, 6, 12); return connector; -- cgit From 2f0f603a377237c9359d96184e2a6d8ae8299c9f Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 12 Sep 2022 14:18:08 +0300 Subject: drm/i915: Extract intel_lvds_add_properties() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the LVDS connector property setup to a dedicated function to depollute intel_lvds_init() a bit. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220912111814.17466-10-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_lvds.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c index 6fef829e855b..7cadb548ad6c 100644 --- a/drivers/gpu/drm/i915/display/intel_lvds.c +++ b/drivers/gpu/drm/i915/display/intel_lvds.c @@ -814,6 +814,19 @@ static bool compute_is_dual_link_lvds(struct intel_lvds_encoder *lvds_encoder) return (val & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP; } +static void intel_lvds_add_properties(struct drm_connector *connector) +{ + u32 allowed_scalers; + + allowed_scalers = BIT(DRM_MODE_SCALE_ASPECT) | + BIT(DRM_MODE_SCALE_FULLSCREEN) | + BIT(DRM_MODE_SCALE_CENTER); + + drm_connector_attach_scaling_mode_property(connector, allowed_scalers); + + connector->state->scaling_mode = DRM_MODE_SCALE_ASPECT; +} + /** * intel_lvds_init - setup LVDS connectors on this device * @dev_priv: i915 device @@ -833,7 +846,6 @@ void intel_lvds_init(struct drm_i915_private *dev_priv) i915_reg_t lvds_reg; u32 lvds; u8 pin; - u32 allowed_scalers; /* Skip init on machines we know falsely report LVDS */ if (dmi_check_system(intel_no_lvds)) { @@ -925,12 +937,7 @@ void intel_lvds_init(struct drm_i915_private *dev_priv) lvds_encoder->reg = lvds_reg; - /* create the scaling mode property */ - allowed_scalers = BIT(DRM_MODE_SCALE_ASPECT); - allowed_scalers |= BIT(DRM_MODE_SCALE_FULLSCREEN); - allowed_scalers |= BIT(DRM_MODE_SCALE_CENTER); - drm_connector_attach_scaling_mode_property(connector, allowed_scalers); - connector->state->scaling_mode = DRM_MODE_SCALE_ASPECT; + intel_lvds_add_properties(connector); intel_lvds_pps_get_hw_state(dev_priv, &lvds_encoder->init_pps); lvds_encoder->init_lvds_val = lvds; -- cgit From ab6214f3c3dbabdb4409e84fe7c1c43cb79c6c56 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 12 Sep 2022 14:18:09 +0300 Subject: drm/i915: Move eDP scaling_mode prop setup to the proper place MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have an eDP specific intel_edp_add_properties() so move the eDP scaling_mode property setup there from intel_dp_add_properties(). Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220912111814.17466-11-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_dp.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index d24a336de81f..2de7773b30ee 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -5172,19 +5172,6 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect if (has_gamut_metadata_dip(dev_priv, port)) drm_connector_attach_hdr_output_metadata_property(connector); - if (intel_dp_is_edp(intel_dp)) { - u32 allowed_scalers; - - allowed_scalers = BIT(DRM_MODE_SCALE_ASPECT) | BIT(DRM_MODE_SCALE_FULLSCREEN); - if (!HAS_GMCH(dev_priv)) - allowed_scalers |= BIT(DRM_MODE_SCALE_CENTER); - - drm_connector_attach_scaling_mode_property(connector, allowed_scalers); - - connector->state->scaling_mode = DRM_MODE_SCALE_ASPECT; - - } - if (HAS_VRR(dev_priv)) drm_connector_attach_vrr_capable_property(connector); } @@ -5196,6 +5183,16 @@ intel_edp_add_properties(struct intel_dp *intel_dp) struct drm_i915_private *i915 = to_i915(connector->base.dev); const struct drm_display_mode *fixed_mode = intel_panel_preferred_fixed_mode(connector); + u32 allowed_scalers; + + allowed_scalers = BIT(DRM_MODE_SCALE_ASPECT) | + BIT(DRM_MODE_SCALE_FULLSCREEN); + if (!HAS_GMCH(i915)) + allowed_scalers |= BIT(DRM_MODE_SCALE_CENTER); + + drm_connector_attach_scaling_mode_property(&connector->base, allowed_scalers); + + connector->base.state->scaling_mode = DRM_MODE_SCALE_ASPECT; if (!fixed_mode) return; -- cgit From 6ac2f04ba1c4a81ff1e205625eaeae1ead152720 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 12 Sep 2022 14:18:10 +0300 Subject: drm/i915: Extract intel_attach_scaling_mode_property() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consolidate the scaling_mode property setup into a single place. The one slight complicateion here is that GMCH platforms can't do the CENTER mode except on the LVDS port. But we can deal with that by just checking the connector type. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220912111814.17466-12-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/icl_dsi.c | 10 +--------- drivers/gpu/drm/i915/display/intel_connector.c | 18 ++++++++++++++++++ drivers/gpu/drm/i915/display/intel_connector.h | 1 + drivers/gpu/drm/i915/display/intel_dp.c | 10 +--------- drivers/gpu/drm/i915/display/intel_lvds.c | 10 +--------- drivers/gpu/drm/i915/display/vlv_dsi.c | 11 +---------- 6 files changed, 23 insertions(+), 37 deletions(-) diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c index ed4d93942dbd..59546cbcaeda 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi.c +++ b/drivers/gpu/drm/i915/display/icl_dsi.c @@ -1974,16 +1974,8 @@ static void icl_dsi_add_properties(struct intel_connector *connector) { const struct drm_display_mode *fixed_mode = intel_panel_preferred_fixed_mode(connector); - u32 allowed_scalers; - allowed_scalers = BIT(DRM_MODE_SCALE_ASPECT) | - BIT(DRM_MODE_SCALE_FULLSCREEN) | - BIT(DRM_MODE_SCALE_CENTER); - - drm_connector_attach_scaling_mode_property(&connector->base, - allowed_scalers); - - connector->base.state->scaling_mode = DRM_MODE_SCALE_ASPECT; + intel_attach_scaling_mode_property(&connector->base); drm_connector_set_panel_orientation_with_quirk(&connector->base, intel_dsi_get_panel_orientation(connector), diff --git a/drivers/gpu/drm/i915/display/intel_connector.c b/drivers/gpu/drm/i915/display/intel_connector.c index 6d5cbeb8df4d..6205ddd3ded0 100644 --- a/drivers/gpu/drm/i915/display/intel_connector.c +++ b/drivers/gpu/drm/i915/display/intel_connector.c @@ -293,3 +293,21 @@ intel_attach_dp_colorspace_property(struct drm_connector *connector) if (!drm_mode_create_dp_colorspace_property(connector)) drm_connector_attach_colorspace_property(connector); } + +void +intel_attach_scaling_mode_property(struct drm_connector *connector) +{ + struct drm_i915_private *i915 = to_i915(connector->dev); + u32 scaling_modes; + + scaling_modes = BIT(DRM_MODE_SCALE_ASPECT) | + BIT(DRM_MODE_SCALE_FULLSCREEN); + + /* On GMCH platforms borders are only possible on the LVDS port */ + if (!HAS_GMCH(i915) || connector->connector_type == DRM_MODE_CONNECTOR_LVDS) + scaling_modes |= BIT(DRM_MODE_SCALE_CENTER); + + drm_connector_attach_scaling_mode_property(connector, scaling_modes); + + connector->state->scaling_mode = DRM_MODE_SCALE_ASPECT; +} diff --git a/drivers/gpu/drm/i915/display/intel_connector.h b/drivers/gpu/drm/i915/display/intel_connector.h index 661a37a3c6d8..7d7b588d2286 100644 --- a/drivers/gpu/drm/i915/display/intel_connector.h +++ b/drivers/gpu/drm/i915/display/intel_connector.h @@ -32,5 +32,6 @@ void intel_attach_broadcast_rgb_property(struct drm_connector *connector); void intel_attach_aspect_ratio_property(struct drm_connector *connector); void intel_attach_hdmi_colorspace_property(struct drm_connector *connector); void intel_attach_dp_colorspace_property(struct drm_connector *connector); +void intel_attach_scaling_mode_property(struct drm_connector *connector); #endif /* __INTEL_CONNECTOR_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 2de7773b30ee..0d195f8b190a 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -5183,16 +5183,8 @@ intel_edp_add_properties(struct intel_dp *intel_dp) struct drm_i915_private *i915 = to_i915(connector->base.dev); const struct drm_display_mode *fixed_mode = intel_panel_preferred_fixed_mode(connector); - u32 allowed_scalers; - allowed_scalers = BIT(DRM_MODE_SCALE_ASPECT) | - BIT(DRM_MODE_SCALE_FULLSCREEN); - if (!HAS_GMCH(i915)) - allowed_scalers |= BIT(DRM_MODE_SCALE_CENTER); - - drm_connector_attach_scaling_mode_property(&connector->base, allowed_scalers); - - connector->base.state->scaling_mode = DRM_MODE_SCALE_ASPECT; + intel_attach_scaling_mode_property(&connector->base); if (!fixed_mode) return; diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c index 7cadb548ad6c..951170af7bb3 100644 --- a/drivers/gpu/drm/i915/display/intel_lvds.c +++ b/drivers/gpu/drm/i915/display/intel_lvds.c @@ -816,15 +816,7 @@ static bool compute_is_dual_link_lvds(struct intel_lvds_encoder *lvds_encoder) static void intel_lvds_add_properties(struct drm_connector *connector) { - u32 allowed_scalers; - - allowed_scalers = BIT(DRM_MODE_SCALE_ASPECT) | - BIT(DRM_MODE_SCALE_FULLSCREEN) | - BIT(DRM_MODE_SCALE_CENTER); - - drm_connector_attach_scaling_mode_property(connector, allowed_scalers); - - connector->state->scaling_mode = DRM_MODE_SCALE_ASPECT; + intel_attach_scaling_mode_property(connector); } /** diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c index b3f5ca280ef2..421ad02f8e9b 100644 --- a/drivers/gpu/drm/i915/display/vlv_dsi.c +++ b/drivers/gpu/drm/i915/display/vlv_dsi.c @@ -1659,19 +1659,10 @@ static const struct drm_connector_funcs intel_dsi_connector_funcs = { static void vlv_dsi_add_properties(struct intel_connector *connector) { - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); const struct drm_display_mode *fixed_mode = intel_panel_preferred_fixed_mode(connector); - u32 allowed_scalers; - allowed_scalers = BIT(DRM_MODE_SCALE_ASPECT) | BIT(DRM_MODE_SCALE_FULLSCREEN); - if (!HAS_GMCH(dev_priv)) - allowed_scalers |= BIT(DRM_MODE_SCALE_CENTER); - - drm_connector_attach_scaling_mode_property(&connector->base, - allowed_scalers); - - connector->base.state->scaling_mode = DRM_MODE_SCALE_ASPECT; + intel_attach_scaling_mode_property(&connector->base); drm_connector_set_panel_orientation_with_quirk(&connector->base, intel_dsi_get_panel_orientation(connector), -- cgit From 8648c6048d4dc4d9294b7e7617c220bf446be0e7 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 12 Sep 2022 14:18:11 +0300 Subject: drm/i915: Clean up connector->*_allowed setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All the connectors are zero initialized so no need to clear the *_allowed flags we don't support. Only leave the ones we want to set. And while at it switch to booleans instead of ints. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220912111814.17466-13-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/icl_dsi.c | 2 -- drivers/gpu/drm/i915/display/intel_crt.c | 7 ++----- drivers/gpu/drm/i915/display/intel_dp.c | 1 - drivers/gpu/drm/i915/display/intel_dvo.c | 2 -- drivers/gpu/drm/i915/display/intel_hdmi.c | 5 ++--- drivers/gpu/drm/i915/display/intel_lvds.c | 2 -- drivers/gpu/drm/i915/display/intel_sdvo.c | 3 +-- drivers/gpu/drm/i915/display/intel_tv.c | 2 -- drivers/gpu/drm/i915/display/vlv_dsi.c | 2 -- 9 files changed, 5 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c index 59546cbcaeda..47f13750f6fa 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi.c +++ b/drivers/gpu/drm/i915/display/icl_dsi.c @@ -2038,8 +2038,6 @@ void icl_dsi_init(struct drm_i915_private *dev_priv) DRM_MODE_CONNECTOR_DSI); drm_connector_helper_add(connector, &gen11_dsi_connector_helper_funcs); connector->display_info.subpixel_order = SubPixelHorizontalRGB; - connector->interlace_allowed = false; - connector->doublescan_allowed = false; intel_connector->get_hw_state = intel_connector_get_hw_state; /* attach connector to encoder */ diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c index eba58345619a..94d0a5e1dd03 100644 --- a/drivers/gpu/drm/i915/display/intel_crt.c +++ b/drivers/gpu/drm/i915/display/intel_crt.c @@ -1050,11 +1050,8 @@ void intel_crt_init(struct drm_i915_private *dev_priv) else crt->base.pipe_mask = ~0; - if (DISPLAY_VER(dev_priv) == 2) - connector->interlace_allowed = 0; - else - connector->interlace_allowed = 1; - connector->doublescan_allowed = 0; + if (DISPLAY_VER(dev_priv) != 2) + connector->interlace_allowed = true; crt->adpa_reg = adpa_reg; diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 0d195f8b190a..ecde1fd41726 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -5411,7 +5411,6 @@ intel_dp_init_connector(struct intel_digital_port *dig_port, if (!HAS_GMCH(dev_priv)) connector->interlace_allowed = true; - connector->doublescan_allowed = 0; intel_connector->polled = DRM_CONNECTOR_POLL_HPD; diff --git a/drivers/gpu/drm/i915/display/intel_dvo.c b/drivers/gpu/drm/i915/display/intel_dvo.c index 167c9b7318f8..595087288922 100644 --- a/drivers/gpu/drm/i915/display/intel_dvo.c +++ b/drivers/gpu/drm/i915/display/intel_dvo.c @@ -515,8 +515,6 @@ void intel_dvo_init(struct drm_i915_private *dev_priv) drm_connector_helper_add(connector, &intel_dvo_connector_helper_funcs); connector->display_info.subpixel_order = SubPixelHorizontalRGB; - connector->interlace_allowed = false; - connector->doublescan_allowed = false; intel_connector_attach_encoder(intel_connector, intel_encoder); if (dvo->type == INTEL_DVO_CHIP_LVDS) { diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index 7816b2a33fee..93519fb23d9d 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -2956,9 +2956,8 @@ void intel_hdmi_init_connector(struct intel_digital_port *dig_port, ddc); drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs); - connector->interlace_allowed = 1; - connector->doublescan_allowed = 0; - connector->stereo_allowed = 1; + connector->interlace_allowed = true; + connector->stereo_allowed = true; if (DISPLAY_VER(dev_priv) >= 10) connector->ycbcr_420_allowed = true; diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c index 951170af7bb3..270368b43729 100644 --- a/drivers/gpu/drm/i915/display/intel_lvds.c +++ b/drivers/gpu/drm/i915/display/intel_lvds.c @@ -924,8 +924,6 @@ void intel_lvds_init(struct drm_i915_private *dev_priv) drm_connector_helper_add(connector, &intel_lvds_connector_helper_funcs); connector->display_info.subpixel_order = SubPixelHorizontalRGB; - connector->interlace_allowed = false; - connector->doublescan_allowed = false; lvds_encoder->reg = lvds_reg; diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c index f5b744bef18f..2a99ec7ff737 100644 --- a/drivers/gpu/drm/i915/display/intel_sdvo.c +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c @@ -2689,9 +2689,8 @@ intel_sdvo_connector_init(struct intel_sdvo_connector *connector, drm_connector_helper_add(drm_connector, &intel_sdvo_connector_helper_funcs); - connector->base.base.interlace_allowed = 1; - connector->base.base.doublescan_allowed = 0; connector->base.base.display_info.subpixel_order = SubPixelHorizontalRGB; + connector->base.base.interlace_allowed = true; connector->base.get_hw_state = intel_sdvo_connector_get_hw_state; intel_connector_attach_encoder(&connector->base, &encoder->base); diff --git a/drivers/gpu/drm/i915/display/intel_tv.c b/drivers/gpu/drm/i915/display/intel_tv.c index 2b985bfc7fc2..b2e93c2ad8f3 100644 --- a/drivers/gpu/drm/i915/display/intel_tv.c +++ b/drivers/gpu/drm/i915/display/intel_tv.c @@ -2013,8 +2013,6 @@ intel_tv_init(struct drm_i915_private *dev_priv) intel_tv->type = DRM_MODE_CONNECTOR_Unknown; drm_connector_helper_add(connector, &intel_tv_connector_helper_funcs); - connector->interlace_allowed = false; - connector->doublescan_allowed = false; intel_tv_add_properties(connector); } diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c index 421ad02f8e9b..dee0147a316c 100644 --- a/drivers/gpu/drm/i915/display/vlv_dsi.c +++ b/drivers/gpu/drm/i915/display/vlv_dsi.c @@ -1971,8 +1971,6 @@ void vlv_dsi_init(struct drm_i915_private *dev_priv) drm_connector_helper_add(connector, &intel_dsi_connector_helper_funcs); connector->display_info.subpixel_order = SubPixelHorizontalRGB; /*XXX*/ - connector->interlace_allowed = false; - connector->doublescan_allowed = false; intel_connector_attach_encoder(intel_connector, intel_encoder); -- cgit From bde544e1d7017f3169b4d97b2e19c2d28066d87c Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 12 Sep 2022 14:18:12 +0300 Subject: drm/i915: Don't init eDP if we can't find a fixed mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the unlikely case of not finding a fixed mode don't register the eDP connector. I think there are some places where we'd oops if we didn't have a fixed mode for eDP so presumable this doesn't typically happen. But better safe than sorry. Also pimp the debugs with the encoder id+name. I think dumping the encoder rather than the connector provides more information here (eg. to match against the port information in the VBT). We can also drop the extra check from intel_edp_add_properties(). Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220912111814.17466-14-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_dp.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index ecde1fd41726..e12231b8d3a3 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -5186,9 +5186,6 @@ intel_edp_add_properties(struct intel_dp *intel_dp) intel_attach_scaling_mode_property(&connector->base); - if (!fixed_mode) - return; - drm_connector_set_panel_orientation_with_quirk(&connector->base, i915->display.vbt.orientation, fixed_mode->hdisplay, @@ -5261,7 +5258,8 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, if (!has_dpcd) { /* if this fails, presume the device is a ghost */ drm_info(&dev_priv->drm, - "failed to retrieve link info, disabling eDP\n"); + "[ENCODER:%d:%s] failed to retrieve link info, disabling eDP\n", + encoder->base.base.id, encoder->base.name); goto out_vdd_off; } @@ -5307,6 +5305,13 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, mutex_unlock(&dev->mode_config.mutex); + if (!intel_panel_preferred_fixed_mode(intel_connector)) { + drm_info(&dev_priv->drm, + "[ENCODER:%d:%s] failed to find fixed mode for the panel, disabling eDP\n", + encoder->base.base.id, encoder->base.name); + goto out_vdd_off; + } + intel_panel_init(intel_connector); intel_edp_backlight_setup(intel_dp, intel_connector); -- cgit From 543ba9d6873b47982aa32c88a18177427e51ae25 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 22 Jun 2022 18:54:44 +0300 Subject: drm/i915: Split g4x_compute_pipe_wm() into two MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split g4x_compute_pipe_wm() into two halves. The first half computes the new raw watermarks, and the second half munges those up into real watermarks for the particular pipe. We can reuse the second half for watermark sanitation as well. Reviewed-by: Stanislav Lisovskiy Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220622155452.32587-2-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/intel_pm.c | 54 +++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 7b454314ab85..2432e9967977 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1337,34 +1337,14 @@ static bool g4x_compute_fbc_en(const struct g4x_wm_state *wm_state, return true; } -static int g4x_compute_pipe_wm(struct intel_atomic_state *state, - struct intel_crtc *crtc) +static int _g4x_compute_pipe_wm(struct intel_crtc_state *crtc_state) { - struct intel_crtc_state *crtc_state = - intel_atomic_get_new_crtc_state(state, crtc); + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct g4x_wm_state *wm_state = &crtc_state->wm.g4x.optimal; u8 active_planes = crtc_state->active_planes & ~BIT(PLANE_CURSOR); const struct g4x_pipe_wm *raw; - const struct intel_plane_state *old_plane_state; - const struct intel_plane_state *new_plane_state; - struct intel_plane *plane; enum plane_id plane_id; - int i, level; - unsigned int dirty = 0; - - for_each_oldnew_intel_plane_in_state(state, plane, - old_plane_state, - new_plane_state, i) { - if (new_plane_state->hw.crtc != &crtc->base && - old_plane_state->hw.crtc != &crtc->base) - continue; - - if (g4x_raw_plane_wm_compute(crtc_state, new_plane_state)) - dirty |= BIT(plane->id); - } - - if (!dirty) - return 0; + int level; level = G4X_WM_LEVEL_NORMAL; if (!g4x_raw_crtc_wm_is_valid(crtc_state, level)) @@ -1417,6 +1397,34 @@ static int g4x_compute_pipe_wm(struct intel_atomic_state *state, return 0; } +static int g4x_compute_pipe_wm(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ + struct intel_crtc_state *crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); + const struct intel_plane_state *old_plane_state; + const struct intel_plane_state *new_plane_state; + struct intel_plane *plane; + unsigned int dirty = 0; + int i; + + for_each_oldnew_intel_plane_in_state(state, plane, + old_plane_state, + new_plane_state, i) { + if (new_plane_state->hw.crtc != &crtc->base && + old_plane_state->hw.crtc != &crtc->base) + continue; + + if (g4x_raw_plane_wm_compute(crtc_state, new_plane_state)) + dirty |= BIT(plane->id); + } + + if (!dirty) + return 0; + + return _g4x_compute_pipe_wm(crtc_state); +} + static int g4x_compute_intermediate_wm(struct intel_atomic_state *state, struct intel_crtc *crtc) { -- cgit From ed57cfd9d54a772a1b60de6dd9f4e90fdba72a4a Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 22 Jun 2022 18:54:45 +0300 Subject: drm/i915: Split vlv_compute_pipe_wm() into two MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split vlv_compute_pipe_wm() into two halves. The first half computes the new raw watermarks, and the second half munges those up into real watermarks for the particular pipe. We can reuse the second half for watermark sanitation as well. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220622155452.32587-3-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy --- drivers/gpu/drm/i915/intel_pm.c | 114 ++++++++++++++++++++++------------------ 1 file changed, 64 insertions(+), 50 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 2432e9967977..01557e571822 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1865,64 +1865,17 @@ static bool vlv_raw_crtc_wm_is_valid(const struct intel_crtc_state *crtc_state, vlv_raw_plane_wm_is_valid(crtc_state, PLANE_CURSOR, level); } -static int vlv_compute_pipe_wm(struct intel_atomic_state *state, - struct intel_crtc *crtc) +static int _vlv_compute_pipe_wm(struct intel_crtc_state *crtc_state) { + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - struct intel_crtc_state *crtc_state = - intel_atomic_get_new_crtc_state(state, crtc); struct vlv_wm_state *wm_state = &crtc_state->wm.vlv.optimal; const struct vlv_fifo_state *fifo_state = &crtc_state->wm.vlv.fifo_state; u8 active_planes = crtc_state->active_planes & ~BIT(PLANE_CURSOR); int num_active_planes = hweight8(active_planes); - bool needs_modeset = drm_atomic_crtc_needs_modeset(&crtc_state->uapi); - const struct intel_plane_state *old_plane_state; - const struct intel_plane_state *new_plane_state; - struct intel_plane *plane; enum plane_id plane_id; - int level, ret, i; - unsigned int dirty = 0; - - for_each_oldnew_intel_plane_in_state(state, plane, - old_plane_state, - new_plane_state, i) { - if (new_plane_state->hw.crtc != &crtc->base && - old_plane_state->hw.crtc != &crtc->base) - continue; - - if (vlv_raw_plane_wm_compute(crtc_state, new_plane_state)) - dirty |= BIT(plane->id); - } - - /* - * DSPARB registers may have been reset due to the - * power well being turned off. Make sure we restore - * them to a consistent state even if no primary/sprite - * planes are initially active. - */ - if (needs_modeset) - crtc_state->fifo_changed = true; - - if (!dirty) - return 0; - - /* cursor changes don't warrant a FIFO recompute */ - if (dirty & ~BIT(PLANE_CURSOR)) { - const struct intel_crtc_state *old_crtc_state = - intel_atomic_get_old_crtc_state(state, crtc); - const struct vlv_fifo_state *old_fifo_state = - &old_crtc_state->wm.vlv.fifo_state; - - ret = vlv_compute_fifo(crtc_state); - if (ret) - return ret; - - if (needs_modeset || - memcmp(old_fifo_state, fifo_state, - sizeof(*fifo_state)) != 0) - crtc_state->fifo_changed = true; - } + int level; /* initially allow all levels */ wm_state->num_levels = intel_wm_num_levels(dev_priv); @@ -1969,6 +1922,67 @@ static int vlv_compute_pipe_wm(struct intel_atomic_state *state, return 0; } +static int vlv_compute_pipe_wm(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ + struct intel_crtc_state *crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); + bool needs_modeset = drm_atomic_crtc_needs_modeset(&crtc_state->uapi); + const struct intel_plane_state *old_plane_state; + const struct intel_plane_state *new_plane_state; + struct intel_plane *plane; + unsigned int dirty = 0; + int i; + + for_each_oldnew_intel_plane_in_state(state, plane, + old_plane_state, + new_plane_state, i) { + if (new_plane_state->hw.crtc != &crtc->base && + old_plane_state->hw.crtc != &crtc->base) + continue; + + if (vlv_raw_plane_wm_compute(crtc_state, new_plane_state)) + dirty |= BIT(plane->id); + } + + /* + * DSPARB registers may have been reset due to the + * power well being turned off. Make sure we restore + * them to a consistent state even if no primary/sprite + * planes are initially active. We also force a FIFO + * recomputation so that we are sure to sanitize the + * FIFO setting we took over from the BIOS even if there + * are no active planes on the crtc. + */ + if (needs_modeset) + dirty = ~0; + + if (!dirty) + return 0; + + /* cursor changes don't warrant a FIFO recompute */ + if (dirty & ~BIT(PLANE_CURSOR)) { + const struct intel_crtc_state *old_crtc_state = + intel_atomic_get_old_crtc_state(state, crtc); + const struct vlv_fifo_state *old_fifo_state = + &old_crtc_state->wm.vlv.fifo_state; + const struct vlv_fifo_state *new_fifo_state = + &crtc_state->wm.vlv.fifo_state; + int ret; + + ret = vlv_compute_fifo(crtc_state); + if (ret) + return ret; + + if (needs_modeset || + memcmp(old_fifo_state, new_fifo_state, + sizeof(*new_fifo_state)) != 0) + crtc_state->fifo_changed = true; + } + + return _vlv_compute_pipe_wm(crtc_state); +} + #define VLV_FIFO(plane, value) \ (((value) << DSPARB_ ## plane ## _SHIFT_VLV) & DSPARB_ ## plane ## _MASK_VLV) -- cgit From 6340120014e8a82263f38c724ea8f3611cc0d074 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 22 Jun 2022 18:54:46 +0300 Subject: drm/i915: Simplify up g4x watermark sanitation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can simplify the g4x watermark sanitation by reusing the second half of g4x_compute_pipe_wm() to convert the sanitized raw watermarks into the proper form to be used as the optimal/intermediate watermarks. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220622155452.32587-4-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy --- drivers/gpu/drm/i915/intel_pm.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 01557e571822..81a762e88b75 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3882,37 +3882,30 @@ void g4x_wm_sanitize(struct drm_i915_private *dev_priv) to_intel_crtc_state(crtc->base.state); struct intel_plane_state *plane_state = to_intel_plane_state(plane->base.state); - struct g4x_wm_state *wm_state = &crtc_state->wm.g4x.optimal; enum plane_id plane_id = plane->id; - int level; + int level, num_levels = intel_wm_num_levels(dev_priv); if (plane_state->uapi.visible) continue; - for (level = 0; level < 3; level++) { + for (level = 0; level < num_levels; level++) { struct g4x_pipe_wm *raw = &crtc_state->wm.g4x.raw[level]; raw->plane[plane_id] = 0; - wm_state->wm.plane[plane_id] = 0; - } - if (plane_id == PLANE_PRIMARY) { - for (level = 0; level < 3; level++) { - struct g4x_pipe_wm *raw = - &crtc_state->wm.g4x.raw[level]; + if (plane_id == PLANE_PRIMARY) raw->fbc = 0; - } - - wm_state->sr.fbc = 0; - wm_state->hpll.fbc = 0; - wm_state->fbc_en = false; } } for_each_intel_crtc(&dev_priv->drm, crtc) { struct intel_crtc_state *crtc_state = to_intel_crtc_state(crtc->base.state); + int ret; + + ret = _g4x_compute_pipe_wm(crtc_state); + drm_WARN_ON(&dev_priv->drm, ret); crtc_state->wm.g4x.intermediate = crtc_state->wm.g4x.optimal; -- cgit From 59f13af3b645e647247de14cc06f0d04c5cc24ae Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 22 Jun 2022 18:54:47 +0300 Subject: drm/i915: Simplify up vlv watermark sanitation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can simplify the vlv watermark sanitation by reusing the second half of vlv_compute_pipe_wm() to convert the sanitized raw watermarks into the proper form to be used as the optimal/intermediate watermarks. Also to be consistent with normal watermark computation the sanitized watermarks should be all 0 for any disabled plane. Previously we zeroed out the watermarks only up to the level (ie. PM2/5/DVDFS) that was enabled. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220622155452.32587-5-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy --- drivers/gpu/drm/i915/intel_pm.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 81a762e88b75..fdea82d29f14 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4031,30 +4031,27 @@ void vlv_wm_sanitize(struct drm_i915_private *dev_priv) to_intel_crtc_state(crtc->base.state); struct intel_plane_state *plane_state = to_intel_plane_state(plane->base.state); - struct vlv_wm_state *wm_state = &crtc_state->wm.vlv.optimal; - const struct vlv_fifo_state *fifo_state = - &crtc_state->wm.vlv.fifo_state; enum plane_id plane_id = plane->id; - int level; + int level, num_levels = intel_wm_num_levels(dev_priv); if (plane_state->uapi.visible) continue; - for (level = 0; level < wm_state->num_levels; level++) { + for (level = 0; level < num_levels; level++) { struct g4x_pipe_wm *raw = &crtc_state->wm.vlv.raw[level]; raw->plane[plane_id] = 0; - - wm_state->wm[level].plane[plane_id] = - vlv_invert_wm_value(raw->plane[plane_id], - fifo_state->plane[plane_id]); } } for_each_intel_crtc(&dev_priv->drm, crtc) { struct intel_crtc_state *crtc_state = to_intel_crtc_state(crtc->base.state); + int ret; + + ret = _vlv_compute_pipe_wm(crtc_state); + drm_WARN_ON(&dev_priv->drm, ret); crtc_state->wm.vlv.intermediate = crtc_state->wm.vlv.optimal; -- cgit From 2d28094b26be804369fcf92315123ff07f3d4e0e Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 22 Jun 2022 18:54:48 +0300 Subject: drm/i915: Add missing invalidate to g4x wm readout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's not forget to mark the unused watermark levels as invalid after the readout. The vlv/chv codepath has this but the g4x didn't for some reason. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220622155452.32587-6-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy --- drivers/gpu/drm/i915/intel_pm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index fdea82d29f14..3cd696806b58 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3846,6 +3846,8 @@ void g4x_wm_get_hw_state(struct drm_i915_private *dev_priv) plane_id, USHRT_MAX); g4x_raw_fbc_wm_set(crtc_state, level, USHRT_MAX); + g4x_invalidate_wms(crtc, active, level); + crtc_state->wm.g4x.optimal = *active; crtc_state->wm.g4x.intermediate = *active; -- cgit From 86570b7b126bd516aba770d1fc4c971c55c66dca Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 16 Sep 2022 11:26:42 +0300 Subject: drm/i915: fix device info for devices without display Commit 00c6cbfd4e8a ("drm/i915: move pipe_mask and cpu_transcoder_mask to runtime info") moved the pipe_mask member from struct intel_device_info to intel_runtime_info, but overlooked some of our platforms initializing device info .display = {}. This is significant, as pipe_mask is the single point of truth for a device having a display or not; the platforms in question left pipe_mask to whatever was set for the platforms they "inherit" from in the complex macro scheme we have. Add new NO_DISPLAY macro initializing .__runtime.pipe_mask = 0, which will cause the device info .display sub-struct to be zeroed in intel_device_info_runtime_init(). A better solution (or simply audit of proper use of HAS_DISPLAY() checks) is required before moving forward with [1]. Also clear all the display related members in runtime info if there's no display. The latter is a bit tedious, but it's for completeness at this time, to ensure similar functionality as before. [1] https://lore.kernel.org/r/dfda1bf67f02ceb07c280b7a13216405fd1f7a34.1660137416.git.jani.nikula@intel.com Fixes: 00c6cbfd4e8a ("drm/i915: move pipe_mask and cpu_transcoder_mask to runtime info") Cc: Lucas De Marchi Cc: Maarten Lankhort Signed-off-by: Jani Nikula Reviewed-by: Gwan-gyeong Mun Acked-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20220916082642.3451961-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/i915_pci.c | 11 ++++++----- drivers/gpu/drm/i915/intel_device_info.c | 6 ++++++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c index 6b563461b314..99624c71b732 100644 --- a/drivers/gpu/drm/i915/i915_pci.c +++ b/drivers/gpu/drm/i915/i915_pci.c @@ -38,6 +38,8 @@ .__runtime.media.ip.ver = (x), \ .__runtime.display.ip.ver = (x) +#define NO_DISPLAY .__runtime.pipe_mask = 0 + #define I845_PIPE_OFFSETS \ .display.pipe_offsets = { \ [TRANSCODER_A] = PIPE_A_OFFSET, \ @@ -516,9 +518,8 @@ static const struct intel_device_info ivb_m_gt2_info = { static const struct intel_device_info ivb_q_info = { GEN7_FEATURES, PLATFORM(INTEL_IVYBRIDGE), + NO_DISPLAY, .gt = 2, - .__runtime.pipe_mask = 0, /* legal, last one wins */ - .__runtime.cpu_transcoder_mask = 0, .has_l3_dpf = 1, }; @@ -1036,7 +1037,7 @@ static const struct intel_device_info xehpsdv_info = { XE_HPM_FEATURES, DGFX_FEATURES, PLATFORM(INTEL_XEHPSDV), - .display = { }, + NO_DISPLAY, .has_64k_pages = 1, .needs_compact_pt = 1, .has_media_ratio_mode = 1, @@ -1078,7 +1079,7 @@ static const struct intel_device_info dg2_info = { static const struct intel_device_info ats_m_info = { DG2_FEATURES, - .display = { 0 }, + NO_DISPLAY, .require_force_probe = 1, }; @@ -1099,7 +1100,7 @@ static const struct intel_device_info pvc_info = { .__runtime.graphics.ip.rel = 60, .__runtime.media.ip.rel = 60, PLATFORM(INTEL_PONTEVECCHIO), - .display = { 0 }, + NO_DISPLAY, .has_flat_ccs = 0, .__runtime.platform_engine_mask = BIT(BCS0) | diff --git a/drivers/gpu/drm/i915/intel_device_info.c b/drivers/gpu/drm/i915/intel_device_info.c index 2018eaaa45f5..908ec241fe71 100644 --- a/drivers/gpu/drm/i915/intel_device_info.c +++ b/drivers/gpu/drm/i915/intel_device_info.c @@ -498,8 +498,14 @@ void intel_device_info_runtime_init(struct drm_i915_private *dev_priv) dev_priv->drm.driver_features &= ~(DRIVER_MODESET | DRIVER_ATOMIC); memset(&info->display, 0, sizeof(info->display)); + + runtime->cpu_transcoder_mask = 0; memset(runtime->num_sprites, 0, sizeof(runtime->num_sprites)); memset(runtime->num_scalers, 0, sizeof(runtime->num_scalers)); + runtime->fbc_mask = 0; + runtime->has_hdcp = false; + runtime->has_dmc = false; + runtime->has_dsc = false; } } -- cgit From eddb4afcb6c533d3f75f5f1a77e292fece27570e Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 22 Sep 2022 22:12:36 +0300 Subject: drm/i915: Force DPLL calculation for TC ports after readout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We always allocate two DPLLs (TC and TBT) for TC ports. This is because we can't know ahead of time wherher we need to put the PHY into DP-Alt or TBT mode. However during readout we can obviously only read out the state of the DPLL that the port is actually using. Thus the state after readout will not have both DPLLs populated. We run into problems if during readout the TC port is in DP-Alt mode, but we then perform a modeset on the port without going through the full .compute_config() machinery, and during said modeset the port cannot be switched back into DP-Alt mode and we need to take the TBT fallback path. Such a modeset can happen eg. due to cdclk reprogramming. This wasn't a problem earlier because we did all the DPLL calculations much later in the modeset. So even if flagged a modeset very late we'd still have gone through the DPLL calculations. But now all the DPLL calculations happen much earlier and so we need to deal with it, or else we'll attempt a modeset without a DPLL. To guarantee that we always have both DPLLs fully cal/ulated for TC ports force a full modeset computation during the initial commit. v2: Avoid bitwise operation on bool (Jani) Call the return variable 'fastset' to convey its meaning Reported-by: Lee Shawn C Fixes: b000abd3b3d2 ("drm/i915: Do .crtc_compute_clock() earlier") Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220922191236.4194-1-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_ddi.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 643832d55c28..da8472cdc135 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -3600,10 +3600,22 @@ static void intel_ddi_sync_state(struct intel_encoder *encoder, static bool intel_ddi_initial_fastset_check(struct intel_encoder *encoder, struct intel_crtc_state *crtc_state) { - if (intel_crtc_has_dp_encoder(crtc_state)) - return intel_dp_initial_fastset_check(encoder, crtc_state); + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum phy phy = intel_port_to_phy(i915, encoder->port); + bool fastset = true; - return true; + if (intel_phy_is_tc(i915, phy)) { + drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s] Forcing full modeset to compute TC port DPLLs\n", + encoder->base.base.id, encoder->base.name); + crtc_state->uapi.mode_changed = true; + fastset = false; + } + + if (intel_crtc_has_dp_encoder(crtc_state) && + !intel_dp_initial_fastset_check(encoder, crtc_state)) + fastset = false; + + return fastset; } static enum intel_output_type -- cgit From fea1beb60db55abc05b2def917bff8e40825d3ed Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 22 Sep 2022 22:13:14 +0300 Subject: drm/i915: Don't bail early from intel_dp_initial_fastset_check() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do all the checks in intel_dp_initial_fastset_check() instead of bailing out on the first condition that triggers. This makes for better debug logs since we see all the reasons why the full modeset computation is forced. Also avoid the risk of someone accidentally adding a check later in the function that would require connectors_changed=true (ie. no fastset at all), but an earlier check may have already bailed out with just mode_changed=true (ie. fastset is still possible). Pimp the debugs with the encoder id+name while at it. v2: Call the return variable 'fastset' to convey its meaning Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220922191314.4252-1-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_dp.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index e12231b8d3a3..6ebd6e104b2c 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -2306,6 +2306,7 @@ bool intel_dp_initial_fastset_check(struct intel_encoder *encoder, { struct drm_i915_private *i915 = to_i915(encoder->base.dev); struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + bool fastset = true; /* * If BIOS has set an unsupported or non-standard link rate for some @@ -2313,9 +2314,10 @@ bool intel_dp_initial_fastset_check(struct intel_encoder *encoder, */ if (intel_dp_rate_index(intel_dp->source_rates, intel_dp->num_source_rates, crtc_state->port_clock) < 0) { - drm_dbg_kms(&i915->drm, "Forcing full modeset due to unsupported link rate\n"); + drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s] Forcing full modeset due to unsupported link rate\n", + encoder->base.base.id, encoder->base.name); crtc_state->uapi.connectors_changed = true; - return false; + fastset = false; } /* @@ -2326,18 +2328,20 @@ bool intel_dp_initial_fastset_check(struct intel_encoder *encoder, * Remove once we have readout for DSC. */ if (crtc_state->dsc.compression_enable) { - drm_dbg_kms(&i915->drm, "Forcing full modeset due to DSC being enabled\n"); + drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s] Forcing full modeset due to DSC being enabled\n", + encoder->base.base.id, encoder->base.name); crtc_state->uapi.mode_changed = true; - return false; + fastset = false; } if (CAN_PSR(intel_dp)) { - drm_dbg_kms(&i915->drm, "Forcing full modeset to compute PSR state\n"); + drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s] Forcing full modeset to compute PSR state\n", + encoder->base.base.id, encoder->base.name); crtc_state->uapi.mode_changed = true; - return false; + fastset = false; } - return true; + return fastset; } static void intel_dp_get_pcon_dsc_cap(struct intel_dp *intel_dp) -- cgit From aa07d34d9f2fba6cad41c85ead441dde27882fd5 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 22 Sep 2022 22:13:50 +0300 Subject: drm/i915: Pimp DPLL ref/unref debugs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We currently have a debug message in intel_reference_shared_dpll() but no counterpart in intel_unreference_shared_dpll(). Add one. Switch to the [CRTC:...] notation for the pipe name while at it. v2: Use drm_dbg_kms() instead of drm_dbg() (Jani) Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220922191350.4303-1-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_dpll_mgr.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c index 60b3277a857b..cc5efac555fb 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c @@ -384,20 +384,25 @@ intel_reference_shared_dpll(struct intel_atomic_state *state, if (shared_dpll[id].pipe_mask == 0) shared_dpll[id].hw_state = *pll_state; - drm_dbg(&i915->drm, "using %s for pipe %c\n", pll->info->name, - pipe_name(crtc->pipe)); - shared_dpll[id].pipe_mask |= BIT(crtc->pipe); + + drm_dbg_kms(&i915->drm, "[CRTC:%d:%s] reserving %s\n", + crtc->base.base.id, crtc->base.name, pll->info->name); } static void intel_unreference_shared_dpll(struct intel_atomic_state *state, const struct intel_crtc *crtc, const struct intel_shared_dpll *pll) { + struct drm_i915_private *i915 = to_i915(state->base.dev); struct intel_shared_dpll_state *shared_dpll; shared_dpll = intel_atomic_get_shared_dpll_state(&state->base); + shared_dpll[pll->info->id].pipe_mask &= ~BIT(crtc->pipe); + + drm_dbg_kms(&i915->drm, "[CRTC:%d:%s] releasing %s\n", + crtc->base.base.id, crtc->base.name, pll->info->name); } static void intel_put_dpll(struct intel_atomic_state *state, -- cgit From 073a12f45fb8e3b21c9e08c36a2528d9f9e38d83 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 22 Sep 2022 00:15:25 +0300 Subject: drm/i915: WARN if PLL ref/unref got messed up MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Spew a WARN if we try to ref/unref the same DPLL multiple times for the same pipe. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220921211525.10675-5-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_dpll_mgr.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c index cc5efac555fb..00e97bd1bbe3 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c @@ -384,6 +384,8 @@ intel_reference_shared_dpll(struct intel_atomic_state *state, if (shared_dpll[id].pipe_mask == 0) shared_dpll[id].hw_state = *pll_state; + drm_WARN_ON(&i915->drm, (shared_dpll[id].pipe_mask & BIT(crtc->pipe)) != 0); + shared_dpll[id].pipe_mask |= BIT(crtc->pipe); drm_dbg_kms(&i915->drm, "[CRTC:%d:%s] reserving %s\n", @@ -396,10 +398,13 @@ static void intel_unreference_shared_dpll(struct intel_atomic_state *state, { struct drm_i915_private *i915 = to_i915(state->base.dev); struct intel_shared_dpll_state *shared_dpll; + const enum intel_dpll_id id = pll->info->id; shared_dpll = intel_atomic_get_shared_dpll_state(&state->base); - shared_dpll[pll->info->id].pipe_mask &= ~BIT(crtc->pipe); + drm_WARN_ON(&i915->drm, (shared_dpll[id].pipe_mask & BIT(crtc->pipe)) == 0); + + shared_dpll[id].pipe_mask &= ~BIT(crtc->pipe); drm_dbg_kms(&i915->drm, "[CRTC:%d:%s] releasing %s\n", crtc->base.base.id, crtc->base.name, pll->info->name); -- cgit From 8a549e8d19f401a717f72cc035f5df6b4d128564 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 21 Sep 2022 15:23:40 +0300 Subject: drm/i915: Always initialize dpll.lock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Initialize the dll.lock mutex whether or not we manage to initialize the rest of the dpll mgr. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220921122343.13061-2-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_dpll_mgr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c index 00e97bd1bbe3..488fffa059d6 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c @@ -4193,6 +4193,8 @@ void intel_shared_dpll_init(struct drm_i915_private *dev_priv) const struct dpll_info *dpll_info; int i; + mutex_init(&dev_priv->display.dpll.lock); + if (IS_DG2(dev_priv)) /* No shared DPLLs on DG2; port PLLs are part of the PHY */ dpll_mgr = NULL; @@ -4237,7 +4239,6 @@ void intel_shared_dpll_init(struct drm_i915_private *dev_priv) dev_priv->display.dpll.mgr = dpll_mgr; dev_priv->display.dpll.num_shared_dpll = i; - mutex_init(&dev_priv->display.dpll.lock); } /** -- cgit From e731a2d2fa13eaa584f4730d619e8e89061e4f6e Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 21 Sep 2022 15:23:41 +0300 Subject: drm/i915: Nuke intel_get_shared_dpll_id() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each PLL knows its own ID so intel_get_shared_dpll_id() is pointless. Get rid of it. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220921122343.13061-3-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_ddi.c | 4 ++-- drivers/gpu/drm/i915/display/intel_dpll_mgr.c | 22 ---------------------- drivers/gpu/drm/i915/display/intel_dpll_mgr.h | 3 --- 3 files changed, 2 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index da8472cdc135..0301a7745ad0 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -3536,7 +3536,7 @@ static void icl_ddi_tc_get_clock(struct intel_encoder *encoder, if (drm_WARN_ON(&i915->drm, !pll)) return; - if (intel_get_shared_dpll_id(i915, pll) == DPLL_ID_ICL_TBTPLL) + if (pll->info->id == DPLL_ID_ICL_TBTPLL) port_dpll_id = ICL_PORT_DPLL_DEFAULT; else port_dpll_id = ICL_PORT_DPLL_MG_PHY; @@ -3549,7 +3549,7 @@ static void icl_ddi_tc_get_clock(struct intel_encoder *encoder, icl_set_active_port_dpll(crtc_state, port_dpll_id); - if (intel_get_shared_dpll_id(i915, crtc_state->shared_dpll) == DPLL_ID_ICL_TBTPLL) + if (crtc_state->shared_dpll->info->id == DPLL_ID_ICL_TBTPLL) crtc_state->port_clock = icl_calc_tbt_pll_link(i915, encoder->port); else crtc_state->port_clock = intel_dpll_get_freq(i915, crtc_state->shared_dpll, diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c index 488fffa059d6..b63600d8ebeb 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c @@ -152,28 +152,6 @@ intel_get_shared_dpll_by_id(struct drm_i915_private *dev_priv, return &dev_priv->display.dpll.shared_dplls[id]; } -/** - * intel_get_shared_dpll_id - get the id of a DPLL - * @dev_priv: i915 device instance - * @pll: the DPLL - * - * Returns: - * The id of @pll - */ -enum intel_dpll_id -intel_get_shared_dpll_id(struct drm_i915_private *dev_priv, - struct intel_shared_dpll *pll) -{ - long pll_idx = pll - dev_priv->display.dpll.shared_dplls; - - if (drm_WARN_ON(&dev_priv->drm, - pll_idx < 0 || - pll_idx >= dev_priv->display.dpll.num_shared_dpll)) - return -1; - - return pll_idx; -} - /* For ILK+ */ void assert_shared_dpll(struct drm_i915_private *dev_priv, struct intel_shared_dpll *pll, diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.h b/drivers/gpu/drm/i915/display/intel_dpll_mgr.h index 3247dc300ae4..3854f1b4299a 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.h +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.h @@ -328,9 +328,6 @@ struct intel_shared_dpll { struct intel_shared_dpll * intel_get_shared_dpll_by_id(struct drm_i915_private *dev_priv, enum intel_dpll_id id); -enum intel_dpll_id -intel_get_shared_dpll_id(struct drm_i915_private *dev_priv, - struct intel_shared_dpll *pll); void assert_shared_dpll(struct drm_i915_private *dev_priv, struct intel_shared_dpll *pll, bool state); -- cgit From c286558f58535cf97b717b946d6c96d774a09d17 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 26 Sep 2022 16:33:33 +0100 Subject: drm/i915/gt: Use i915_vm_put on ppgtt_create error paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that the scratch page and page directories have a reference back to the i915_address_space, we cannot do an immediate free of the ppgtt upon error as those buffer objects will perform a later i915_vm_put in their deferred frees. The downside is that by replacing the onion unwind along the error paths, the ppgtt cleanup must handle a partially constructed vm. This includes ensuring that the vm->cleanup is set prior to the error path. Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/6900 Signed-off-by: Chris Wilson Fixes: 4d8151ae5329 ("drm/i915: Don't free shared locks while shared") Cc: Thomas Hellström Cc: Matthew Auld Cc: # v5.14+ Reviewed-by: Matthew Auld Signed-off-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20220926153333.102195-1-matthew.auld@intel.com --- drivers/gpu/drm/i915/gt/gen6_ppgtt.c | 16 +++++----- drivers/gpu/drm/i915/gt/gen8_ppgtt.c | 58 +++++++++++++++++++----------------- drivers/gpu/drm/i915/gt/intel_gtt.c | 3 ++ 3 files changed, 41 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/gen6_ppgtt.c b/drivers/gpu/drm/i915/gt/gen6_ppgtt.c index 1bb766c79dcb..5aaacc53fa4c 100644 --- a/drivers/gpu/drm/i915/gt/gen6_ppgtt.c +++ b/drivers/gpu/drm/i915/gt/gen6_ppgtt.c @@ -247,6 +247,7 @@ err_scratch1: i915_gem_object_put(vm->scratch[1]); err_scratch0: i915_gem_object_put(vm->scratch[0]); + vm->scratch[0] = NULL; return ret; } @@ -268,9 +269,10 @@ static void gen6_ppgtt_cleanup(struct i915_address_space *vm) gen6_ppgtt_free_pd(ppgtt); free_scratch(vm); - mutex_destroy(&ppgtt->flush); + if (ppgtt->base.pd) + free_pd(&ppgtt->base.vm, ppgtt->base.pd); - free_pd(&ppgtt->base.vm, ppgtt->base.pd); + mutex_destroy(&ppgtt->flush); } static void pd_vma_bind(struct i915_address_space *vm, @@ -449,19 +451,17 @@ struct i915_ppgtt *gen6_ppgtt_create(struct intel_gt *gt) err = gen6_ppgtt_init_scratch(ppgtt); if (err) - goto err_free; + goto err_put; ppgtt->base.pd = gen6_alloc_top_pd(ppgtt); if (IS_ERR(ppgtt->base.pd)) { err = PTR_ERR(ppgtt->base.pd); - goto err_scratch; + goto err_put; } return &ppgtt->base; -err_scratch: - free_scratch(&ppgtt->base.vm); -err_free: - kfree(ppgtt); +err_put: + i915_vm_put(&ppgtt->base.vm); return ERR_PTR(err); } diff --git a/drivers/gpu/drm/i915/gt/gen8_ppgtt.c b/drivers/gpu/drm/i915/gt/gen8_ppgtt.c index c7bd5d71b03e..2128b7a72a25 100644 --- a/drivers/gpu/drm/i915/gt/gen8_ppgtt.c +++ b/drivers/gpu/drm/i915/gt/gen8_ppgtt.c @@ -196,7 +196,10 @@ static void gen8_ppgtt_cleanup(struct i915_address_space *vm) if (intel_vgpu_active(vm->i915)) gen8_ppgtt_notify_vgt(ppgtt, false); - __gen8_ppgtt_cleanup(vm, ppgtt->pd, gen8_pd_top_count(vm), vm->top); + if (ppgtt->pd) + __gen8_ppgtt_cleanup(vm, ppgtt->pd, + gen8_pd_top_count(vm), vm->top); + free_scratch(vm); } @@ -803,8 +806,10 @@ static int gen8_init_scratch(struct i915_address_space *vm) struct drm_i915_gem_object *obj; obj = vm->alloc_pt_dma(vm, I915_GTT_PAGE_SIZE_4K); - if (IS_ERR(obj)) + if (IS_ERR(obj)) { + ret = PTR_ERR(obj); goto free_scratch; + } ret = map_pt_dma(vm, obj); if (ret) { @@ -823,7 +828,8 @@ static int gen8_init_scratch(struct i915_address_space *vm) free_scratch: while (i--) i915_gem_object_put(vm->scratch[i]); - return -ENOMEM; + vm->scratch[0] = NULL; + return ret; } static int gen8_preallocate_top_level_pdp(struct i915_ppgtt *ppgtt) @@ -901,6 +907,7 @@ err_pd: struct i915_ppgtt *gen8_ppgtt_create(struct intel_gt *gt, unsigned long lmem_pt_obj_flags) { + struct i915_page_directory *pd; struct i915_ppgtt *ppgtt; int err; @@ -946,21 +953,7 @@ struct i915_ppgtt *gen8_ppgtt_create(struct intel_gt *gt, ppgtt->vm.alloc_scratch_dma = alloc_pt_dma; } - err = gen8_init_scratch(&ppgtt->vm); - if (err) - goto err_free; - - ppgtt->pd = gen8_alloc_top_pd(&ppgtt->vm); - if (IS_ERR(ppgtt->pd)) { - err = PTR_ERR(ppgtt->pd); - goto err_free_scratch; - } - - if (!i915_vm_is_4lvl(&ppgtt->vm)) { - err = gen8_preallocate_top_level_pdp(ppgtt); - if (err) - goto err_free_pd; - } + ppgtt->vm.pte_encode = gen8_pte_encode; ppgtt->vm.bind_async_flags = I915_VMA_LOCAL_BIND; ppgtt->vm.insert_entries = gen8_ppgtt_insert; @@ -971,22 +964,31 @@ struct i915_ppgtt *gen8_ppgtt_create(struct intel_gt *gt, ppgtt->vm.allocate_va_range = gen8_ppgtt_alloc; ppgtt->vm.clear_range = gen8_ppgtt_clear; ppgtt->vm.foreach = gen8_ppgtt_foreach; + ppgtt->vm.cleanup = gen8_ppgtt_cleanup; - ppgtt->vm.pte_encode = gen8_pte_encode; + err = gen8_init_scratch(&ppgtt->vm); + if (err) + goto err_put; + + pd = gen8_alloc_top_pd(&ppgtt->vm); + if (IS_ERR(pd)) { + err = PTR_ERR(pd); + goto err_put; + } + ppgtt->pd = pd; + + if (!i915_vm_is_4lvl(&ppgtt->vm)) { + err = gen8_preallocate_top_level_pdp(ppgtt); + if (err) + goto err_put; + } if (intel_vgpu_active(gt->i915)) gen8_ppgtt_notify_vgt(ppgtt, true); - ppgtt->vm.cleanup = gen8_ppgtt_cleanup; - return ppgtt; -err_free_pd: - __gen8_ppgtt_cleanup(&ppgtt->vm, ppgtt->pd, - gen8_pd_top_count(&ppgtt->vm), ppgtt->vm.top); -err_free_scratch: - free_scratch(&ppgtt->vm); -err_free: - kfree(ppgtt); +err_put: + i915_vm_put(&ppgtt->vm); return ERR_PTR(err); } diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.c b/drivers/gpu/drm/i915/gt/intel_gtt.c index b67831833c9a..2eaeba14319e 100644 --- a/drivers/gpu/drm/i915/gt/intel_gtt.c +++ b/drivers/gpu/drm/i915/gt/intel_gtt.c @@ -405,6 +405,9 @@ void free_scratch(struct i915_address_space *vm) { int i; + if (!vm->scratch[0]) + return; + for (i = 0; i <= vm->top; i++) i915_gem_object_put(vm->scratch[i]); } -- cgit From e5cedf9859b29642f8908f7e8949d983c748e2d0 Mon Sep 17 00:00:00 2001 From: Nirmoy Das Date: Fri, 23 Sep 2022 16:37:30 +0200 Subject: drm/i915: Improve debug print in vm_fault_ttm Print the error code returned by __i915_ttm_migrate() for better debuggability. v2: Fix kernel test robot warning. v3: Fix dim checkpatch warning. References: https://gitlab.freedesktop.org/drm/intel/-/issues/6889 Acked-by: Matthew Auld Signed-off-by: Nirmoy Das Signed-off-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20220923143730.13498-1-nirmoy.das@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c index 72ba56e638c8..107bd0d8d06f 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c @@ -1073,7 +1073,8 @@ static vm_fault_t vm_fault_ttm(struct vm_fault *vmf) } if (err) { - drm_dbg(dev, "Unable to make resource CPU accessible\n"); + drm_dbg(dev, "Unable to make resource CPU accessible(err = %pe)\n", + ERR_PTR(err)); dma_resv_unlock(bo->base.resv); ret = VM_FAULT_SIGBUS; goto out_rpm; -- cgit From f28d42663eb063173f63ee294465d2f336da325f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 26 Sep 2022 16:50:18 +0100 Subject: drm/i915/gt: Move scratch page into system memory on all platforms The scratch page should never be accessed, and is only assigned as a filler page to redirection invalid userspace access. It is not of a performance concern and so we prefer to have a single consistent configuration across all platforms, reducing the pressure on device memory and avoiding the direct device access that would be required to initialise the scratch page. Signed-off-by: Chris Wilson Cc: Matthew Auld Reviewed-by: Matthew Auld Signed-off-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20220926155018.109678-1-matthew.auld@intel.com --- drivers/gpu/drm/i915/gt/gen8_ppgtt.c | 43 ++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/gen8_ppgtt.c b/drivers/gpu/drm/i915/gt/gen8_ppgtt.c index 2128b7a72a25..8dd60d5ef905 100644 --- a/drivers/gpu/drm/i915/gt/gen8_ppgtt.c +++ b/drivers/gpu/drm/i915/gt/gen8_ppgtt.c @@ -929,29 +929,30 @@ struct i915_ppgtt *gen8_ppgtt_create(struct intel_gt *gt, */ ppgtt->vm.has_read_only = !IS_GRAPHICS_VER(gt->i915, 11, 12); - if (HAS_LMEM(gt->i915)) { + if (HAS_LMEM(gt->i915)) ppgtt->vm.alloc_pt_dma = alloc_pt_lmem; - - /* - * On some platforms the hw has dropped support for 4K GTT pages - * when dealing with LMEM, and due to the design of 64K GTT - * pages in the hw, we can only mark the *entire* page-table as - * operating in 64K GTT mode, since the enable bit is still on - * the pde, and not the pte. And since we still need to allow - * 4K GTT pages for SMEM objects, we can't have a "normal" 4K - * page-table with scratch pointing to LMEM, since that's - * undefined from the hw pov. The simplest solution is to just - * move the 64K scratch page to SMEM on such platforms and call - * it a day, since that should work for all configurations. - */ - if (HAS_64K_PAGES(gt->i915)) - ppgtt->vm.alloc_scratch_dma = alloc_pt_dma; - else - ppgtt->vm.alloc_scratch_dma = alloc_pt_lmem; - } else { + else ppgtt->vm.alloc_pt_dma = alloc_pt_dma; - ppgtt->vm.alloc_scratch_dma = alloc_pt_dma; - } + + /* + * On some platforms the hw has dropped support for 4K GTT pages + * when dealing with LMEM, and due to the design of 64K GTT + * pages in the hw, we can only mark the *entire* page-table as + * operating in 64K GTT mode, since the enable bit is still on + * the pde, and not the pte. And since we still need to allow + * 4K GTT pages for SMEM objects, we can't have a "normal" 4K + * page-table with scratch pointing to LMEM, since that's + * undefined from the hw pov. The simplest solution is to just + * move the 64K scratch page to SMEM on all platforms and call + * it a day, since that should work for all configurations. + * + * Using SMEM instead of LMEM has the additional advantage of + * not reserving high performance memory for a "never" used + * filler page. It also removes the device access that would + * be required to initialise the scratch page, reducing pressure + * on an even scarcer resource. + */ + ppgtt->vm.alloc_scratch_dma = alloc_pt_dma; ppgtt->vm.pte_encode = gen8_pte_encode; -- cgit From a82796a2e332d108b2d3aff38509caad370f69b5 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 22 Sep 2022 20:21:48 +0300 Subject: drm/i915: Fix TypeC mode initialization during system resume During system resume DP MST requires AUX to be working already before the HW state readout of the given encoder. Since AUX requires the encoder/PHY TypeC mode to be initialized, which atm only happens during HW state readout, these AUX transfers can change the TypeC mode incorrectly (disconnecting the PHY for an enabled encoder) and trigger the state check WARNs in intel_tc_port_sanitize(). Fix this by initializing the TypeC mode earlier both during driver loading and system resume and making sure that the mode can't change until the encoder's state is read out. While at it add the missing DocBook comments and rename intel_tc_port_sanitize()->intel_tc_port_sanitize_mode() for consistency. Signed-off-by: Imre Deak Reviewed-by: Mika Kahola Link: https://patchwork.freedesktop.org/patch/msgid/20220922172148.2913088-1-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 8 +++- drivers/gpu/drm/i915/display/intel_tc.c | 66 ++++++++++++++++++++++++-------- drivers/gpu/drm/i915/display/intel_tc.h | 3 +- 3 files changed, 60 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 0301a7745ad0..971356237eca 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -3591,7 +3591,7 @@ static void intel_ddi_sync_state(struct intel_encoder *encoder, enum phy phy = intel_port_to_phy(i915, encoder->port); if (intel_phy_is_tc(i915, phy)) - intel_tc_port_sanitize(enc_to_dig_port(encoder)); + intel_tc_port_sanitize_mode(enc_to_dig_port(encoder)); if (crtc_state && intel_crtc_has_dp_encoder(crtc_state)) intel_dp_sync_state(encoder, crtc_state); @@ -3801,11 +3801,17 @@ static void intel_ddi_encoder_destroy(struct drm_encoder *encoder) static void intel_ddi_encoder_reset(struct drm_encoder *encoder) { + struct drm_i915_private *i915 = to_i915(encoder->dev); struct intel_dp *intel_dp = enc_to_intel_dp(to_intel_encoder(encoder)); + struct intel_digital_port *dig_port = enc_to_dig_port(to_intel_encoder(encoder)); + enum phy phy = intel_port_to_phy(i915, dig_port->base.port); intel_dp->reset_link_params = true; intel_pps_encoder_reset(intel_dp); + + if (intel_phy_is_tc(i915, phy)) + intel_tc_port_init_mode(dig_port); } static const struct drm_encoder_funcs intel_ddi_funcs = { diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index e5af955b5600..b0aa1edd8302 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -686,19 +686,59 @@ static void intel_tc_port_update_mode(struct intel_digital_port *dig_port, static void intel_tc_port_link_init_refcount(struct intel_digital_port *dig_port, int refcount) +{ + dig_port->tc_link_refcount = refcount; +} + +/** + * intel_tc_port_init_mode: Read out HW state and init the given port's TypeC mode + * @dig_port: digital port + * + * Read out the HW state and initialize the TypeC mode of @dig_port. The mode + * will be locked until intel_tc_port_sanitize_mode() is called. + */ +void intel_tc_port_init_mode(struct intel_digital_port *dig_port) { struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); + intel_wakeref_t tc_cold_wref; + enum intel_display_power_domain domain; + + mutex_lock(&dig_port->tc_lock); + drm_WARN_ON(&i915->drm, dig_port->tc_mode != TC_PORT_DISCONNECTED); + drm_WARN_ON(&i915->drm, dig_port->tc_lock_wakeref); drm_WARN_ON(&i915->drm, dig_port->tc_link_refcount); - dig_port->tc_link_refcount = refcount; + + tc_cold_wref = tc_cold_block(dig_port, &domain); + + dig_port->tc_mode = intel_tc_port_get_current_mode(dig_port); + /* Prevent changing dig_port->tc_mode until intel_tc_port_sanitize_mode() is called. */ + intel_tc_port_link_init_refcount(dig_port, 1); + dig_port->tc_lock_wakeref = tc_cold_block(dig_port, &dig_port->tc_lock_power_domain); + + tc_cold_unblock(dig_port, domain, tc_cold_wref); + + drm_dbg_kms(&i915->drm, "Port %s: init mode (%s)\n", + dig_port->tc_port_name, + tc_port_mode_name(dig_port->tc_mode)); + + mutex_unlock(&dig_port->tc_lock); } -void intel_tc_port_sanitize(struct intel_digital_port *dig_port) +/** + * intel_tc_port_sanitize_mode: Sanitize the given port's TypeC mode + * @dig_port: digital port + * + * Sanitize @dig_port's TypeC mode wrt. the encoder's state right after driver + * loading and system resume: + * If the encoder is enabled keep the TypeC mode/PHY connected state locked until + * the encoder is disabled. + * If the encoder is disabled make sure the PHY is disconnected. + */ +void intel_tc_port_sanitize_mode(struct intel_digital_port *dig_port) { struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); struct intel_encoder *encoder = &dig_port->base; - intel_wakeref_t tc_cold_wref; - enum intel_display_power_domain domain; int active_links = 0; mutex_lock(&dig_port->tc_lock); @@ -708,21 +748,14 @@ void intel_tc_port_sanitize(struct intel_digital_port *dig_port) else if (encoder->base.crtc) active_links = to_intel_crtc(encoder->base.crtc)->active; - drm_WARN_ON(&i915->drm, dig_port->tc_mode != TC_PORT_DISCONNECTED); - drm_WARN_ON(&i915->drm, dig_port->tc_lock_wakeref); - - tc_cold_wref = tc_cold_block(dig_port, &domain); + drm_WARN_ON(&i915->drm, dig_port->tc_link_refcount != 1); + intel_tc_port_link_init_refcount(dig_port, active_links); - dig_port->tc_mode = intel_tc_port_get_current_mode(dig_port); if (active_links) { if (!icl_tc_phy_is_connected(dig_port)) drm_dbg_kms(&i915->drm, "Port %s: PHY disconnected with %d active link(s)\n", dig_port->tc_port_name, active_links); - intel_tc_port_link_init_refcount(dig_port, active_links); - - dig_port->tc_lock_wakeref = tc_cold_block(dig_port, - &dig_port->tc_lock_power_domain); } else { /* * TBT-alt is the default mode in any case the PHY ownership is not @@ -736,9 +769,10 @@ void intel_tc_port_sanitize(struct intel_digital_port *dig_port) dig_port->tc_port_name, tc_port_mode_name(dig_port->tc_mode)); icl_tc_phy_disconnect(dig_port); - } - tc_cold_unblock(dig_port, domain, tc_cold_wref); + tc_cold_unblock(dig_port, dig_port->tc_lock_power_domain, + fetch_and_zero(&dig_port->tc_lock_wakeref)); + } drm_dbg_kms(&i915->drm, "Port %s: sanitize mode (%s)\n", dig_port->tc_port_name, @@ -923,4 +957,6 @@ void intel_tc_port_init(struct intel_digital_port *dig_port, bool is_legacy) dig_port->tc_mode = TC_PORT_DISCONNECTED; dig_port->tc_link_refcount = 0; tc_port_load_fia_params(i915, dig_port); + + intel_tc_port_init_mode(dig_port); } diff --git a/drivers/gpu/drm/i915/display/intel_tc.h b/drivers/gpu/drm/i915/display/intel_tc.h index 6b47b29f551c..d54082e2d5e8 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.h +++ b/drivers/gpu/drm/i915/display/intel_tc.h @@ -24,7 +24,8 @@ int intel_tc_port_fia_max_lane_count(struct intel_digital_port *dig_port); void intel_tc_port_set_fia_lane_count(struct intel_digital_port *dig_port, int required_lanes); -void intel_tc_port_sanitize(struct intel_digital_port *dig_port); +void intel_tc_port_init_mode(struct intel_digital_port *dig_port); +void intel_tc_port_sanitize_mode(struct intel_digital_port *dig_port); void intel_tc_port_lock(struct intel_digital_port *dig_port); void intel_tc_port_unlock(struct intel_digital_port *dig_port); void intel_tc_port_flush_work(struct intel_digital_port *dig_port); -- cgit From 86b972ef1091882d66672399c6f8ebdd12a3b707 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 26 Sep 2022 22:30:21 +0300 Subject: drm/i915: Round to closest in g4x+ HDMI clock readout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On pre-ddi platforms we have slightly different code being used for HDMI TMDS clock to dotclock conversion between the state computation and state readout. Both of these need to round the same way in order to not get a mismatch between the computed and read out states. Fix up the rounding direction in the readout path to match what is used during state computation. Another option would to just use intel_crtc_dotclock() in the readout path as well, but I don't really want to do that as the current code more accurately represents how the hardware really works; The HDMI port register defines whether we're actually outputting 8bpc or 12bpc over HDMI, and the PIPECONF bpc setting just defines what goes over FDI between the CPU and PCH. The fact that we try to cram all that into a single pipe_bpp during state computation is perhaps not entirely great... Fixes: f2c9df101095 ("drm/i915: Round TMDS clock to nearest") Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220926193021.23287-1-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/g4x_hdmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/g4x_hdmi.c b/drivers/gpu/drm/i915/display/g4x_hdmi.c index 5606c667e422..8aadf96fa5e9 100644 --- a/drivers/gpu/drm/i915/display/g4x_hdmi.c +++ b/drivers/gpu/drm/i915/display/g4x_hdmi.c @@ -120,7 +120,7 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder, pipe_config->hw.adjusted_mode.flags |= flags; if ((tmp & SDVO_COLOR_FORMAT_MASK) == HDMI_COLOR_FORMAT_12bpc) - dotclock = pipe_config->port_clock * 2 / 3; + dotclock = DIV_ROUND_CLOSEST(pipe_config->port_clock * 2, 3); else dotclock = pipe_config->port_clock; -- cgit From d24e7855ef7242a045d20af9c2a58474fe238993 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 16 Sep 2022 13:48:23 -0700 Subject: drm/i915/gt: Bump the reset-failure timeout to 60s If attempting to perform a GT reset takes long than 5 seconds (including resetting the display for gen3/4), then we declare all hope lost and discard all user work and wedge the device to prevent further misbehaviour. 5 seconds is too short a time for such drastic action, as we may be stuck on other timeouts and watchdogs. If we allow a little bit longer before hitting the big red button, we should at the very least capture other hung task indicators pointing towards the reason why the reset was hanging; and allow more marginal cases the extra headroom to complete the reset without further collateral damage. Bug: https://gitlab.freedesktop.org/drm/intel/-/issues/6448 Signed-off-by: Chris Wilson Reviewed-by: Matt Roper Signed-off-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20220916204823.1897089-1-ashutosh.dixit@intel.com --- drivers/gpu/drm/i915/gt/intel_reset.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gt/intel_reset.c b/drivers/gpu/drm/i915/gt/intel_reset.c index b36674356986..3159df6cdd49 100644 --- a/drivers/gpu/drm/i915/gt/intel_reset.c +++ b/drivers/gpu/drm/i915/gt/intel_reset.c @@ -1278,7 +1278,7 @@ static void intel_gt_reset_global(struct intel_gt *gt, kobject_uevent_env(kobj, KOBJ_CHANGE, reset_event); /* Use a watchdog to ensure that our reset completes */ - intel_wedge_on_timeout(&w, gt, 5 * HZ) { + intel_wedge_on_timeout(&w, gt, 60 * HZ) { intel_display_prepare_reset(gt->i915); intel_gt_reset(gt, engine_mask, reason); -- cgit From abf46db341bd87261d0b3128bac9bdc204570284 Mon Sep 17 00:00:00 2001 From: Alan Previn Date: Thu, 22 Sep 2022 23:45:42 -0700 Subject: drm/i915/pxp: Add firmware status when ARB session fails Add firmware status using a drm_warn when ARB session fails or else a drm_dbg when the ARB session register slot bit did get set. Signed-off-by: Alan Previn Reviewed-by: Juston Li Signed-off-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20220923064542.415252-2-alan.previn.teres.alexis@intel.com --- drivers/gpu/drm/i915/pxp/intel_pxp_session.c | 1 + drivers/gpu/drm/i915/pxp/intel_pxp_tee.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_session.c b/drivers/gpu/drm/i915/pxp/intel_pxp_session.c index 92b00b4de240..19c330aeb49b 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_session.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_session.c @@ -77,6 +77,7 @@ static int pxp_create_arb_session(struct intel_pxp *pxp) drm_err(>->i915->drm, "arb session failed to go in play\n"); return ret; } + drm_dbg(>->i915->drm, "PXP ARB session is alive\n"); if (!++pxp->key_instance) ++pxp->key_instance; diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c index 4b6f5655fab5..a90905039216 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c @@ -174,6 +174,9 @@ int intel_pxp_tee_cmd_create_arb_session(struct intel_pxp *pxp, if (ret) drm_err(&i915->drm, "Failed to send tee msg ret=[%d]\n", ret); + else if (msg_out.header.status != 0x0) + drm_warn(&i915->drm, "PXP firmware failed arb session init request ret=[0x%08x]\n", + msg_out.header.status); return ret; } -- cgit From 1e88da4f6d8938bef42b3bc6e9c68c795b46ce0f Mon Sep 17 00:00:00 2001 From: John Harrison Date: Thu, 22 Sep 2022 13:12:09 -0700 Subject: drm/i915/guc: Enable compute scheduling on DG2 DG2 has issues. To work around one of these the GuC must schedule apps in an exclusive manner across both RCS and CCS. That is, if a context from app X is running on RCS then all CCS engines must sit idle even if there are contexts from apps Y, Z, ... waiting to run. A certain OS favours RCS to the total starvation of CCS. Linux does not. Hence the GuC now has a scheduling policy setting to control this abitration. Signed-off-by: John Harrison Reviewed-by: Umesh Nerlige Ramappa Link: https://patchwork.freedesktop.org/patch/msgid/20220922201209.1446343-2-John.C.Harrison@Intel.com --- drivers/gpu/drm/i915/gt/uc/abi/guc_actions_abi.h | 1 + drivers/gpu/drm/i915/gt/uc/abi/guc_klvs_abi.h | 9 ++- drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h | 22 ++++++ drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c | 93 +++++++++++++++++++++++ 4 files changed, 124 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gt/uc/abi/guc_actions_abi.h b/drivers/gpu/drm/i915/gt/uc/abi/guc_actions_abi.h index 29ef8afc8c2e..f359bef046e0 100644 --- a/drivers/gpu/drm/i915/gt/uc/abi/guc_actions_abi.h +++ b/drivers/gpu/drm/i915/gt/uc/abi/guc_actions_abi.h @@ -117,6 +117,7 @@ enum intel_guc_action { INTEL_GUC_ACTION_ENTER_S_STATE = 0x501, INTEL_GUC_ACTION_EXIT_S_STATE = 0x502, INTEL_GUC_ACTION_GLOBAL_SCHED_POLICY_CHANGE = 0x506, + INTEL_GUC_ACTION_UPDATE_SCHEDULING_POLICIES_KLV = 0x509, INTEL_GUC_ACTION_SCHED_CONTEXT = 0x1000, INTEL_GUC_ACTION_SCHED_CONTEXT_MODE_SET = 0x1001, INTEL_GUC_ACTION_SCHED_CONTEXT_MODE_DONE = 0x1002, diff --git a/drivers/gpu/drm/i915/gt/uc/abi/guc_klvs_abi.h b/drivers/gpu/drm/i915/gt/uc/abi/guc_klvs_abi.h index 4a59478c3b5c..58012edd4eb0 100644 --- a/drivers/gpu/drm/i915/gt/uc/abi/guc_klvs_abi.h +++ b/drivers/gpu/drm/i915/gt/uc/abi/guc_klvs_abi.h @@ -81,10 +81,17 @@ #define GUC_KLV_SELF_CFG_G2H_CTB_SIZE_KEY 0x0907 #define GUC_KLV_SELF_CFG_G2H_CTB_SIZE_LEN 1u +/* + * Global scheduling policy update keys. + */ +enum { + GUC_SCHEDULING_POLICIES_KLV_ID_RENDER_COMPUTE_YIELD = 0x1001, +}; + /* * Per context scheduling policy update keys. */ -enum { +enum { GUC_CONTEXT_POLICIES_KLV_ID_EXECUTION_QUANTUM = 0x2001, GUC_CONTEXT_POLICIES_KLV_ID_PREEMPTION_TIMEOUT = 0x2002, GUC_CONTEXT_POLICIES_KLV_ID_SCHEDULING_PRIORITY = 0x2003, diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h index 323b055e5db9..e7a7fb450f44 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h @@ -290,6 +290,25 @@ struct guc_update_context_policy { struct guc_klv_generic_dw_t klv[GUC_CONTEXT_POLICIES_KLV_NUM_IDS]; } __packed; +/* Format of the UPDATE_SCHEDULING_POLICIES H2G data packet */ +struct guc_update_scheduling_policy_header { + u32 action; +} __packed; + +/* + * Can't dynmically allocate memory for the scheduling policy KLV because + * it will be sent from within the reset path. Need a fixed size lump on + * the stack instead :(. + * + * Currently, there is only one KLV defined, which has 1 word of KL + 2 words of V. + */ +#define MAX_SCHEDULING_POLICY_SIZE 3 + +struct guc_update_scheduling_policy { + struct guc_update_scheduling_policy_header header; + u32 data[MAX_SCHEDULING_POLICY_SIZE]; +} __packed; + #define GUC_POWER_UNSPECIFIED 0 #define GUC_POWER_D0 1 #define GUC_POWER_D1 2 @@ -298,6 +317,9 @@ struct guc_update_context_policy { /* Scheduling policy settings */ +#define GLOBAL_SCHEDULE_POLICY_RC_YIELD_DURATION 100 /* in ms */ +#define GLOBAL_SCHEDULE_POLICY_RC_YIELD_RATIO 50 /* in percent */ + #define GLOBAL_POLICY_MAX_NUM_WI 15 /* Don't reset an engine upon preemption failure */ diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index ca6f47496869..0ef295a94060 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -4178,6 +4178,98 @@ int intel_guc_submission_setup(struct intel_engine_cs *engine) return 0; } +struct scheduling_policy { + /* internal data */ + u32 max_words, num_words; + u32 count; + /* API data */ + struct guc_update_scheduling_policy h2g; +}; + +static u32 __guc_scheduling_policy_action_size(struct scheduling_policy *policy) +{ + u32 *start = (void *)&policy->h2g; + u32 *end = policy->h2g.data + policy->num_words; + size_t delta = end - start; + + return delta; +} + +static struct scheduling_policy *__guc_scheduling_policy_start_klv(struct scheduling_policy *policy) +{ + policy->h2g.header.action = INTEL_GUC_ACTION_UPDATE_SCHEDULING_POLICIES_KLV; + policy->max_words = ARRAY_SIZE(policy->h2g.data); + policy->num_words = 0; + policy->count = 0; + + return policy; +} + +static void __guc_scheduling_policy_add_klv(struct scheduling_policy *policy, + u32 action, u32 *data, u32 len) +{ + u32 *klv_ptr = policy->h2g.data + policy->num_words; + + GEM_BUG_ON((policy->num_words + 1 + len) > policy->max_words); + *(klv_ptr++) = FIELD_PREP(GUC_KLV_0_KEY, action) | + FIELD_PREP(GUC_KLV_0_LEN, len); + memcpy(klv_ptr, data, sizeof(u32) * len); + policy->num_words += 1 + len; + policy->count++; +} + +static int __guc_action_set_scheduling_policies(struct intel_guc *guc, + struct scheduling_policy *policy) +{ + int ret; + + ret = intel_guc_send(guc, (u32 *)&policy->h2g, + __guc_scheduling_policy_action_size(policy)); + if (ret < 0) + return ret; + + if (ret != policy->count) { + drm_warn(&guc_to_gt(guc)->i915->drm, "GuC global scheduler policy processed %d of %d KLVs!", + ret, policy->count); + if (ret > policy->count) + return -EPROTO; + } + + return 0; +} + +static int guc_init_global_schedule_policy(struct intel_guc *guc) +{ + struct scheduling_policy policy; + struct intel_gt *gt = guc_to_gt(guc); + intel_wakeref_t wakeref; + int ret = 0; + + if (GET_UC_VER(guc) < MAKE_UC_VER(70, 3, 0)) + return 0; + + __guc_scheduling_policy_start_klv(&policy); + + with_intel_runtime_pm(>->i915->runtime_pm, wakeref) { + u32 yield[] = { + GLOBAL_SCHEDULE_POLICY_RC_YIELD_DURATION, + GLOBAL_SCHEDULE_POLICY_RC_YIELD_RATIO, + }; + + __guc_scheduling_policy_add_klv(&policy, + GUC_SCHEDULING_POLICIES_KLV_ID_RENDER_COMPUTE_YIELD, + yield, ARRAY_SIZE(yield)); + + ret = __guc_action_set_scheduling_policies(guc, &policy); + if (ret) + i915_probe_error(gt->i915, + "Failed to configure global scheduling policies: %pe!\n", + ERR_PTR(ret)); + } + + return ret; +} + void intel_guc_submission_enable(struct intel_guc *guc) { struct intel_gt *gt = guc_to_gt(guc); @@ -4190,6 +4282,7 @@ void intel_guc_submission_enable(struct intel_guc *guc) guc_init_lrc_mapping(guc); guc_init_engine_stats(guc); + guc_init_global_schedule_policy(guc); } void intel_guc_submission_disable(struct intel_guc *guc) -- cgit From b801d71493bbb9ec8dd4526bbec41f709621cb97 Mon Sep 17 00:00:00 2001 From: Niranjana Vishwanathapura Date: Tue, 27 Sep 2022 11:13:46 -0700 Subject: drm/i915: Remove unwanted pointer unpacking In await_fence_array(), unpacking syncobj pointer is not needed. Remove it. Reviewed-by: Tvrtko Ursulin Signed-off-by: Niranjana Vishwanathapura Signed-off-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20220927181346.1187-1-niranjana.vishwanathapura@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c index b7b2c14fd9e1..d38aa74b3814 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c @@ -2955,11 +2955,6 @@ await_fence_array(struct i915_execbuffer *eb, int err; for (n = 0; n < eb->num_fences; n++) { - struct drm_syncobj *syncobj; - unsigned int flags; - - syncobj = ptr_unpack_bits(eb->fences[n].syncobj, &flags, 2); - if (!eb->fences[n].dma_fence) continue; -- cgit From eb89e83c152b122a94e79527d63cb7c79823c37e Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 27 Sep 2022 21:06:13 +0300 Subject: drm/i915: Simplify intel_panel_add_edid_alt_fixed_modes() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit a5810f551d0a ("drm/i915: Allow more varied alternate fixed modes for panels") intel_panel_add_edid_alt_fixed_modes() no longer considers vrr vs. drrs separately. So no reason to pass them as separate parameters either. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220927180615.25476-2-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_dp.c | 2 +- drivers/gpu/drm/i915/display/intel_lvds.c | 3 +-- drivers/gpu/drm/i915/display/intel_panel.c | 4 ++-- drivers/gpu/drm/i915/display/intel_panel.h | 2 +- drivers/gpu/drm/i915/display/intel_sdvo.c | 2 +- 5 files changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 6ebd6e104b2c..c368caa23291 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -5293,7 +5293,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, encoder->devdata, IS_ERR(edid) ? NULL : edid); intel_panel_add_edid_fixed_modes(intel_connector, - intel_connector->panel.vbt.drrs_type != DRRS_TYPE_NONE, + intel_connector->panel.vbt.drrs_type != DRRS_TYPE_NONE || intel_vrr_is_capable(intel_connector)); /* MSO requires information from the EDID */ diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c index 270368b43729..e6600d2f369b 100644 --- a/drivers/gpu/drm/i915/display/intel_lvds.c +++ b/drivers/gpu/drm/i915/display/intel_lvds.c @@ -969,8 +969,7 @@ void intel_lvds_init(struct drm_i915_private *dev_priv) /* Try EDID first */ intel_panel_add_edid_fixed_modes(intel_connector, - intel_connector->panel.vbt.drrs_type != DRRS_TYPE_NONE, - false); + intel_connector->panel.vbt.drrs_type != DRRS_TYPE_NONE); /* Failed to get EDID, what about VBT? */ if (!intel_panel_preferred_fixed_mode(intel_connector)) diff --git a/drivers/gpu/drm/i915/display/intel_panel.c b/drivers/gpu/drm/i915/display/intel_panel.c index a3a3f9fe4342..41cec9dc4223 100644 --- a/drivers/gpu/drm/i915/display/intel_panel.c +++ b/drivers/gpu/drm/i915/display/intel_panel.c @@ -254,10 +254,10 @@ static void intel_panel_destroy_probed_modes(struct intel_connector *connector) } void intel_panel_add_edid_fixed_modes(struct intel_connector *connector, - bool has_drrs, bool has_vrr) + bool use_alt_fixed_modes) { intel_panel_add_edid_preferred_mode(connector); - if (intel_panel_preferred_fixed_mode(connector) && (has_drrs || has_vrr)) + if (intel_panel_preferred_fixed_mode(connector) && use_alt_fixed_modes) intel_panel_add_edid_alt_fixed_modes(connector); intel_panel_destroy_probed_modes(connector); } diff --git a/drivers/gpu/drm/i915/display/intel_panel.h b/drivers/gpu/drm/i915/display/intel_panel.h index eff3ffd3d082..5c5b5b7f95b6 100644 --- a/drivers/gpu/drm/i915/display/intel_panel.h +++ b/drivers/gpu/drm/i915/display/intel_panel.h @@ -44,7 +44,7 @@ int intel_panel_fitting(struct intel_crtc_state *crtc_state, int intel_panel_compute_config(struct intel_connector *connector, struct drm_display_mode *adjusted_mode); void intel_panel_add_edid_fixed_modes(struct intel_connector *connector, - bool has_drrs, bool has_vrr); + bool use_alt_fixed_modes); void intel_panel_add_vbt_lfp_fixed_mode(struct intel_connector *connector); void intel_panel_add_vbt_sdvo_fixed_mode(struct intel_connector *connector); void intel_panel_add_encoder_fixed_mode(struct intel_connector *connector, diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c index 2a99ec7ff737..cf8e80936d8e 100644 --- a/drivers/gpu/drm/i915/display/intel_sdvo.c +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c @@ -2910,7 +2910,7 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device) if (!intel_panel_preferred_fixed_mode(intel_connector)) { intel_ddc_get_modes(connector, &intel_sdvo->ddc); - intel_panel_add_edid_fixed_modes(intel_connector, false, false); + intel_panel_add_edid_fixed_modes(intel_connector, false); } intel_panel_init(intel_connector); -- cgit From 55cfeecc2197de68e9cc30f77c711dcbcdf27510 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 27 Sep 2022 21:06:14 +0300 Subject: drm/i915: Allow alternate fixed modes always for eDP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stop considering VBT's static DRRS support when deciding whether to use alternate fixed modes or not. It looks like Windows more or less just uses that to decide whether to automagically switch refresh rates on AC<->battery changes, or perhaps whether to even expose a control for that in some UI thing. Either way it seems happy to always use all EDID modes, and I guess the DRRS/VRR stuff more or less adjusts how said modes get actually used. Let's do the same and just accept all the suitable looking modes from EDID, whether we have DRRS or VRR. Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/6323 Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/6484 Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220927180615.25476-3-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_dp.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index c368caa23291..70b06806ec0d 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -5292,9 +5292,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, intel_bios_init_panel(dev_priv, &intel_connector->panel, encoder->devdata, IS_ERR(edid) ? NULL : edid); - intel_panel_add_edid_fixed_modes(intel_connector, - intel_connector->panel.vbt.drrs_type != DRRS_TYPE_NONE || - intel_vrr_is_capable(intel_connector)); + intel_panel_add_edid_fixed_modes(intel_connector, true); /* MSO requires information from the EDID */ intel_edp_mso_init(intel_dp); -- cgit From 3dbf20e483cf3f31e287ad3152ffadd15a482e4f Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 27 Sep 2022 21:06:15 +0300 Subject: drm/i915: Allow alternate fixed modes always for LVDS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As with eDP let's stop considering the VBTs DRRS knobs and just always accept all otherwise suitable EDID modes. This appears to be how Windows does it. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220927180615.25476-4-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_lvds.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c index e6600d2f369b..e97e24f690a9 100644 --- a/drivers/gpu/drm/i915/display/intel_lvds.c +++ b/drivers/gpu/drm/i915/display/intel_lvds.c @@ -968,8 +968,7 @@ void intel_lvds_init(struct drm_i915_private *dev_priv) IS_ERR(edid) ? NULL : edid); /* Try EDID first */ - intel_panel_add_edid_fixed_modes(intel_connector, - intel_connector->panel.vbt.drrs_type != DRRS_TYPE_NONE); + intel_panel_add_edid_fixed_modes(intel_connector, true); /* Failed to get EDID, what about VBT? */ if (!intel_panel_preferred_fixed_mode(intel_connector)) -- cgit From c09ae4edd11062cd147328c77926330596277097 Mon Sep 17 00:00:00 2001 From: Riana Tauro Date: Fri, 23 Sep 2022 16:30:41 +0530 Subject: drm/i915/guc/slpc: Run SLPC selftests on all tiles Run slpc selftests on all tiles Signed-off-by: Riana Tauro Reviewed-by: Vinay Belgaumkar Signed-off-by: Anshuman Gupta Link: https://patchwork.freedesktop.org/patch/msgid/20220923110043.789178-2-riana.tauro@intel.com --- drivers/gpu/drm/i915/gt/selftest_slpc.c | 45 +++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/selftest_slpc.c b/drivers/gpu/drm/i915/gt/selftest_slpc.c index f8a1d27df272..928f74718881 100644 --- a/drivers/gpu/drm/i915/gt/selftest_slpc.c +++ b/drivers/gpu/drm/i915/gt/selftest_slpc.c @@ -270,26 +270,50 @@ static int run_test(struct intel_gt *gt, int test_type) static int live_slpc_vary_min(void *arg) { struct drm_i915_private *i915 = arg; - struct intel_gt *gt = to_gt(i915); + struct intel_gt *gt; + unsigned int i; + int ret; + + for_each_gt(gt, i915, i) { + ret = run_test(gt, VARY_MIN); + if (ret) + return ret; + } - return run_test(gt, VARY_MIN); + return ret; } static int live_slpc_vary_max(void *arg) { struct drm_i915_private *i915 = arg; - struct intel_gt *gt = to_gt(i915); + struct intel_gt *gt; + unsigned int i; + int ret; + + for_each_gt(gt, i915, i) { + ret = run_test(gt, VARY_MAX); + if (ret) + return ret; + } - return run_test(gt, VARY_MAX); + return ret; } /* check if pcode can grant RP0 */ static int live_slpc_max_granted(void *arg) { struct drm_i915_private *i915 = arg; - struct intel_gt *gt = to_gt(i915); + struct intel_gt *gt; + unsigned int i; + int ret; + + for_each_gt(gt, i915, i) { + ret = run_test(gt, MAX_GRANTED); + if (ret) + return ret; + } - return run_test(gt, MAX_GRANTED); + return ret; } int intel_slpc_live_selftests(struct drm_i915_private *i915) @@ -300,8 +324,13 @@ int intel_slpc_live_selftests(struct drm_i915_private *i915) SUBTEST(live_slpc_max_granted), }; - if (intel_gt_is_wedged(to_gt(i915))) - return 0; + struct intel_gt *gt; + unsigned int i; + + for_each_gt(gt, i915, i) { + if (intel_gt_is_wedged(gt)) + return 0; + } return i915_live_subtests(tests, i915); } -- cgit From ac4e8560248f8c33c11b96a05ad64cfd1eb39665 Mon Sep 17 00:00:00 2001 From: Riana Tauro Date: Fri, 23 Sep 2022 16:30:42 +0530 Subject: drm/i915/selftests: Add helper function measure_power move the power measurement and the triangle filter to a different function. No functional changes. Signed-off-by: Riana Tauro Reviewed-by: Vinay Belgaumkar Signed-off-by: Anshuman Gupta Link: https://patchwork.freedesktop.org/patch/msgid/20220923110043.789178-3-riana.tauro@intel.com --- drivers/gpu/drm/i915/gt/selftest_rps.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/selftest_rps.c b/drivers/gpu/drm/i915/gt/selftest_rps.c index cfb4708dd62e..99a372486fb7 100644 --- a/drivers/gpu/drm/i915/gt/selftest_rps.c +++ b/drivers/gpu/drm/i915/gt/selftest_rps.c @@ -1107,21 +1107,27 @@ static u64 __measure_power(int duration_ms) return div64_u64(1000 * 1000 * dE, dt); } -static u64 measure_power_at(struct intel_rps *rps, int *freq) +static u64 measure_power(struct intel_rps *rps, int *freq) { u64 x[5]; int i; - *freq = rps_set_check(rps, *freq); for (i = 0; i < 5; i++) x[i] = __measure_power(5); - *freq = (*freq + read_cagf(rps)) / 2; + + *freq = (*freq + intel_rps_read_actual_frequency(rps)) / 2; /* A simple triangle filter for better result stability */ sort(x, 5, sizeof(*x), cmp_u64, NULL); return div_u64(x[1] + 2 * x[2] + x[3], 4); } +static u64 measure_power_at(struct intel_rps *rps, int *freq) +{ + *freq = rps_set_check(rps, *freq); + return measure_power(rps, freq); +} + int live_rps_power(void *arg) { struct intel_gt *gt = arg; -- cgit From 59cfc750f537b973e17583ce8f14a913401a5ac0 Mon Sep 17 00:00:00 2001 From: Riana Tauro Date: Fri, 23 Sep 2022 16:30:43 +0530 Subject: drm/i915/guc/slpc: Add SLPC selftest live_slpc_power A fundamental assumption is that at lower frequencies, not only do we run slower, but we save power compared to higher frequencies. live_slpc_power checks if running at low frequency saves power v2: re-use code to measure power fixed cosmetic review comments (Vinay) Signed-off-by: Riana Tauro Reviewed-by: Vinay Belgaumkar Signed-off-by: Anshuman Gupta Link: https://patchwork.freedesktop.org/patch/msgid/20220923110043.789178-4-riana.tauro@intel.com --- drivers/gpu/drm/i915/gt/selftest_slpc.c | 127 +++++++++++++++++++++++++++++--- 1 file changed, 118 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/selftest_slpc.c b/drivers/gpu/drm/i915/gt/selftest_slpc.c index 928f74718881..4c6e9257e593 100644 --- a/drivers/gpu/drm/i915/gt/selftest_slpc.c +++ b/drivers/gpu/drm/i915/gt/selftest_slpc.c @@ -11,7 +11,8 @@ enum test_type { VARY_MIN, VARY_MAX, - MAX_GRANTED + MAX_GRANTED, + SLPC_POWER, }; static int slpc_set_min_freq(struct intel_guc_slpc *slpc, u32 freq) @@ -41,6 +42,39 @@ static int slpc_set_max_freq(struct intel_guc_slpc *slpc, u32 freq) return ret; } +static int slpc_set_freq(struct intel_gt *gt, u32 freq) +{ + int err; + struct intel_guc_slpc *slpc = >->uc.guc.slpc; + + err = slpc_set_max_freq(slpc, freq); + if (err) { + pr_err("Unable to update max freq"); + return err; + } + + err = slpc_set_min_freq(slpc, freq); + if (err) { + pr_err("Unable to update min freq"); + return err; + } + + return err; +} + +static u64 measure_power_at_freq(struct intel_gt *gt, int *freq, u64 *power) +{ + int err = 0; + + err = slpc_set_freq(gt, *freq); + if (err) + return err; + *freq = intel_rps_read_actual_frequency(>->rps); + *power = measure_power(>->rps, freq); + + return err; +} + static int vary_max_freq(struct intel_guc_slpc *slpc, struct intel_rps *rps, u32 *max_act_freq) { @@ -113,6 +147,58 @@ static int vary_min_freq(struct intel_guc_slpc *slpc, struct intel_rps *rps, return err; } +static int slpc_power(struct intel_gt *gt, struct intel_engine_cs *engine) +{ + struct intel_guc_slpc *slpc = >->uc.guc.slpc; + struct { + u64 power; + int freq; + } min, max; + int err = 0; + + /* + * Our fundamental assumption is that running at lower frequency + * actually saves power. Let's see if our RAPL measurement supports + * that theory. + */ + if (!librapl_supported(gt->i915)) + return 0; + + min.freq = slpc->min_freq; + err = measure_power_at_freq(gt, &min.freq, &min.power); + + if (err) + return err; + + max.freq = slpc->rp0_freq; + err = measure_power_at_freq(gt, &max.freq, &max.power); + + if (err) + return err; + + pr_info("%s: min:%llumW @ %uMHz, max:%llumW @ %uMHz\n", + engine->name, + min.power, min.freq, + max.power, max.freq); + + if (10 * min.freq >= 9 * max.freq) { + pr_notice("Could not control frequency, ran at [%uMHz, %uMhz]\n", + min.freq, max.freq); + } + + if (11 * min.power > 10 * max.power) { + pr_err("%s: did not conserve power when setting lower frequency!\n", + engine->name); + err = -EINVAL; + } + + /* Restore min/max frequencies */ + slpc_set_max_freq(slpc, slpc->rp0_freq); + slpc_set_min_freq(slpc, slpc->min_freq); + + return err; +} + static int max_granted_freq(struct intel_guc_slpc *slpc, struct intel_rps *rps, u32 *max_act_freq) { struct intel_gt *gt = rps_to_gt(rps); @@ -233,17 +319,23 @@ static int run_test(struct intel_gt *gt, int test_type) err = max_granted_freq(slpc, rps, &max_act_freq); break; + + case SLPC_POWER: + err = slpc_power(gt, engine); + break; } - pr_info("Max actual frequency for %s was %d\n", - engine->name, max_act_freq); + if (test_type != SLPC_POWER) { + pr_info("Max actual frequency for %s was %d\n", + engine->name, max_act_freq); - /* Actual frequency should rise above min */ - if (max_act_freq <= slpc_min_freq) { - pr_err("Actual freq did not rise above min\n"); - pr_err("Perf Limit Reasons: 0x%x\n", - intel_uncore_read(gt->uncore, GT0_PERF_LIMIT_REASONS)); - err = -EINVAL; + /* Actual frequency should rise above min */ + if (max_act_freq <= slpc_min_freq) { + pr_err("Actual freq did not rise above min\n"); + pr_err("Perf Limit Reasons: 0x%x\n", + intel_uncore_read(gt->uncore, GT0_PERF_LIMIT_REASONS)); + err = -EINVAL; + } } igt_spinner_end(&spin); @@ -316,12 +408,29 @@ static int live_slpc_max_granted(void *arg) return ret; } +static int live_slpc_power(void *arg) +{ + struct drm_i915_private *i915 = arg; + struct intel_gt *gt; + unsigned int i; + int ret; + + for_each_gt(gt, i915, i) { + ret = run_test(gt, SLPC_POWER); + if (ret) + return ret; + } + + return ret; +} + int intel_slpc_live_selftests(struct drm_i915_private *i915) { static const struct i915_subtest tests[] = { SUBTEST(live_slpc_vary_max), SUBTEST(live_slpc_vary_min), SUBTEST(live_slpc_max_granted), + SUBTEST(live_slpc_power), }; struct intel_gt *gt; -- cgit From c50cec9bab620927445e9c7c050a8fae536557b8 Mon Sep 17 00:00:00 2001 From: Nirmoy Das Date: Fri, 23 Sep 2022 09:35:14 +0200 Subject: drm/i915: Fix a potential UAF at device unload i915_gem_drain_freed_objects() might not be enough to free all the objects and RCU delayed work might get scheduled after the i915 device struct gets freed. Call i915_gem_drain_workqueue() to catch all RCU delayed work. Suggested-by: Chris Wilson Acked-by: Tvrtko Ursulin Signed-off-by: Nirmoy Das Reviewed-by: Andrzej Hajda Signed-off-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20220923073515.23093-1-nirmoy.das@intel.com --- drivers/gpu/drm/i915/i915_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 4539431a3c3e..366169e5be73 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1242,7 +1242,7 @@ void i915_gem_init_early(struct drm_i915_private *dev_priv) void i915_gem_cleanup_early(struct drm_i915_private *dev_priv) { - i915_gem_drain_freed_objects(dev_priv); + i915_gem_drain_workqueue(dev_priv); GEM_BUG_ON(!llist_empty(&dev_priv->mm.free_list)); GEM_BUG_ON(atomic_read(&dev_priv->mm.free_count)); drm_WARN_ON(&dev_priv->drm, dev_priv->mm.shrink_count); -- cgit From da3dbdfea49cbaef41f37a566470b27df3e0e9ab Mon Sep 17 00:00:00 2001 From: Nirmoy Das Date: Fri, 23 Sep 2022 09:35:15 +0200 Subject: drm/i915: remove excessive i915_gem_drain_freed_objects i915_gem_drain_workqueue() call i915_gem_drain_freed_objects() so no need to call that again. Reviewed-by: Tvrtko Ursulin Signed-off-by: Nirmoy Das Reviewed-by: Andrzej Hajda Signed-off-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20220923073515.23093-2-nirmoy.das@intel.com --- drivers/gpu/drm/i915/i915_gem.c | 2 -- drivers/gpu/drm/i915/selftests/mock_gem_device.c | 1 - 2 files changed, 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 366169e5be73..b37daf9d4bd0 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1200,8 +1200,6 @@ void i915_gem_driver_remove(struct drm_i915_private *dev_priv) /* Flush any outstanding unpin_work. */ i915_gem_drain_workqueue(dev_priv); - - i915_gem_drain_freed_objects(dev_priv); } void i915_gem_driver_release(struct drm_i915_private *dev_priv) diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_device.c b/drivers/gpu/drm/i915/selftests/mock_gem_device.c index 8cd51cea77f0..85b1beea81cf 100644 --- a/drivers/gpu/drm/i915/selftests/mock_gem_device.c +++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.c @@ -67,7 +67,6 @@ static void mock_device_release(struct drm_device *dev) intel_gt_driver_remove(to_gt(i915)); i915_gem_drain_workqueue(i915); - i915_gem_drain_freed_objects(i915); mock_fini_ggtt(to_gt(i915)->ggtt); destroy_workqueue(i915->wq); -- cgit From e26ec8aebfbbb38cb3733d64b793e5c0085cbcee Mon Sep 17 00:00:00 2001 From: Prathap Kumar Valsan Date: Tue, 27 Sep 2022 19:13:13 +0200 Subject: drm/i915/gt: Flush to global observation point before breadcrumb write Add flag to pipecontrol instruction to ensure in-flight writes are flushed to global observation point. Also split the pipecontrol instruction like we have in gen8. References: https://gitlab.freedesktop.org/drm/intel/-/issues/5886 Signed-off-by: Prathap Kumar Valsan Signed-off-by: Nirmoy Das Reviewed-by: Andi Shyti Signed-off-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20220927171313.6553-1-nirmoy.das@intel.com --- drivers/gpu/drm/i915/gt/gen8_engine_cs.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/gen8_engine_cs.c b/drivers/gpu/drm/i915/gt/gen8_engine_cs.c index e49fa6fa6aee..31a2fbd8c4a8 100644 --- a/drivers/gpu/drm/i915/gt/gen8_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/gen8_engine_cs.c @@ -583,6 +583,8 @@ u32 *gen8_emit_fini_breadcrumb_xcs(struct i915_request *rq, u32 *cs) u32 *gen8_emit_fini_breadcrumb_rcs(struct i915_request *rq, u32 *cs) { cs = gen8_emit_pipe_control(cs, + PIPE_CONTROL_CS_STALL | + PIPE_CONTROL_TLB_INVALIDATE | PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH | PIPE_CONTROL_DEPTH_CACHE_FLUSH | PIPE_CONTROL_DC_FLUSH_ENABLE, @@ -600,15 +602,21 @@ u32 *gen8_emit_fini_breadcrumb_rcs(struct i915_request *rq, u32 *cs) u32 *gen11_emit_fini_breadcrumb_rcs(struct i915_request *rq, u32 *cs) { + cs = gen8_emit_pipe_control(cs, + PIPE_CONTROL_CS_STALL | + PIPE_CONTROL_TLB_INVALIDATE | + PIPE_CONTROL_TILE_CACHE_FLUSH | + PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH | + PIPE_CONTROL_DEPTH_CACHE_FLUSH | + PIPE_CONTROL_DC_FLUSH_ENABLE, + 0); + + /*XXX: Look at gen8_emit_fini_breadcrumb_rcs */ cs = gen8_emit_ggtt_write_rcs(cs, rq->fence.seqno, hwsp_offset(rq), - PIPE_CONTROL_CS_STALL | - PIPE_CONTROL_TILE_CACHE_FLUSH | - PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH | - PIPE_CONTROL_DEPTH_CACHE_FLUSH | - PIPE_CONTROL_DC_FLUSH_ENABLE | - PIPE_CONTROL_FLUSH_ENABLE); + PIPE_CONTROL_FLUSH_ENABLE | + PIPE_CONTROL_CS_STALL); return gen8_emit_fini_breadcrumb_tail(rq, cs); } @@ -715,6 +723,7 @@ u32 *gen12_emit_fini_breadcrumb_rcs(struct i915_request *rq, u32 *cs) { struct drm_i915_private *i915 = rq->engine->i915; u32 flags = (PIPE_CONTROL_CS_STALL | + PIPE_CONTROL_TLB_INVALIDATE | PIPE_CONTROL_TILE_CACHE_FLUSH | PIPE_CONTROL_FLUSH_L3 | PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH | @@ -731,11 +740,15 @@ u32 *gen12_emit_fini_breadcrumb_rcs(struct i915_request *rq, u32 *cs) else if (rq->engine->class == COMPUTE_CLASS) flags &= ~PIPE_CONTROL_3D_ENGINE_FLAGS; + cs = gen12_emit_pipe_control(cs, PIPE_CONTROL0_HDC_PIPELINE_FLUSH, flags, 0); + + /*XXX: Look at gen8_emit_fini_breadcrumb_rcs */ cs = gen12_emit_ggtt_write_rcs(cs, rq->fence.seqno, hwsp_offset(rq), - PIPE_CONTROL0_HDC_PIPELINE_FLUSH, - flags); + 0, + PIPE_CONTROL_FLUSH_ENABLE | + PIPE_CONTROL_CS_STALL); return gen12_emit_fini_breadcrumb_tail(rq, cs); } -- cgit From 0d0e7d1eea9e7379b8709a71283eaadd94af37ca Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Wed, 28 Sep 2022 08:55:11 -0700 Subject: drm/i915/mtl: Define engine context layouts The part of the media and blitter engine contexts that we care about for setting up an initial state on MTL are nearly similar to DG2 (and PVC). The difference being PRT_BB_STATE being replaced with NOP. For render/compute engines, the part of the context images are nearly the same, although the layout had a very slight change --- one POSH register was removed and the placement of some LRI/noops adjusted slightly to compensate. v2: - Dg2, mtl xcs offsets slightly vary. Use a separate offsets array(Bala) - Add missing nop in xcs offsets(Bala) v3: - Fix the spacing for nop in xcs offset(MattR) v4: - Fix rcs register offset(MattR) v4.1: - Fix commit message(Lucas) Bspec: 46261, 46260, 45585 Cc: Balasubramani Vivekanandan Cc: Licas De Marchi Signed-off-by: Matt Roper Signed-off-by: Radhakrishna Sripada Reviewed-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20220928155511.2379663-1-radhakrishna.sripada@intel.com --- drivers/gpu/drm/i915/gt/intel_lrc.c | 84 ++++++++++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.c b/drivers/gpu/drm/i915/gt/intel_lrc.c index 82d899f170fb..e84ef3859934 100644 --- a/drivers/gpu/drm/i915/gt/intel_lrc.c +++ b/drivers/gpu/drm/i915/gt/intel_lrc.c @@ -264,6 +264,39 @@ static const u8 dg2_xcs_offsets[] = { END }; +static const u8 mtl_xcs_offsets[] = { + NOP(1), + LRI(13, POSTED), + REG16(0x244), + REG(0x034), + REG(0x030), + REG(0x038), + REG(0x03c), + REG(0x168), + REG(0x140), + REG(0x110), + REG(0x1c0), + REG(0x1c4), + REG(0x1c8), + REG(0x180), + REG16(0x2b4), + NOP(4), + + NOP(1), + LRI(9, POSTED), + REG16(0x3a8), + REG16(0x28c), + REG16(0x288), + REG16(0x284), + REG16(0x280), + REG16(0x27c), + REG16(0x278), + REG16(0x274), + REG16(0x270), + + END +}; + static const u8 gen8_rcs_offsets[] = { NOP(1), LRI(14, POSTED), @@ -606,6 +639,49 @@ static const u8 dg2_rcs_offsets[] = { END }; +static const u8 mtl_rcs_offsets[] = { + NOP(1), + LRI(15, POSTED), + REG16(0x244), + REG(0x034), + REG(0x030), + REG(0x038), + REG(0x03c), + REG(0x168), + REG(0x140), + REG(0x110), + REG(0x1c0), + REG(0x1c4), + REG(0x1c8), + REG(0x180), + REG16(0x2b4), + REG(0x120), + REG(0x124), + + NOP(1), + LRI(9, POSTED), + REG16(0x3a8), + REG16(0x28c), + REG16(0x288), + REG16(0x284), + REG16(0x280), + REG16(0x27c), + REG16(0x278), + REG16(0x274), + REG16(0x270), + + NOP(2), + LRI(2, POSTED), + REG16(0x5a8), + REG16(0x5ac), + + NOP(6), + LRI(1, 0), + REG(0x0c8), + + END +}; + #undef END #undef REG16 #undef REG @@ -624,7 +700,9 @@ static const u8 *reg_offsets(const struct intel_engine_cs *engine) !intel_engine_has_relative_mmio(engine)); if (engine->flags & I915_ENGINE_HAS_RCS_REG_STATE) { - if (GRAPHICS_VER_FULL(engine->i915) >= IP_VER(12, 55)) + if (GRAPHICS_VER_FULL(engine->i915) >= IP_VER(12, 70)) + return mtl_rcs_offsets; + else if (GRAPHICS_VER_FULL(engine->i915) >= IP_VER(12, 55)) return dg2_rcs_offsets; else if (GRAPHICS_VER_FULL(engine->i915) >= IP_VER(12, 50)) return xehp_rcs_offsets; @@ -637,7 +715,9 @@ static const u8 *reg_offsets(const struct intel_engine_cs *engine) else return gen8_rcs_offsets; } else { - if (GRAPHICS_VER_FULL(engine->i915) >= IP_VER(12, 55)) + if (GRAPHICS_VER_FULL(engine->i915) >= IP_VER(12, 70)) + return mtl_xcs_offsets; + else if (GRAPHICS_VER_FULL(engine->i915) >= IP_VER(12, 55)) return dg2_xcs_offsets; else if (GRAPHICS_VER(engine->i915) >= 12) return gen12_xcs_offsets; -- cgit From 319b0869f51c16034c48627d77ec62fc3b9dccfe Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 29 Sep 2022 10:15:12 +0300 Subject: drm/i915: Remove PLL asserts from .load_luts() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit .load_luts() potentially runs from the vblank worker, and is under a deadline to complete within the vblank. Thus we can't do expesive stuff like talk to the Punit, etc. To that end get rid of the assert_dsi_pll_enabled() call for vlv/chv. We'll just have to trust that the PLL is already enabled here. And I don't think the normal assert_pll_enabled() really buys us anything useful on gmch platforms either, so nuke that one too. We don't have corresponding asserts in the ilk+ codepaths anyway despite the hardware (IIRC) still requiring the clock to be enabled when we access the LUT. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220929071521.26612-2-ville.syrjala@linux.intel.com Acked-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_color.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index 6bda4274eae9..bbc56affb3ec 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -25,9 +25,7 @@ #include "intel_color.h" #include "intel_de.h" #include "intel_display_types.h" -#include "intel_dpll.h" #include "intel_dsb.h" -#include "vlv_dsi_pll.h" struct intel_color_funcs { int (*color_check)(struct intel_crtc_state *crtc_state); @@ -580,11 +578,8 @@ static void i9xx_load_lut_8(struct intel_crtc *crtc, static void i9xx_load_luts(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut; - assert_pll_enabled(dev_priv, crtc->pipe); - i9xx_load_lut_8(crtc, gamma_lut); } @@ -611,14 +606,8 @@ static void i965_load_lut_10p6(struct intel_crtc *crtc, static void i965_load_luts(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut; - if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI)) - assert_dsi_pll_enabled(dev_priv); - else - assert_pll_enabled(dev_priv, crtc->pipe); - if (crtc_state->gamma_mode == GAMMA_MODE_MODE_8BIT) i9xx_load_lut_8(crtc, gamma_lut); else -- cgit From 064751a6c5dc719d28a490268f140d4d9cf379d4 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 29 Sep 2022 10:15:13 +0300 Subject: drm/i915: Split up intel_color_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit intel_color_init() does both device level and crtc level stuff. Split it up accordingly. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220929071521.26612-3-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_color.c | 15 +++++++++------ drivers/gpu/drm/i915/display/intel_color.h | 4 +++- drivers/gpu/drm/i915/display/intel_crtc.c | 3 +-- drivers/gpu/drm/i915/display/intel_display.c | 1 + 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index bbc56affb3ec..ddfe7c257a72 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -2206,13 +2206,21 @@ static const struct intel_color_funcs ilk_color_funcs = { .read_luts = ilk_read_luts, }; -void intel_color_init(struct intel_crtc *crtc) +void intel_crtc_color_init(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); bool has_ctm = INTEL_INFO(dev_priv)->display.color.degamma_lut_size != 0; drm_mode_crtc_set_gamma_size(&crtc->base, 256); + drm_crtc_enable_color_mgmt(&crtc->base, + INTEL_INFO(dev_priv)->display.color.degamma_lut_size, + has_ctm, + INTEL_INFO(dev_priv)->display.color.gamma_lut_size); +} + +void intel_color_init_hooks(struct drm_i915_private *dev_priv) +{ if (HAS_GMCH(dev_priv)) { if (IS_CHERRYVIEW(dev_priv)) { dev_priv->display.funcs.color = &chv_color_funcs; @@ -2238,9 +2246,4 @@ void intel_color_init(struct intel_crtc *crtc) } else dev_priv->display.funcs.color = &ilk_color_funcs; } - - drm_crtc_enable_color_mgmt(&crtc->base, - INTEL_INFO(dev_priv)->display.color.degamma_lut_size, - has_ctm, - INTEL_INFO(dev_priv)->display.color.gamma_lut_size); } diff --git a/drivers/gpu/drm/i915/display/intel_color.h b/drivers/gpu/drm/i915/display/intel_color.h index fd873425e082..67702451e2fd 100644 --- a/drivers/gpu/drm/i915/display/intel_color.h +++ b/drivers/gpu/drm/i915/display/intel_color.h @@ -10,9 +10,11 @@ struct intel_crtc_state; struct intel_crtc; +struct drm_i915_private; struct drm_property_blob; -void intel_color_init(struct intel_crtc *crtc); +void intel_color_init_hooks(struct drm_i915_private *i915); +void intel_crtc_color_init(struct intel_crtc *crtc); int intel_color_check(struct intel_crtc_state *crtc_state); void intel_color_commit_noarm(const struct intel_crtc_state *crtc_state); void intel_color_commit_arm(const struct intel_crtc_state *crtc_state); diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c index 6792a9056f46..2d9fc7383bfc 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc.c +++ b/drivers/gpu/drm/i915/display/intel_crtc.c @@ -365,8 +365,7 @@ int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe) BIT(DRM_SCALING_FILTER_DEFAULT) | BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR)); - intel_color_init(crtc); - + intel_crtc_color_init(crtc); intel_crtc_drrs_init(crtc); intel_crtc_crc_init(crtc); diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 3f72d0cd6d1e..4bcba618242d 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -8326,6 +8326,7 @@ void intel_init_display_hooks(struct drm_i915_private *dev_priv) if (!HAS_DISPLAY(dev_priv)) return; + intel_color_init_hooks(dev_priv); intel_init_cdclk_hooks(dev_priv); intel_audio_hooks_init(dev_priv); -- cgit From 2a40e5848a9526c3ad5d35e1aab4c04df117693b Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 29 Sep 2022 10:15:14 +0300 Subject: drm/i915: Simplify the intel_color_init_hooks() if ladder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Get rid of the funny hsw vs. ivb extra indentation level in intel_color_init_hooks(). Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220929071521.26612-4-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_color.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index ddfe7c257a72..ce8a4be9b292 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -2238,12 +2238,11 @@ void intel_color_init_hooks(struct drm_i915_private *dev_priv) dev_priv->display.funcs.color = &skl_color_funcs; else if (DISPLAY_VER(dev_priv) == 8) dev_priv->display.funcs.color = &bdw_color_funcs; - else if (DISPLAY_VER(dev_priv) == 7) { - if (IS_HASWELL(dev_priv)) - dev_priv->display.funcs.color = &hsw_color_funcs; - else - dev_priv->display.funcs.color = &ivb_color_funcs; - } else + else if (IS_HASWELL(dev_priv)) + dev_priv->display.funcs.color = &hsw_color_funcs; + else if (DISPLAY_VER(dev_priv) == 7) + dev_priv->display.funcs.color = &ivb_color_funcs; + else dev_priv->display.funcs.color = &ilk_color_funcs; } } -- cgit From 7671fc6265266abcbefcef4527ded35b48ba07ea Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 29 Sep 2022 10:15:15 +0300 Subject: drm/i915: Clean up intel_color_init_hooks() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove a bunch of pointless curly brackets and do the s/dev_priv/i915/ while at it. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220929071521.26612-5-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_color.c | 43 +++++++++++++++--------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index ce8a4be9b292..96687ec30b19 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -2219,30 +2219,29 @@ void intel_crtc_color_init(struct intel_crtc *crtc) INTEL_INFO(dev_priv)->display.color.gamma_lut_size); } -void intel_color_init_hooks(struct drm_i915_private *dev_priv) +void intel_color_init_hooks(struct drm_i915_private *i915) { - if (HAS_GMCH(dev_priv)) { - if (IS_CHERRYVIEW(dev_priv)) { - dev_priv->display.funcs.color = &chv_color_funcs; - } else if (DISPLAY_VER(dev_priv) >= 4) { - dev_priv->display.funcs.color = &i965_color_funcs; - } else { - dev_priv->display.funcs.color = &i9xx_color_funcs; - } + if (HAS_GMCH(i915)) { + if (IS_CHERRYVIEW(i915)) + i915->display.funcs.color = &chv_color_funcs; + else if (DISPLAY_VER(i915) >= 4) + i915->display.funcs.color = &i965_color_funcs; + else + i915->display.funcs.color = &i9xx_color_funcs; } else { - if (DISPLAY_VER(dev_priv) >= 11) - dev_priv->display.funcs.color = &icl_color_funcs; - else if (DISPLAY_VER(dev_priv) == 10) - dev_priv->display.funcs.color = &glk_color_funcs; - else if (DISPLAY_VER(dev_priv) == 9) - dev_priv->display.funcs.color = &skl_color_funcs; - else if (DISPLAY_VER(dev_priv) == 8) - dev_priv->display.funcs.color = &bdw_color_funcs; - else if (IS_HASWELL(dev_priv)) - dev_priv->display.funcs.color = &hsw_color_funcs; - else if (DISPLAY_VER(dev_priv) == 7) - dev_priv->display.funcs.color = &ivb_color_funcs; + if (DISPLAY_VER(i915) >= 11) + i915->display.funcs.color = &icl_color_funcs; + else if (DISPLAY_VER(i915) == 10) + i915->display.funcs.color = &glk_color_funcs; + else if (DISPLAY_VER(i915) == 9) + i915->display.funcs.color = &skl_color_funcs; + else if (DISPLAY_VER(i915) == 8) + i915->display.funcs.color = &bdw_color_funcs; + else if (IS_HASWELL(i915)) + i915->display.funcs.color = &hsw_color_funcs; + else if (DISPLAY_VER(i915) == 7) + i915->display.funcs.color = &ivb_color_funcs; else - dev_priv->display.funcs.color = &ilk_color_funcs; + i915->display.funcs.color = &ilk_color_funcs; } } -- cgit From 296cd8ecfd305dae76722bb683943cdfefe7f4d3 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 29 Sep 2022 10:15:16 +0300 Subject: drm/i915: Change glk_load_degamma_lut() calling convention MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make glk_load_degamma_lut() more like most everyone else and pass in the LUT explicitly. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220929071521.26612-6-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_color.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index 96687ec30b19..0c73b2ba1283 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -826,13 +826,14 @@ static int glk_degamma_lut_size(struct drm_i915_private *i915) return 35; } -static void glk_load_degamma_lut(const struct intel_crtc_state *crtc_state) +static void glk_load_degamma_lut(const struct intel_crtc_state *crtc_state, + const struct drm_property_blob *blob) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + const struct drm_color_lut *lut = blob->data; + int i, lut_size = drm_color_lut_size(blob); enum pipe pipe = crtc->pipe; - int i, lut_size = INTEL_INFO(dev_priv)->display.color.degamma_lut_size; - const struct drm_color_lut *lut = crtc_state->hw.degamma_lut->data; /* * When setting the auto-increment bit, the hardware seems to @@ -899,6 +900,7 @@ static void glk_load_degamma_lut_linear(const struct intel_crtc_state *crtc_stat static void glk_load_luts(const struct intel_crtc_state *crtc_state) { + const struct drm_property_blob *degamma_lut = crtc_state->hw.degamma_lut; const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut; struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); @@ -910,8 +912,8 @@ static void glk_load_luts(const struct intel_crtc_state *crtc_state) * the degama LUT so that we don't have to reload * it every time the pipe CSC is being enabled. */ - if (crtc_state->hw.degamma_lut) - glk_load_degamma_lut(crtc_state); + if (degamma_lut) + glk_load_degamma_lut(crtc_state, degamma_lut); else glk_load_degamma_lut_linear(crtc_state); @@ -1043,11 +1045,12 @@ icl_program_gamma_multi_segment(const struct intel_crtc_state *crtc_state) static void icl_load_luts(const struct intel_crtc_state *crtc_state) { + const struct drm_property_blob *degamma_lut = crtc_state->hw.degamma_lut; const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut; struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - if (crtc_state->hw.degamma_lut) - glk_load_degamma_lut(crtc_state); + if (degamma_lut) + glk_load_degamma_lut(crtc_state, degamma_lut); switch (crtc_state->gamma_mode & GAMMA_MODE_MODE_MASK) { case GAMMA_MODE_MODE_8BIT: -- cgit From 0c31611437b7155f115919a24f31673ffe94deee Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 28 Sep 2022 09:08:13 +0300 Subject: drm/i915: Add some debug prints for intel_modeset_all_pipes() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Print out on which pipes, and for what reason, we are forcing a full modeset. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220928060813.23264-1-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_cdclk.c | 2 +- drivers/gpu/drm/i915/display/intel_display.c | 6 +++++- drivers/gpu/drm/i915/display/intel_display.h | 3 ++- drivers/gpu/drm/i915/display/skl_watermark.c | 2 +- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index a12e86d92783..ad401357ab66 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -2769,7 +2769,7 @@ int intel_modeset_calc_cdclk(struct intel_atomic_state *state) } else if (intel_cdclk_needs_modeset(&old_cdclk_state->actual, &new_cdclk_state->actual)) { /* All pipes must be switched off while we change the cdclk. */ - ret = intel_modeset_all_pipes(state); + ret = intel_modeset_all_pipes(state, "CDCLK change"); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 4bcba618242d..8f20c11e91f7 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -5937,7 +5937,8 @@ intel_verify_planes(struct intel_atomic_state *state) plane_state->uapi.visible); } -int intel_modeset_all_pipes(struct intel_atomic_state *state) +int intel_modeset_all_pipes(struct intel_atomic_state *state, + const char *reason) { struct drm_i915_private *dev_priv = to_i915(state->base.dev); struct intel_crtc *crtc; @@ -5958,6 +5959,9 @@ int intel_modeset_all_pipes(struct intel_atomic_state *state) drm_atomic_crtc_needs_modeset(&crtc_state->uapi)) continue; + drm_dbg_kms(&dev_priv->drm, "[CRTC:%d:%s] Full modeset due to %s\n", + crtc->base.base.id, crtc->base.name, reason); + crtc_state->uapi.mode_changed = true; ret = drm_atomic_add_affected_connectors(&state->base, diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index ae06153210b7..dc335e03934e 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -683,7 +683,8 @@ void intel_modeset_driver_remove(struct drm_i915_private *i915); void intel_modeset_driver_remove_noirq(struct drm_i915_private *i915); void intel_modeset_driver_remove_nogem(struct drm_i915_private *i915); void intel_display_resume(struct drm_device *dev); -int intel_modeset_all_pipes(struct intel_atomic_state *state); +int intel_modeset_all_pipes(struct intel_atomic_state *state, + const char *reason); void intel_modeset_get_crtc_power_domains(struct intel_crtc_state *crtc_state, struct intel_power_domain_mask *old_domains); void intel_modeset_put_crtc_power_domains(struct intel_crtc *crtc, diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index 01b0932757ed..59e4fc6191f1 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -2486,7 +2486,7 @@ skl_compute_ddb(struct intel_atomic_state *state) if (old_dbuf_state->joined_mbus != new_dbuf_state->joined_mbus) { /* TODO: Implement vblank synchronized MBUS joining changes */ - ret = intel_modeset_all_pipes(state); + ret = intel_modeset_all_pipes(state, "MBUS joining change"); if (ret) return ret; } -- cgit From 08fb97de03aa2205c6791301bd83a095abc1949c Mon Sep 17 00:00:00 2001 From: Andrey Grodzovsky Date: Fri, 30 Sep 2022 00:12:58 -0400 Subject: drm/sched: Add FIFO sched policy to run queue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When many entities are competing for the same run queue on the same scheduler, we observe an unusually long wait times and some jobs get starved. This has been observed on GPUVis. The issue is due to the Round Robin policy used by schedulers to pick up the next entity's job queue for execution. Under stress of many entities and long job queues within entity some jobs could be stuck for very long time in it's entity's queue before being popped from the queue and executed while for other entities with smaller job queues a job might execute earlier even though that job arrived later then the job in the long queue. Fix: Add FIFO selection policy to entities in run queue, chose next entity on run queue in such order that if job on one entity arrived earlier then job on another entity the first job will start executing earlier regardless of the length of the entity's job queue. v2: Switch to rb tree structure for entities based on TS of oldest job waiting in the job queue of an entity. Improves next entity extraction to O(1). Entity TS update O(log N) where N is the number of entities in the run-queue Drop default option in module control parameter. v3: Various cosmetical fixes and minor refactoring of fifo update function. (Luben) v4: Switch drm_sched_rq_select_entity_fifo to in order search (Luben) v5: Fix up drm_sched_rq_select_entity_fifo loop (Luben) v6: Add missing drm_sched_rq_remove_fifo_locked v7: Fix ts sampling bug and more cosmetic stuff (Luben) v8: Fix module parameter string (Luben) Cc: Luben Tuikov Cc: Christian König Cc: Direct Rendering Infrastructure - Development Cc: AMD Graphics Signed-off-by: Andrey Grodzovsky Tested-by: Yunxiang Li (Teddy) Signed-off-by: Luben Tuikov Reviewed-by: Luben Tuikov Link: https://patchwork.freedesktop.org/patch/msgid/20220930041258.1050247-1-luben.tuikov@amd.com --- drivers/gpu/drm/scheduler/sched_entity.c | 20 +++++++ drivers/gpu/drm/scheduler/sched_main.c | 96 +++++++++++++++++++++++++++++++- include/drm/gpu_scheduler.h | 32 +++++++++++ 3 files changed, 145 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/scheduler/sched_entity.c b/drivers/gpu/drm/scheduler/sched_entity.c index 6b25b2f4f5a3..7060e4ed5a31 100644 --- a/drivers/gpu/drm/scheduler/sched_entity.c +++ b/drivers/gpu/drm/scheduler/sched_entity.c @@ -73,6 +73,7 @@ int drm_sched_entity_init(struct drm_sched_entity *entity, entity->priority = priority; entity->sched_list = num_sched_list > 1 ? sched_list : NULL; entity->last_scheduled = NULL; + RB_CLEAR_NODE(&entity->rb_tree_node); if(num_sched_list) entity->rq = &sched_list[0]->sched_rq[entity->priority]; @@ -443,6 +444,19 @@ struct drm_sched_job *drm_sched_entity_pop_job(struct drm_sched_entity *entity) smp_wmb(); spsc_queue_pop(&entity->job_queue); + + /* + * Update the entity's location in the min heap according to + * the timestamp of the next job, if any. + */ + if (drm_sched_policy == DRM_SCHED_POLICY_FIFO) { + struct drm_sched_job *next; + + next = to_drm_sched_job(spsc_queue_peek(&entity->job_queue)); + if (next) + drm_sched_rq_update_fifo(entity, next->submit_ts); + } + return sched_job; } @@ -507,6 +521,7 @@ void drm_sched_entity_push_job(struct drm_sched_job *sched_job) atomic_inc(entity->rq->sched->score); WRITE_ONCE(entity->last_user, current->group_leader); first = spsc_queue_push(&entity->job_queue, &sched_job->queue_node); + sched_job->submit_ts = ktime_get(); /* first job wakes up scheduler */ if (first) { @@ -518,8 +533,13 @@ void drm_sched_entity_push_job(struct drm_sched_job *sched_job) DRM_ERROR("Trying to push to a killed entity\n"); return; } + drm_sched_rq_add_entity(entity->rq, entity); spin_unlock(&entity->rq_lock); + + if (drm_sched_policy == DRM_SCHED_POLICY_FIFO) + drm_sched_rq_update_fifo(entity, sched_job->submit_ts); + drm_sched_wakeup(entity->rq->sched); } } diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index 4f2395d1a791..ce86b03e8386 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -62,6 +62,55 @@ #define to_drm_sched_job(sched_job) \ container_of((sched_job), struct drm_sched_job, queue_node) +int drm_sched_policy = DRM_SCHED_POLICY_RR; + +/** + * DOC: sched_policy (int) + * Used to override default entities scheduling policy in a run queue. + */ +MODULE_PARM_DESC(sched_policy, "Specify schedule policy for entities on a runqueue, " __stringify(DRM_SCHED_POLICY_RR) " = Round Robin (default), " __stringify(DRM_SCHED_POLICY_FIFO) " = use FIFO."); +module_param_named(sched_policy, drm_sched_policy, int, 0444); + +static __always_inline bool drm_sched_entity_compare_before(struct rb_node *a, + const struct rb_node *b) +{ + struct drm_sched_entity *ent_a = rb_entry((a), struct drm_sched_entity, rb_tree_node); + struct drm_sched_entity *ent_b = rb_entry((b), struct drm_sched_entity, rb_tree_node); + + return ktime_before(ent_a->oldest_job_waiting, ent_b->oldest_job_waiting); +} + +static inline void drm_sched_rq_remove_fifo_locked(struct drm_sched_entity *entity) +{ + struct drm_sched_rq *rq = entity->rq; + + if (!RB_EMPTY_NODE(&entity->rb_tree_node)) { + rb_erase_cached(&entity->rb_tree_node, &rq->rb_tree_root); + RB_CLEAR_NODE(&entity->rb_tree_node); + } +} + +void drm_sched_rq_update_fifo(struct drm_sched_entity *entity, ktime_t ts) +{ + /* + * Both locks need to be grabbed, one to protect from entity->rq change + * for entity from within concurrent drm_sched_entity_select_rq and the + * other to update the rb tree structure. + */ + spin_lock(&entity->rq_lock); + spin_lock(&entity->rq->lock); + + drm_sched_rq_remove_fifo_locked(entity); + + entity->oldest_job_waiting = ts; + + rb_add_cached(&entity->rb_tree_node, &entity->rq->rb_tree_root, + drm_sched_entity_compare_before); + + spin_unlock(&entity->rq->lock); + spin_unlock(&entity->rq_lock); +} + /** * drm_sched_rq_init - initialize a given run queue struct * @@ -75,6 +124,7 @@ static void drm_sched_rq_init(struct drm_gpu_scheduler *sched, { spin_lock_init(&rq->lock); INIT_LIST_HEAD(&rq->entities); + rq->rb_tree_root = RB_ROOT_CACHED; rq->current_entity = NULL; rq->sched = sched; } @@ -92,9 +142,12 @@ void drm_sched_rq_add_entity(struct drm_sched_rq *rq, { if (!list_empty(&entity->list)) return; + spin_lock(&rq->lock); + atomic_inc(rq->sched->score); list_add_tail(&entity->list, &rq->entities); + spin_unlock(&rq->lock); } @@ -111,23 +164,30 @@ void drm_sched_rq_remove_entity(struct drm_sched_rq *rq, { if (list_empty(&entity->list)) return; + spin_lock(&rq->lock); + atomic_dec(rq->sched->score); list_del_init(&entity->list); + if (rq->current_entity == entity) rq->current_entity = NULL; + + if (drm_sched_policy == DRM_SCHED_POLICY_FIFO) + drm_sched_rq_remove_fifo_locked(entity); + spin_unlock(&rq->lock); } /** - * drm_sched_rq_select_entity - Select an entity which could provide a job to run + * drm_sched_rq_select_entity_rr - Select an entity which could provide a job to run * * @rq: scheduler run queue to check. * * Try to find a ready entity, returns NULL if none found. */ static struct drm_sched_entity * -drm_sched_rq_select_entity(struct drm_sched_rq *rq) +drm_sched_rq_select_entity_rr(struct drm_sched_rq *rq) { struct drm_sched_entity *entity; @@ -163,6 +223,34 @@ drm_sched_rq_select_entity(struct drm_sched_rq *rq) return NULL; } +/** + * drm_sched_rq_select_entity_fifo - Select an entity which provides a job to run + * + * @rq: scheduler run queue to check. + * + * Find oldest waiting ready entity, returns NULL if none found. + */ +static struct drm_sched_entity * +drm_sched_rq_select_entity_fifo(struct drm_sched_rq *rq) +{ + struct rb_node *rb; + + spin_lock(&rq->lock); + for (rb = rb_first_cached(&rq->rb_tree_root); rb; rb = rb_next(rb)) { + struct drm_sched_entity *entity; + + entity = rb_entry(rb, struct drm_sched_entity, rb_tree_node); + if (drm_sched_entity_is_ready(entity)) { + rq->current_entity = entity; + reinit_completion(&entity->entity_idle); + break; + } + } + spin_unlock(&rq->lock); + + return rb ? rb_entry(rb, struct drm_sched_entity, rb_tree_node) : NULL; +} + /** * drm_sched_job_done - complete a job * @s_job: pointer to the job which is done @@ -803,7 +891,9 @@ drm_sched_select_entity(struct drm_gpu_scheduler *sched) /* Kernel run queue has higher priority than normal run queue*/ for (i = DRM_SCHED_PRIORITY_COUNT - 1; i >= DRM_SCHED_PRIORITY_MIN; i--) { - entity = drm_sched_rq_select_entity(&sched->sched_rq[i]); + entity = drm_sched_policy == DRM_SCHED_POLICY_FIFO ? + drm_sched_rq_select_entity_fifo(&sched->sched_rq[i]) : + drm_sched_rq_select_entity_rr(&sched->sched_rq[i]); if (entity) break; } diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h index 599855c6a672..1f7d9dd1a444 100644 --- a/include/drm/gpu_scheduler.h +++ b/include/drm/gpu_scheduler.h @@ -50,6 +50,12 @@ enum drm_sched_priority { DRM_SCHED_PRIORITY_UNSET = -2 }; +/* Used to chose between FIFO and RR jobs scheduling */ +extern int drm_sched_policy; + +#define DRM_SCHED_POLICY_RR 0 +#define DRM_SCHED_POLICY_FIFO 1 + /** * struct drm_sched_entity - A wrapper around a job queue (typically * attached to the DRM file_priv). @@ -196,6 +202,21 @@ struct drm_sched_entity { * drm_sched_entity_fini(). */ struct completion entity_idle; + + /** + * @oldest_job_waiting: + * + * Marks earliest job waiting in SW queue + */ + ktime_t oldest_job_waiting; + + /** + * @rb_tree_node: + * + * The node used to insert this entity into time based priority queue + */ + struct rb_node rb_tree_node; + }; /** @@ -205,6 +226,7 @@ struct drm_sched_entity { * @sched: the scheduler to which this rq belongs to. * @entities: list of the entities to be scheduled. * @current_entity: the entity which is to be scheduled. + * @rb_tree_root: root of time based priory queue of entities for FIFO scheduling * * Run queue is a set of entities scheduling command submissions for * one specific ring. It implements the scheduling policy that selects @@ -215,6 +237,7 @@ struct drm_sched_rq { struct drm_gpu_scheduler *sched; struct list_head entities; struct drm_sched_entity *current_entity; + struct rb_root_cached rb_tree_root; }; /** @@ -314,6 +337,13 @@ struct drm_sched_job { /** @last_dependency: tracks @dependencies as they signal */ unsigned long last_dependency; + + /** + * @submit_ts: + * + * When the job was pushed into the entity queue. + */ + ktime_t submit_ts; }; static inline bool drm_sched_invalidate_job(struct drm_sched_job *s_job, @@ -503,6 +533,8 @@ void drm_sched_rq_add_entity(struct drm_sched_rq *rq, void drm_sched_rq_remove_entity(struct drm_sched_rq *rq, struct drm_sched_entity *entity); +void drm_sched_rq_update_fifo(struct drm_sched_entity *entity, ktime_t ts); + int drm_sched_entity_init(struct drm_sched_entity *entity, enum drm_sched_priority priority, struct drm_gpu_scheduler **sched_list, -- cgit From dbb2ffbfd708b2d0f1b7fe0083c5e3333d0fe35b Mon Sep 17 00:00:00 2001 From: Aravind Iddamsetty Date: Thu, 29 Sep 2022 17:16:58 +0530 Subject: drm/i915/mtl: enable local stolen memory As an integrated GPU, MTL does not have local memory and HAS_LMEM() returns false. However the platform's stolen memory is presented via BAR2 (i.e., the BAR we traditionally consider to be the GMADR on IGFX) and should be managed by the driver the same way that local memory is on dgpu platforms (which includes setting the "lmem" bit on page table entries). We use the term "local stolen memory" to refer to this model. The major difference from the traditional BAR2 (GMADR) is that the stolen area is mapped via the BAR2 while in the former BAR2 is an aperture into the GTT VA through which access are made into stolen area. BSPEC: 53098, 63830 v2: 1. dropped is_dsm_invalid, updated valid_stolen_size check from Lucas (Jani, Lucas) 2. drop lmembar_is_igpu_stolen 3. revert to referring GFXMEM_BAR as GEN12_LMEM_BAR (Lucas) v3:(Jani) 1. rename get_mtl_gms_size to mtl_get_gms_size 2. define register for MMIO address v4:(Matt) 1. Use REG_FIELD_GET to read GMS value 2. replace the calculations with SZ_256M/SZ_8M v5: Include more details to commit message on how it is different from earlier platforms (Anshuman) Cc: Matt Roper Cc: Lucas De Marchi Cc: Jani Nikula Signed-off-by: CQ Tang Signed-off-by: Aravind Iddamsetty Original-author: CQ Tang Reviewed-by: Matt Roper Signed-off-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20220929114658.145287-1-aravind.iddamsetty@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_stolen.c | 83 ++++++++++++++++++++++++------ drivers/gpu/drm/i915/gt/intel_ggtt.c | 2 +- drivers/gpu/drm/i915/i915_drv.h | 3 ++ drivers/gpu/drm/i915/i915_reg.h | 4 ++ 4 files changed, 76 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c index a89bb5ed6c51..f512316de396 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c @@ -75,9 +75,9 @@ void i915_gem_stolen_remove_node(struct drm_i915_private *i915, mutex_unlock(&i915->mm.stolen_lock); } -static bool valid_stolen_size(struct resource *dsm) +static bool valid_stolen_size(struct drm_i915_private *i915, struct resource *dsm) { - return dsm->start != 0 && dsm->end > dsm->start; + return (dsm->start != 0 || HAS_BAR2_SMEM_STOLEN(i915)) && dsm->end > dsm->start; } static int adjust_stolen(struct drm_i915_private *i915, @@ -86,7 +86,7 @@ static int adjust_stolen(struct drm_i915_private *i915, struct i915_ggtt *ggtt = to_gt(i915)->ggtt; struct intel_uncore *uncore = ggtt->vm.gt->uncore; - if (!valid_stolen_size(dsm)) + if (!valid_stolen_size(i915, dsm)) return -EINVAL; /* @@ -133,7 +133,7 @@ static int adjust_stolen(struct drm_i915_private *i915, } } - if (!valid_stolen_size(dsm)) + if (!valid_stolen_size(i915, dsm)) return -EINVAL; return 0; @@ -147,8 +147,11 @@ static int request_smem_stolen(struct drm_i915_private *i915, /* * With stolen lmem, we don't need to request system memory for the * address range since it's local to the gpu. + * + * Starting MTL, in IGFX devices the stolen memory is exposed via + * BAR2 and shall be considered similar to stolen lmem. */ - if (HAS_LMEM(i915)) + if (HAS_LMEM(i915) || HAS_BAR2_SMEM_STOLEN(i915)) return 0; /* @@ -383,8 +386,6 @@ static void icl_get_stolen_reserved(struct drm_i915_private *i915, drm_dbg(&i915->drm, "GEN6_STOLEN_RESERVED = 0x%016llx\n", reg_val); - *base = reg_val & GEN11_STOLEN_RESERVED_ADDR_MASK; - switch (reg_val & GEN8_STOLEN_RESERVED_SIZE_MASK) { case GEN8_STOLEN_RESERVED_1M: *size = 1024 * 1024; @@ -402,6 +403,12 @@ static void icl_get_stolen_reserved(struct drm_i915_private *i915, *size = 8 * 1024 * 1024; MISSING_CASE(reg_val & GEN8_STOLEN_RESERVED_SIZE_MASK); } + + if (HAS_BAR2_SMEM_STOLEN(i915)) + /* the base is initialized to stolen top so subtract size to get base */ + *base -= *size; + else + *base = reg_val & GEN11_STOLEN_RESERVED_ADDR_MASK; } /* @@ -831,6 +838,29 @@ static const struct intel_memory_region_ops i915_region_stolen_lmem_ops = { .init_object = _i915_gem_object_stolen_init, }; +static int mtl_get_gms_size(struct intel_uncore *uncore) +{ + u16 ggc, gms; + + ggc = intel_uncore_read16(uncore, GGC); + + /* check GGMS, should be fixed 0x3 (8MB) */ + if ((ggc & GGMS_MASK) != GGMS_MASK) + return -EIO; + + /* return valid GMS value, -EIO if invalid */ + gms = REG_FIELD_GET(GMS_MASK, ggc); + switch (gms) { + case 0x0 ... 0x04: + return gms * 32; + case 0xf0 ... 0xfe: + return (gms - 0xf0 + 1) * 4; + default: + MISSING_CASE(gms); + return -EIO; + } +} + struct intel_memory_region * i915_gem_stolen_lmem_setup(struct drm_i915_private *i915, u16 type, u16 instance) @@ -841,16 +871,13 @@ i915_gem_stolen_lmem_setup(struct drm_i915_private *i915, u16 type, struct intel_memory_region *mem; resource_size_t io_start, io_size; resource_size_t min_page_size; + int ret; if (WARN_ON_ONCE(instance)) return ERR_PTR(-ENODEV); - /* Use DSM base address instead for stolen memory */ - dsm_base = intel_uncore_read64(uncore, GEN12_DSMBASE) & GEN12_BDSM_MASK; - if (IS_DG1(uncore->i915)) { + if (HAS_BAR2_SMEM_STOLEN(i915) || IS_DG1(i915)) { lmem_size = pci_resource_len(pdev, 2); - if (WARN_ON(lmem_size < dsm_base)) - return ERR_PTR(-ENODEV); } else { resource_size_t lmem_range; @@ -859,13 +886,39 @@ i915_gem_stolen_lmem_setup(struct drm_i915_private *i915, u16 type, lmem_size *= SZ_1G; } - dsm_size = lmem_size - dsm_base; - if (pci_resource_len(pdev, 2) < lmem_size) { + if (HAS_BAR2_SMEM_STOLEN(i915)) { + /* + * MTL dsm size is in GGC register. + * Also MTL uses offset to DSMBASE in ptes, so i915 + * uses dsm_base = 0 to setup stolen region. + */ + ret = mtl_get_gms_size(uncore); + if (ret < 0) { + drm_err(&i915->drm, "invalid MTL GGC register setting\n"); + return ERR_PTR(ret); + } + + dsm_base = 0; + dsm_size = (resource_size_t)(ret * SZ_1M); + + GEM_BUG_ON(pci_resource_len(pdev, 2) != SZ_256M); + GEM_BUG_ON((dsm_size + SZ_8M) > lmem_size); + } else { + /* Use DSM base address instead for stolen memory */ + dsm_base = intel_uncore_read64(uncore, GEN12_DSMBASE); + if (WARN_ON(lmem_size < dsm_base)) + return ERR_PTR(-ENODEV); + dsm_size = lmem_size - dsm_base; + } + + io_size = dsm_size; + if (pci_resource_len(pdev, 2) < dsm_size) { io_start = 0; io_size = 0; + } else if (HAS_BAR2_SMEM_STOLEN(i915)) { + io_start = pci_resource_start(pdev, 2) + SZ_8M; } else { io_start = pci_resource_start(pdev, 2) + dsm_base; - io_size = dsm_size; } min_page_size = HAS_64K_PAGES(i915) ? I915_GTT_PAGE_SIZE_64K : diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt.c b/drivers/gpu/drm/i915/gt/intel_ggtt.c index 15a915bb4088..51669b4aae74 100644 --- a/drivers/gpu/drm/i915/gt/intel_ggtt.c +++ b/drivers/gpu/drm/i915/gt/intel_ggtt.c @@ -929,7 +929,7 @@ static int gen8_gmch_probe(struct i915_ggtt *ggtt) unsigned int size; u16 snb_gmch_ctl; - if (!HAS_LMEM(i915)) { + if (!HAS_LMEM(i915) && !HAS_BAR2_SMEM_STOLEN(i915)) { ggtt->gmadr = pci_resource(pdev, 2); ggtt->mappable_end = resource_size(&ggtt->gmadr); } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index cf6d0c102d54..ec3b2ebae25b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1427,6 +1427,9 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915, #define HAS_ONE_EU_PER_FUSE_BIT(i915) (INTEL_INFO(i915)->has_one_eu_per_fuse_bit) +#define HAS_BAR2_SMEM_STOLEN(i915) (!HAS_LMEM(i915) && \ + GRAPHICS_VER_FULL(i915) >= IP_VER(12, 70)) + /* i915_gem.c */ void i915_gem_init_early(struct drm_i915_private *dev_priv); void i915_gem_cleanup_early(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index d51e291d310a..11650c518b5d 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -8499,6 +8499,10 @@ enum skl_power_gate { _ICL_PIPE_DSS_CTL2_PB, \ _ICL_PIPE_DSS_CTL2_PC) +#define GGC _MMIO(0x108040) +#define GMS_MASK REG_GENMASK(15, 8) +#define GGMS_MASK REG_GENMASK(7, 6) + #define GEN12_GSMBASE _MMIO(0x108100) #define GEN12_DSMBASE _MMIO(0x1080C0) #define GEN12_BDSM_MASK REG_GENMASK64(63, 20) -- cgit From c3d5cfe7b978acea8c0613fb3a068d376ad93463 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Thu, 29 Sep 2022 22:09:01 -0700 Subject: drm/i915: Fix __gen125_emit_bb_start() without WA ce->wa_bb_page is allocated only for graphics version 12. However __gen125_emit_bb_start() is used for any graphics version >= 12.50. For the currently supported platforms this is not an issue, but for future ones there's a mismatch causing the jump to `wa_offset + DG2_PREDICATE_RESULT_BB` to be invalid since wa_offset is not correct. As in other places in the driver, check for graphics version "greater or equal" to future-proof the support for new platforms. Cc: Matt Roper Cc: Matthew Auld Cc: Chris Wilson Signed-off-by: Lucas De Marchi Reviewed-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20220930050903.3479619-2-lucas.demarchi@intel.com --- drivers/gpu/drm/i915/gt/gen8_engine_cs.c | 2 ++ drivers/gpu/drm/i915/gt/intel_lrc.c | 19 +++++++++---------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/gen8_engine_cs.c b/drivers/gpu/drm/i915/gt/gen8_engine_cs.c index 31a2fbd8c4a8..e000eaf8abed 100644 --- a/drivers/gpu/drm/i915/gt/gen8_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/gen8_engine_cs.c @@ -405,6 +405,8 @@ static int __gen125_emit_bb_start(struct i915_request *rq, u32 wa_offset = lrc_indirect_bb(ce); u32 *cs; + GEM_BUG_ON(!ce->wa_bb_page); + cs = intel_ring_begin(rq, 12); if (IS_ERR(cs)) return PTR_ERR(cs); diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.c b/drivers/gpu/drm/i915/gt/intel_lrc.c index e84ef3859934..3515882a91fb 100644 --- a/drivers/gpu/drm/i915/gt/intel_lrc.c +++ b/drivers/gpu/drm/i915/gt/intel_lrc.c @@ -825,19 +825,18 @@ static int lrc_ring_cmd_buf_cctl(const struct intel_engine_cs *engine) static u32 lrc_ring_indirect_offset_default(const struct intel_engine_cs *engine) { - switch (GRAPHICS_VER(engine->i915)) { - default: - MISSING_CASE(GRAPHICS_VER(engine->i915)); - fallthrough; - case 12: + if (GRAPHICS_VER(engine->i915) >= 12) return GEN12_CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT; - case 11: + else if (GRAPHICS_VER(engine->i915) >= 11) return GEN11_CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT; - case 9: + else if (GRAPHICS_VER(engine->i915) >= 9) return GEN9_CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT; - case 8: + else if (GRAPHICS_VER(engine->i915) >= 8) return GEN8_CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT; - } + + GEM_BUG_ON(GRAPHICS_VER(engine->i915) < 8); + + return 0; } static void @@ -1092,7 +1091,7 @@ __lrc_alloc_state(struct intel_context *ce, struct intel_engine_cs *engine) if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)) context_size += I915_GTT_PAGE_SIZE; /* for redzone */ - if (GRAPHICS_VER(engine->i915) == 12) { + if (GRAPHICS_VER(engine->i915) >= 12) { ce->wa_bb_page = context_size / PAGE_SIZE; context_size += PAGE_SIZE; } -- cgit From b1f80a5aaa9e8e1c2cbaf5bd65bb27bcaefb33d3 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Thu, 29 Sep 2022 22:09:02 -0700 Subject: drm/i915/gt: Document function to decode register state context It's not obvious how the encode/decode of the per platform tables is done. Document it so while adding tables for new platforms people can be confident they right things is being done. Signed-off-by: Lucas De Marchi Reviewed-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20220930050903.3479619-3-lucas.demarchi@intel.com --- drivers/gpu/drm/i915/gt/intel_lrc.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.c b/drivers/gpu/drm/i915/gt/intel_lrc.c index 3515882a91fb..7771a19008c6 100644 --- a/drivers/gpu/drm/i915/gt/intel_lrc.c +++ b/drivers/gpu/drm/i915/gt/intel_lrc.c @@ -20,6 +20,30 @@ #include "intel_ring.h" #include "shmem_utils.h" +/* + * The per-platform tables are u8-encoded in @data. Decode @data and set the + * addresses' offset and commands in @regs. The following encoding is used + * for each byte. There are 2 steps: decoding commands and decoding addresses. + * + * Commands: + * [7]: create NOPs - number of NOPs are set in lower bits + * [6]: When creating MI_LOAD_REGISTER_IMM command, allow to set + * MI_LRI_FORCE_POSTED + * [5:0]: Number of NOPs or registers to set values to in case of + * MI_LOAD_REGISTER_IMM + * + * Addresses: these are decoded after a MI_LOAD_REGISTER_IMM command by "count" + * number of registers. They are set by using the REG/REG16 macros: the former + * is used for offsets smaller than 0x200 while the latter is for values bigger + * than that. Those macros already set all the bits documented below correctly: + * + * [7]: When a register offset needs more than 6 bits, use additional bytes, to + * follow, for the lower bits + * [6:0]: Register offset, without considering the engine base. + * + * This function only tweaks the commands and register offsets. Values are not + * filled out. + */ static void set_offsets(u32 *regs, const u8 *data, const struct intel_engine_cs *engine, -- cgit From d263545ef0a32a087ec9dd89edb2ee1be1de629f Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Thu, 29 Sep 2022 22:09:03 -0700 Subject: drm/i915/gt: Fix platform prefix Different handling for XeHP and later platforms should be using the xehp prefix, not gen125. Rename them. Signed-off-by: Lucas De Marchi Reviewed-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20220930050903.3479619-4-lucas.demarchi@intel.com --- drivers/gpu/drm/i915/gt/gen8_engine_cs.c | 24 +++++++++++----------- drivers/gpu/drm/i915/gt/gen8_engine_cs.h | 12 +++++------ .../gpu/drm/i915/gt/intel_execlists_submission.c | 4 ++-- drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c | 2 +- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/gen8_engine_cs.c b/drivers/gpu/drm/i915/gt/gen8_engine_cs.c index e000eaf8abed..e1c76e5bfa82 100644 --- a/drivers/gpu/drm/i915/gt/gen8_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/gen8_engine_cs.c @@ -396,10 +396,10 @@ int gen8_emit_init_breadcrumb(struct i915_request *rq) return 0; } -static int __gen125_emit_bb_start(struct i915_request *rq, - u64 offset, u32 len, - const unsigned int flags, - u32 arb) +static int __xehp_emit_bb_start(struct i915_request *rq, + u64 offset, u32 len, + const unsigned int flags, + u32 arb) { struct intel_context *ce = rq->context; u32 wa_offset = lrc_indirect_bb(ce); @@ -437,18 +437,18 @@ static int __gen125_emit_bb_start(struct i915_request *rq, return 0; } -int gen125_emit_bb_start_noarb(struct i915_request *rq, - u64 offset, u32 len, - const unsigned int flags) +int xehp_emit_bb_start_noarb(struct i915_request *rq, + u64 offset, u32 len, + const unsigned int flags) { - return __gen125_emit_bb_start(rq, offset, len, flags, MI_ARB_DISABLE); + return __xehp_emit_bb_start(rq, offset, len, flags, MI_ARB_DISABLE); } -int gen125_emit_bb_start(struct i915_request *rq, - u64 offset, u32 len, - const unsigned int flags) +int xehp_emit_bb_start(struct i915_request *rq, + u64 offset, u32 len, + const unsigned int flags) { - return __gen125_emit_bb_start(rq, offset, len, flags, MI_ARB_ENABLE); + return __xehp_emit_bb_start(rq, offset, len, flags, MI_ARB_ENABLE); } int gen8_emit_bb_start_noarb(struct i915_request *rq, diff --git a/drivers/gpu/drm/i915/gt/gen8_engine_cs.h b/drivers/gpu/drm/i915/gt/gen8_engine_cs.h index e4d24c811dd6..655e5c00ddc2 100644 --- a/drivers/gpu/drm/i915/gt/gen8_engine_cs.h +++ b/drivers/gpu/drm/i915/gt/gen8_engine_cs.h @@ -32,12 +32,12 @@ int gen8_emit_bb_start(struct i915_request *rq, u64 offset, u32 len, const unsigned int flags); -int gen125_emit_bb_start_noarb(struct i915_request *rq, - u64 offset, u32 len, - const unsigned int flags); -int gen125_emit_bb_start(struct i915_request *rq, - u64 offset, u32 len, - const unsigned int flags); +int xehp_emit_bb_start_noarb(struct i915_request *rq, + u64 offset, u32 len, + const unsigned int flags); +int xehp_emit_bb_start(struct i915_request *rq, + u64 offset, u32 len, + const unsigned int flags); u32 *gen8_emit_fini_breadcrumb_xcs(struct i915_request *rq, u32 *cs); u32 *gen12_emit_fini_breadcrumb_xcs(struct i915_request *rq, u32 *cs); diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c index 428da98c5356..a61ac592ddff 100644 --- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c +++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c @@ -3471,9 +3471,9 @@ logical_ring_default_vfuncs(struct intel_engine_cs *engine) if (GRAPHICS_VER_FULL(engine->i915) >= IP_VER(12, 50)) { if (intel_engine_has_preemption(engine)) - engine->emit_bb_start = gen125_emit_bb_start; + engine->emit_bb_start = xehp_emit_bb_start; else - engine->emit_bb_start = gen125_emit_bb_start_noarb; + engine->emit_bb_start = xehp_emit_bb_start_noarb; } else { if (intel_engine_has_preemption(engine)) engine->emit_bb_start = gen8_emit_bb_start; diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index 0ef295a94060..d81f68fef9a8 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -4094,7 +4094,7 @@ static void guc_default_vfuncs(struct intel_engine_cs *engine) engine->emit_bb_start = gen8_emit_bb_start; if (GRAPHICS_VER_FULL(engine->i915) >= IP_VER(12, 50)) - engine->emit_bb_start = gen125_emit_bb_start; + engine->emit_bb_start = xehp_emit_bb_start; } static void rcs_submission_override(struct intel_engine_cs *engine) -- cgit From 6fa964c045a6bc3321a9186e87bfbcfd1059b0f1 Mon Sep 17 00:00:00 2001 From: Tejas Upadhyay Date: Fri, 30 Sep 2022 19:02:23 +0530 Subject: drm/i915/ehl: Update MOCS table for EHL Add these extra EHL entries back since we have drm-tip commit 13d29c823738 ("drm/i915/ehl: unconditionally flush the pages on acquire") introduces proper flushing to make it work as expected. Cc: Chris Wilson Cc: Matthew Auld Fixes: 046091758b50 ("Revert "drm/i915/ehl: Update MOCS table for EHL"") Signed-off-by: Matt Roper Signed-off-by: Tejas Upadhyay Acked-by: Matthew Auld Signed-off-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20220930133223.2757282-1-tejas.upadhyay@intel.com --- drivers/gpu/drm/i915/gt/intel_mocs.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/gt/intel_mocs.c b/drivers/gpu/drm/i915/gt/intel_mocs.c index c6ebe2781076..152244d7f62a 100644 --- a/drivers/gpu/drm/i915/gt/intel_mocs.c +++ b/drivers/gpu/drm/i915/gt/intel_mocs.c @@ -207,6 +207,14 @@ static const struct drm_i915_mocs_entry broxton_mocs_table[] = { MOCS_ENTRY(15, \ LE_3_WB | LE_TC_1_LLC | LE_LRUM(2) | LE_AOM(1), \ L3_3_WB), \ + /* Bypass LLC - Uncached (EHL+) */ \ + MOCS_ENTRY(16, \ + LE_1_UC | LE_TC_1_LLC | LE_SCF(1), \ + L3_1_UC), \ + /* Bypass LLC - L3 (Read-Only) (EHL+) */ \ + MOCS_ENTRY(17, \ + LE_1_UC | LE_TC_1_LLC | LE_SCF(1), \ + L3_3_WB), \ /* Self-Snoop - L3 + LLC */ \ MOCS_ENTRY(18, \ LE_3_WB | LE_TC_1_LLC | LE_LRUM(3) | LE_SSE(3), \ -- cgit From 8da8e32e0b095613af2c2ce4b322240269164a8e Mon Sep 17 00:00:00 2001 From: Jouni Högander Date: Mon, 3 Oct 2022 10:20:11 +0300 Subject: drm/i915/psr: Fix PSR_IMR/IIR field handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Current PSR code is supposed to use TRANSCODER_EDP to force 0 shift for bits in PSR_IMR/IIR registers: /* * gen12+ has registers relative to transcoder and one per transcoder * using the same bit definition: handle it as TRANSCODER_EDP to force * 0 shift in bit definition */ At the time of writing the code assumption "TRANSCODER_EDP == 0" was made. This is not the case and all fields in PSR_IMR and PSR_IIR are shifted incorrectly if DISPLAY_VER >= 12. Fix this by adding separate register field defines for >=12 and add bit getter functions to keep code readability. v4: - Remove EDP from TGL definitions (José) - Use REG_BIT and REG_GENMASK (José) v3: - Add separate register field defines (José) - Add bit getter functions (José) v2: - Improve commit message (José) Cc: José Roberto de Souza Cc: Mika Kahola Fixes: 8241cfbe67f4 ("drm/i915/tgl: Access the right register when handling PSR interruptions") Signed-off-by: Jouni Högander Reviewed-by: José Roberto de Souza Signed-off-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20221003072011.72408-1-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_psr.c | 78 +++++++++++++++++++------------- drivers/gpu/drm/i915/i915_reg.h | 16 +++++-- 2 files changed, 59 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 9def8d9fade6..d4cce627d7a8 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -116,34 +116,56 @@ static bool psr2_global_enabled(struct intel_dp *intel_dp) } } +static u32 psr_irq_psr_error_bit_get(struct intel_dp *intel_dp) +{ + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + + return DISPLAY_VER(dev_priv) >= 12 ? TGL_PSR_ERROR : + EDP_PSR_ERROR(intel_dp->psr.transcoder); +} + +static u32 psr_irq_post_exit_bit_get(struct intel_dp *intel_dp) +{ + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + + return DISPLAY_VER(dev_priv) >= 12 ? TGL_PSR_POST_EXIT : + EDP_PSR_POST_EXIT(intel_dp->psr.transcoder); +} + +static u32 psr_irq_pre_entry_bit_get(struct intel_dp *intel_dp) +{ + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + + return DISPLAY_VER(dev_priv) >= 12 ? TGL_PSR_PRE_ENTRY : + EDP_PSR_PRE_ENTRY(intel_dp->psr.transcoder); +} + +static u32 psr_irq_mask_get(struct intel_dp *intel_dp) +{ + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + + return DISPLAY_VER(dev_priv) >= 12 ? TGL_PSR_MASK : + EDP_PSR_MASK(intel_dp->psr.transcoder); +} + static void psr_irq_control(struct intel_dp *intel_dp) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); - enum transcoder trans_shift; i915_reg_t imr_reg; u32 mask, val; - /* - * gen12+ has registers relative to transcoder and one per transcoder - * using the same bit definition: handle it as TRANSCODER_EDP to force - * 0 shift in bit definition - */ - if (DISPLAY_VER(dev_priv) >= 12) { - trans_shift = 0; + if (DISPLAY_VER(dev_priv) >= 12) imr_reg = TRANS_PSR_IMR(intel_dp->psr.transcoder); - } else { - trans_shift = intel_dp->psr.transcoder; + else imr_reg = EDP_PSR_IMR; - } - mask = EDP_PSR_ERROR(trans_shift); + mask = psr_irq_psr_error_bit_get(intel_dp); if (intel_dp->psr.debug & I915_PSR_DEBUG_IRQ) - mask |= EDP_PSR_POST_EXIT(trans_shift) | - EDP_PSR_PRE_ENTRY(trans_shift); + mask |= psr_irq_post_exit_bit_get(intel_dp) | + psr_irq_pre_entry_bit_get(intel_dp); - /* Warning: it is masking/setting reserved bits too */ val = intel_de_read(dev_priv, imr_reg); - val &= ~EDP_PSR_TRANS_MASK(trans_shift); + val &= ~psr_irq_mask_get(intel_dp); val |= ~mask; intel_de_write(dev_priv, imr_reg, val); } @@ -191,25 +213,21 @@ void intel_psr_irq_handler(struct intel_dp *intel_dp, u32 psr_iir) enum transcoder cpu_transcoder = intel_dp->psr.transcoder; struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); ktime_t time_ns = ktime_get(); - enum transcoder trans_shift; i915_reg_t imr_reg; - if (DISPLAY_VER(dev_priv) >= 12) { - trans_shift = 0; + if (DISPLAY_VER(dev_priv) >= 12) imr_reg = TRANS_PSR_IMR(intel_dp->psr.transcoder); - } else { - trans_shift = intel_dp->psr.transcoder; + else imr_reg = EDP_PSR_IMR; - } - if (psr_iir & EDP_PSR_PRE_ENTRY(trans_shift)) { + if (psr_iir & psr_irq_pre_entry_bit_get(intel_dp)) { intel_dp->psr.last_entry_attempt = time_ns; drm_dbg_kms(&dev_priv->drm, "[transcoder %s] PSR entry attempt in 2 vblanks\n", transcoder_name(cpu_transcoder)); } - if (psr_iir & EDP_PSR_POST_EXIT(trans_shift)) { + if (psr_iir & psr_irq_post_exit_bit_get(intel_dp)) { intel_dp->psr.last_exit = time_ns; drm_dbg_kms(&dev_priv->drm, "[transcoder %s] PSR exit completed\n", @@ -226,7 +244,7 @@ void intel_psr_irq_handler(struct intel_dp *intel_dp, u32 psr_iir) } } - if (psr_iir & EDP_PSR_ERROR(trans_shift)) { + if (psr_iir & psr_irq_psr_error_bit_get(intel_dp)) { u32 val; drm_warn(&dev_priv->drm, "[transcoder %s] PSR aux error\n", @@ -243,7 +261,7 @@ void intel_psr_irq_handler(struct intel_dp *intel_dp, u32 psr_iir) * or unset irq_aux_error. */ val = intel_de_read(dev_priv, imr_reg); - val |= EDP_PSR_ERROR(trans_shift); + val |= psr_irq_psr_error_bit_get(intel_dp); intel_de_write(dev_priv, imr_reg, val); schedule_work(&intel_dp->psr.work); @@ -1194,14 +1212,12 @@ static bool psr_interrupt_error_check(struct intel_dp *intel_dp) * first time that PSR HW tries to activate so lets keep PSR disabled * to avoid any rendering problems. */ - if (DISPLAY_VER(dev_priv) >= 12) { + if (DISPLAY_VER(dev_priv) >= 12) val = intel_de_read(dev_priv, TRANS_PSR_IIR(intel_dp->psr.transcoder)); - val &= EDP_PSR_ERROR(0); - } else { + else val = intel_de_read(dev_priv, EDP_PSR_IIR); - val &= EDP_PSR_ERROR(intel_dp->psr.transcoder); - } + val &= psr_irq_psr_error_bit_get(intel_dp); if (val) { intel_dp->psr.sink_not_reliable = true; drm_dbg_kms(&dev_priv->drm, diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index a4f0129c3f6f..e43bb0a911e9 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2157,10 +2157,18 @@ #define TRANS_PSR_IIR(tran) _MMIO_TRANS2(tran, _PSR_IIR_A) #define _EDP_PSR_TRANS_SHIFT(trans) ((trans) == TRANSCODER_EDP ? \ 0 : ((trans) - TRANSCODER_A + 1) * 8) -#define EDP_PSR_TRANS_MASK(trans) (0x7 << _EDP_PSR_TRANS_SHIFT(trans)) -#define EDP_PSR_ERROR(trans) (0x4 << _EDP_PSR_TRANS_SHIFT(trans)) -#define EDP_PSR_POST_EXIT(trans) (0x2 << _EDP_PSR_TRANS_SHIFT(trans)) -#define EDP_PSR_PRE_ENTRY(trans) (0x1 << _EDP_PSR_TRANS_SHIFT(trans)) +#define TGL_PSR_MASK REG_GENMASK(2, 0) +#define TGL_PSR_ERROR REG_BIT(2) +#define TGL_PSR_POST_EXIT REG_BIT(1) +#define TGL_PSR_PRE_ENTRY REG_BIT(0) +#define EDP_PSR_MASK(trans) (TGL_PSR_MASK << \ + _EDP_PSR_TRANS_SHIFT(trans)) +#define EDP_PSR_ERROR(trans) (TGL_PSR_ERROR << \ + _EDP_PSR_TRANS_SHIFT(trans)) +#define EDP_PSR_POST_EXIT(trans) (TGL_PSR_POST_EXIT << \ + _EDP_PSR_TRANS_SHIFT(trans)) +#define EDP_PSR_PRE_ENTRY(trans) (TGL_PSR_PRE_ENTRY << \ + _EDP_PSR_TRANS_SHIFT(trans)) #define _SRD_AUX_DATA_A 0x60814 #define _SRD_AUX_DATA_EDP 0x6f814 -- cgit From a89a96a586114f67598c6391c75678b4dba5c2da Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 3 Oct 2022 14:15:39 +0300 Subject: drm/i915: Fix watermark calculations for gen12+ RC CCS modifier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Take the gen12+ RC CCS modifier into account when calculating the watermarks. Othwerwise we'll calculate the watermarks thinking this Y-tiled modifier is linear. The rc_surface part is actually a nop since that is not used for any glk+ platform. v2: Split RC CCS vs. MC CCS to separate patches Cc: stable@vger.kernel.org Fixes: b3e57bccd68a ("drm/i915/tgl: Gen-12 render decompression") Reviewed-by: Juha-Pekka Heikkila Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221003111544.8007-2-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/skl_watermark.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index 59e4fc6191f1..6ce1213c18b3 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -1710,10 +1710,12 @@ skl_compute_wm_params(const struct intel_crtc_state *crtc_state, modifier == I915_FORMAT_MOD_4_TILED || modifier == I915_FORMAT_MOD_Yf_TILED || modifier == I915_FORMAT_MOD_Y_TILED_CCS || - modifier == I915_FORMAT_MOD_Yf_TILED_CCS; + modifier == I915_FORMAT_MOD_Yf_TILED_CCS || + modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS; wp->x_tiled = modifier == I915_FORMAT_MOD_X_TILED; wp->rc_surface = modifier == I915_FORMAT_MOD_Y_TILED_CCS || - modifier == I915_FORMAT_MOD_Yf_TILED_CCS; + modifier == I915_FORMAT_MOD_Yf_TILED_CCS || + modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS; wp->is_planar = intel_format_info_is_yuv_semiplanar(format, modifier); wp->width = width; -- cgit From 91c9651425fe955b1387f3637607dda005f3f710 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 3 Oct 2022 14:15:40 +0300 Subject: drm/i915: Fix watermark calculations for gen12+ MC CCS modifier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Take the gen12+ MC CCS modifier into account when calculating the watermarks. Othwerwise we'll calculate the watermarks thinking this Y-tiled modifier is linear. The rc_surface part is actually a nop since that is not used for any glk+ platform. v2: Split RC CCS vs. MC CCS to separate patches Cc: stable@vger.kernel.org Fixes: 2dfbf9d2873a ("drm/i915/tgl: Gen-12 display can decompress surfaces compressed by the media engine") Reviewed-by: Juha-Pekka Heikkila Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221003111544.8007-3-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/skl_watermark.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index 6ce1213c18b3..1b8f5970cbf7 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -1711,11 +1711,13 @@ skl_compute_wm_params(const struct intel_crtc_state *crtc_state, modifier == I915_FORMAT_MOD_Yf_TILED || modifier == I915_FORMAT_MOD_Y_TILED_CCS || modifier == I915_FORMAT_MOD_Yf_TILED_CCS || - modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS; + modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS || + modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS; wp->x_tiled = modifier == I915_FORMAT_MOD_X_TILED; wp->rc_surface = modifier == I915_FORMAT_MOD_Y_TILED_CCS || modifier == I915_FORMAT_MOD_Yf_TILED_CCS || - modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS; + modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS || + modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS; wp->is_planar = intel_format_info_is_yuv_semiplanar(format, modifier); wp->width = width; -- cgit From a627455bbe50a111475d7a42beb58fa64bd96c83 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 3 Oct 2022 14:15:41 +0300 Subject: drm/i915: Fix watermark calculations for gen12+ CCS+CC modifier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Take the gen12+ CCS+CC modifier into account when calculating the watermarks. Othwerwise we'll calculate the watermarks thinking this Y-tiled modifier is linear. The rc_surface part is actually a nop since that is not used for any glk+ platform. Cc: stable@vger.kernel.org Fixes: d1e2775e9b96 ("drm/i915/tgl: Add Clear Color support for TGL Render Decompression") Reviewed-by: Juha-Pekka Heikkila Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221003111544.8007-4-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/skl_watermark.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index 1b8f5970cbf7..0ff3ece166fe 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -1712,12 +1712,14 @@ skl_compute_wm_params(const struct intel_crtc_state *crtc_state, modifier == I915_FORMAT_MOD_Y_TILED_CCS || modifier == I915_FORMAT_MOD_Yf_TILED_CCS || modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS || - modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS; + modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS || + modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC; wp->x_tiled = modifier == I915_FORMAT_MOD_X_TILED; wp->rc_surface = modifier == I915_FORMAT_MOD_Y_TILED_CCS || modifier == I915_FORMAT_MOD_Yf_TILED_CCS || modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS || - modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS; + modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS || + modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC; wp->is_planar = intel_format_info_is_yuv_semiplanar(format, modifier); wp->width = width; -- cgit From f25d9f81a8e09ace4f04106995550bae1f522143 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 3 Oct 2022 14:15:42 +0300 Subject: drm/i915: Fix watermark calculations for DG2 CCS modifiers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Take the DG2 CCS modifiers into account when calculating the watermarks. Othwerwise we'll calculate the watermarks thinking these tile-4 modifiers are linear. The rc_surface part is actually a nop since that is not used for any glk+ platform. Cc: stable@vger.kernel.org Fixes: 4c3afa72138c ("drm/i915/dg2: Add support for DG2 render and media compression") Reviewed-by: Juha-Pekka Heikkila Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221003111544.8007-5-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/skl_watermark.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index 0ff3ece166fe..070357da40e4 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -1713,13 +1713,17 @@ skl_compute_wm_params(const struct intel_crtc_state *crtc_state, modifier == I915_FORMAT_MOD_Yf_TILED_CCS || modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS || modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS || - modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC; + modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC || + modifier == I915_FORMAT_MOD_4_TILED_DG2_RC_CCS || + modifier == I915_FORMAT_MOD_4_TILED_DG2_MC_CCS; wp->x_tiled = modifier == I915_FORMAT_MOD_X_TILED; wp->rc_surface = modifier == I915_FORMAT_MOD_Y_TILED_CCS || modifier == I915_FORMAT_MOD_Yf_TILED_CCS || modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS || modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS || - modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC; + modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC || + modifier == I915_FORMAT_MOD_4_TILED_DG2_RC_CCS || + modifier == I915_FORMAT_MOD_4_TILED_DG2_MC_CCS; wp->is_planar = intel_format_info_is_yuv_semiplanar(format, modifier); wp->width = width; -- cgit From 334810f82024815283a6e7febd3d2de1fed6c232 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 3 Oct 2022 14:15:43 +0300 Subject: drm/i915: Fix watermark calculations for DG2 CCS+CC modifier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Take the DG2 CCS+CC modifier into account when calculating the watermarks. Othwerwise we'll calculate the watermarks thinking this tile-4 modifier is linear. The rc_surface part is actually a nop since that is not used for any glk+ platform. Cc: stable@vger.kernel.org Fixes: 680025dcc400 ("drm/i915/dg2: Add support for DG2 clear color compression") Reviewed-by: Juha-Pekka Heikkila Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221003111544.8007-6-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/skl_watermark.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index 070357da40e4..aac0980a0c9d 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -1715,7 +1715,8 @@ skl_compute_wm_params(const struct intel_crtc_state *crtc_state, modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS || modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC || modifier == I915_FORMAT_MOD_4_TILED_DG2_RC_CCS || - modifier == I915_FORMAT_MOD_4_TILED_DG2_MC_CCS; + modifier == I915_FORMAT_MOD_4_TILED_DG2_MC_CCS || + modifier == I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC; wp->x_tiled = modifier == I915_FORMAT_MOD_X_TILED; wp->rc_surface = modifier == I915_FORMAT_MOD_Y_TILED_CCS || modifier == I915_FORMAT_MOD_Yf_TILED_CCS || @@ -1723,7 +1724,8 @@ skl_compute_wm_params(const struct intel_crtc_state *crtc_state, modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS || modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC || modifier == I915_FORMAT_MOD_4_TILED_DG2_RC_CCS || - modifier == I915_FORMAT_MOD_4_TILED_DG2_MC_CCS; + modifier == I915_FORMAT_MOD_4_TILED_DG2_MC_CCS || + modifier == I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC; wp->is_planar = intel_format_info_is_yuv_semiplanar(format, modifier); wp->width = width; -- cgit From d5c45330c8986aff945de997383e19b5b7a85b9a Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 3 Oct 2022 14:15:44 +0300 Subject: drm/i915: Simplify modifier lookup in watermark code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the huge modifier lists in the watermark code with a few calls to intel_fb.c. Reviewed-by: Juha-Pekka Heikkila Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221003111544.8007-7-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_fb.c | 13 +++++++++++++ drivers/gpu/drm/i915/display/intel_fb.h | 1 + drivers/gpu/drm/i915/display/skl_watermark.c | 22 +++------------------- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fb.c b/drivers/gpu/drm/i915/display/intel_fb.c index b191915ab351..cc755cc017c1 100644 --- a/drivers/gpu/drm/i915/display/intel_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fb.c @@ -300,6 +300,19 @@ static bool plane_caps_contain_all(u8 caps, u8 mask) return (caps & mask) == mask; } +/** + * intel_fb_is_tiled_modifier: Check if a modifier is a tiled modifier type + * @modifier: Modifier to check + * + * Returns: + * Returns %true if @modifier is a tiled modifier. + */ +bool intel_fb_is_tiled_modifier(u64 modifier) +{ + return plane_caps_contain_any(lookup_modifier(modifier)->plane_caps, + INTEL_PLANE_CAP_TILING_MASK); +} + /** * intel_fb_is_ccs_modifier: Check if a modifier is a CCS modifier type * @modifier: Modifier to check diff --git a/drivers/gpu/drm/i915/display/intel_fb.h b/drivers/gpu/drm/i915/display/intel_fb.h index 12386f13a4e0..4662b812b934 100644 --- a/drivers/gpu/drm/i915/display/intel_fb.h +++ b/drivers/gpu/drm/i915/display/intel_fb.h @@ -29,6 +29,7 @@ struct intel_plane_state; #define INTEL_PLANE_CAP_TILING_Yf BIT(5) #define INTEL_PLANE_CAP_TILING_4 BIT(6) +bool intel_fb_is_tiled_modifier(u64 modifier); bool intel_fb_is_ccs_modifier(u64 modifier); bool intel_fb_is_rc_ccs_cc_modifier(u64 modifier); bool intel_fb_is_mc_ccs_modifier(u64 modifier); diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index aac0980a0c9d..d58e667016e4 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -1706,26 +1706,10 @@ skl_compute_wm_params(const struct intel_crtc_state *crtc_state, return -EINVAL; } - wp->y_tiled = modifier == I915_FORMAT_MOD_Y_TILED || - modifier == I915_FORMAT_MOD_4_TILED || - modifier == I915_FORMAT_MOD_Yf_TILED || - modifier == I915_FORMAT_MOD_Y_TILED_CCS || - modifier == I915_FORMAT_MOD_Yf_TILED_CCS || - modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS || - modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS || - modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC || - modifier == I915_FORMAT_MOD_4_TILED_DG2_RC_CCS || - modifier == I915_FORMAT_MOD_4_TILED_DG2_MC_CCS || - modifier == I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC; wp->x_tiled = modifier == I915_FORMAT_MOD_X_TILED; - wp->rc_surface = modifier == I915_FORMAT_MOD_Y_TILED_CCS || - modifier == I915_FORMAT_MOD_Yf_TILED_CCS || - modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS || - modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS || - modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC || - modifier == I915_FORMAT_MOD_4_TILED_DG2_RC_CCS || - modifier == I915_FORMAT_MOD_4_TILED_DG2_MC_CCS || - modifier == I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC; + wp->y_tiled = modifier != I915_FORMAT_MOD_X_TILED && + intel_fb_is_tiled_modifier(modifier); + wp->rc_surface = intel_fb_is_ccs_modifier(modifier); wp->is_planar = intel_format_info_is_yuv_semiplanar(format, modifier); wp->width = width; -- cgit From df2f59c5857b56a5cc40b6562b032c5d8d50cdfc Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 27 Sep 2022 21:24:55 +0300 Subject: drm/i915: Reject excessive dotclocks early MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make sure modes with crazy big dotclocks are rejected early, so as to not cause problems for subsequent code via integer overflows and whatnot. These would eventually be rejected in intel_crtc_compute_pipe_mode() but that is now too late as we do the clock computations a bit earlier than that. And we don't want to just reorder the two since we still want to check the final computed dotclock against the hardware limit to make sure we didn't end up above the limit due to rounding/etc. Fixes: 0ff0e219d9b8 ("drm/i915: Compute clocks earlier") Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220927182455.3422-1-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_display.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 8f20c11e91f7..237262a0bab4 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -8134,6 +8134,17 @@ static void intel_setup_outputs(struct drm_i915_private *dev_priv) drm_helper_move_panel_connectors_to_head(&dev_priv->drm); } +static int max_dotclock(struct drm_i915_private *i915) +{ + int max_dotclock = i915->max_dotclk_freq; + + /* icl+ might use bigjoiner */ + if (DISPLAY_VER(i915) >= 11) + max_dotclock *= 2; + + return max_dotclock; +} + static enum drm_mode_status intel_mode_valid(struct drm_device *dev, const struct drm_display_mode *mode) @@ -8171,6 +8182,13 @@ intel_mode_valid(struct drm_device *dev, DRM_MODE_FLAG_CLKDIV2)) return MODE_BAD; + /* + * Reject clearly excessive dotclocks early to + * avoid having to worry about huge integers later. + */ + if (mode->clock > max_dotclock(dev_priv)) + return MODE_CLOCK_HIGH; + /* Transcoder timing limits */ if (DISPLAY_VER(dev_priv) >= 11) { hdisplay_max = 16384; -- cgit From 61564e6c5a4addf170b75415c4ac86282784a072 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 3 Oct 2022 14:32:44 +0300 Subject: drm/i915: Move DRRS debugfs next to the implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the DRRS debugfs stuff next to the actual implementation so that it's easier to deal with the whole. Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221003113249.16213-2-ville.syrjala@linux.intel.com --- .../gpu/drm/i915/display/intel_display_debugfs.c | 96 +------------------ drivers/gpu/drm/i915/display/intel_drrs.c | 106 +++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_drrs.h | 1 + 3 files changed, 108 insertions(+), 95 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c index c5f47df0f362..df5a217d46ce 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c @@ -1023,52 +1023,6 @@ static int i915_ddb_info(struct seq_file *m, void *unused) return 0; } -static int i915_drrs_status(struct seq_file *m, void *unused) -{ - struct drm_i915_private *dev_priv = node_to_i915(m->private); - struct drm_connector_list_iter conn_iter; - struct intel_connector *connector; - struct intel_crtc *crtc; - - drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter); - for_each_intel_connector_iter(connector, &conn_iter) { - seq_printf(m, "[CONNECTOR:%d:%s] DRRS type: %s\n", - connector->base.base.id, connector->base.name, - intel_drrs_type_str(intel_panel_drrs_type(connector))); - } - drm_connector_list_iter_end(&conn_iter); - - seq_puts(m, "\n"); - - for_each_intel_crtc(&dev_priv->drm, crtc) { - const struct intel_crtc_state *crtc_state = - to_intel_crtc_state(crtc->base.state); - - seq_printf(m, "[CRTC:%d:%s]:\n", - crtc->base.base.id, crtc->base.name); - - mutex_lock(&crtc->drrs.mutex); - - /* DRRS Supported */ - seq_printf(m, "\tDRRS Enabled: %s\n", - str_yes_no(crtc_state->has_drrs)); - - seq_printf(m, "\tDRRS Active: %s\n", - str_yes_no(intel_drrs_is_active(crtc))); - - seq_printf(m, "\tBusy_frontbuffer_bits: 0x%X\n", - crtc->drrs.busy_frontbuffer_bits); - - seq_printf(m, "\tDRRS refresh rate: %s\n", - crtc->drrs.refresh_rate == DRRS_REFRESH_RATE_LOW ? - "low" : "high"); - - mutex_unlock(&crtc->drrs.mutex); - } - - return 0; -} - static bool intel_lpsp_power_well_enabled(struct drm_i915_private *i915, enum i915_power_well_id power_well_id) @@ -1567,53 +1521,6 @@ static const struct file_operations i915_cur_wm_latency_fops = { .write = cur_wm_latency_write }; -static int i915_drrs_ctl_set(void *data, u64 val) -{ - struct drm_i915_private *dev_priv = data; - struct drm_device *dev = &dev_priv->drm; - struct intel_crtc *crtc; - - for_each_intel_crtc(dev, crtc) { - struct intel_crtc_state *crtc_state; - struct drm_crtc_commit *commit; - int ret; - - ret = drm_modeset_lock_single_interruptible(&crtc->base.mutex); - if (ret) - return ret; - - crtc_state = to_intel_crtc_state(crtc->base.state); - - if (!crtc_state->hw.active || - !crtc_state->has_drrs) - goto out; - - commit = crtc_state->uapi.commit; - if (commit) { - ret = wait_for_completion_interruptible(&commit->hw_done); - if (ret) - goto out; - } - - drm_dbg(&dev_priv->drm, - "Manually %sactivating DRRS\n", val ? "" : "de"); - - if (val) - intel_drrs_activate(crtc_state); - else - intel_drrs_deactivate(crtc_state); - -out: - drm_modeset_unlock(&crtc->base.mutex); - if (ret) - return ret; - } - - return 0; -} - -DEFINE_SIMPLE_ATTRIBUTE(i915_drrs_ctl_fops, NULL, i915_drrs_ctl_set, "%llu\n"); - static ssize_t i915_fifo_underrun_reset_write(struct file *filp, const char __user *ubuf, @@ -1687,7 +1594,6 @@ static const struct drm_info_list intel_display_debugfs_list[] = { {"i915_shared_dplls_info", i915_shared_dplls_info, 0}, {"i915_dp_mst_info", i915_dp_mst_info, 0}, {"i915_ddb_info", i915_ddb_info, 0}, - {"i915_drrs_status", i915_drrs_status, 0}, {"i915_lpsp_status", i915_lpsp_status, 0}, }; @@ -1702,7 +1608,6 @@ static const struct { {"i915_dp_test_data", &i915_displayport_test_data_fops}, {"i915_dp_test_type", &i915_displayport_test_type_fops}, {"i915_dp_test_active", &i915_displayport_test_active_fops}, - {"i915_drrs_ctl", &i915_drrs_ctl_fops}, {"i915_edp_psr_debug", &i915_edp_psr_debug_fops}, }; @@ -1724,6 +1629,7 @@ void intel_display_debugfs_register(struct drm_i915_private *i915) minor->debugfs_root, minor); intel_dmc_debugfs_register(i915); + intel_drrs_debugfs_register(i915); intel_fbc_debugfs_register(i915); intel_hpd_debugfs_register(i915); skl_watermark_ipc_debugfs_register(i915); diff --git a/drivers/gpu/drm/i915/display/intel_drrs.c b/drivers/gpu/drm/i915/display/intel_drrs.c index 7da4a9cbe4ba..030a3566538a 100644 --- a/drivers/gpu/drm/i915/display/intel_drrs.c +++ b/drivers/gpu/drm/i915/display/intel_drrs.c @@ -297,3 +297,109 @@ void intel_crtc_drrs_init(struct intel_crtc *crtc) mutex_init(&crtc->drrs.mutex); crtc->drrs.cpu_transcoder = INVALID_TRANSCODER; } + +static int intel_drrs_debugfs_status_show(struct seq_file *m, void *unused) +{ + struct drm_i915_private *i915 = m->private; + struct drm_connector_list_iter conn_iter; + struct intel_connector *connector; + struct intel_crtc *crtc; + + drm_connector_list_iter_begin(&i915->drm, &conn_iter); + for_each_intel_connector_iter(connector, &conn_iter) { + seq_printf(m, "[CONNECTOR:%d:%s] DRRS type: %s\n", + connector->base.base.id, connector->base.name, + intel_drrs_type_str(intel_panel_drrs_type(connector))); + } + drm_connector_list_iter_end(&conn_iter); + + seq_puts(m, "\n"); + + for_each_intel_crtc(&i915->drm, crtc) { + const struct intel_crtc_state *crtc_state = + to_intel_crtc_state(crtc->base.state); + + seq_printf(m, "[CRTC:%d:%s]:\n", + crtc->base.base.id, crtc->base.name); + + mutex_lock(&crtc->drrs.mutex); + + /* DRRS Supported */ + seq_printf(m, "\tDRRS Enabled: %s\n", + str_yes_no(crtc_state->has_drrs)); + + seq_printf(m, "\tDRRS Active: %s\n", + str_yes_no(intel_drrs_is_active(crtc))); + + seq_printf(m, "\tBusy_frontbuffer_bits: 0x%X\n", + crtc->drrs.busy_frontbuffer_bits); + + seq_printf(m, "\tDRRS refresh rate: %s\n", + crtc->drrs.refresh_rate == DRRS_REFRESH_RATE_LOW ? + "low" : "high"); + + mutex_unlock(&crtc->drrs.mutex); + } + + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(intel_drrs_debugfs_status); + +static int intel_drrs_debugfs_ctl_set(void *data, u64 val) +{ + struct drm_i915_private *i915 = data; + struct intel_crtc *crtc; + + for_each_intel_crtc(&i915->drm, crtc) { + struct intel_crtc_state *crtc_state; + struct drm_crtc_commit *commit; + int ret; + + ret = drm_modeset_lock_single_interruptible(&crtc->base.mutex); + if (ret) + return ret; + + crtc_state = to_intel_crtc_state(crtc->base.state); + + if (!crtc_state->hw.active || + !crtc_state->has_drrs) + goto out; + + commit = crtc_state->uapi.commit; + if (commit) { + ret = wait_for_completion_interruptible(&commit->hw_done); + if (ret) + goto out; + } + + drm_dbg(&i915->drm, + "Manually %sactivating DRRS\n", val ? "" : "de"); + + if (val) + intel_drrs_activate(crtc_state); + else + intel_drrs_deactivate(crtc_state); + +out: + drm_modeset_unlock(&crtc->base.mutex); + if (ret) + return ret; + } + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(intel_drrs_debugfs_ctl_fops, + NULL, intel_drrs_debugfs_ctl_set, "%llu\n"); + +void intel_drrs_debugfs_register(struct drm_i915_private *i915) +{ + struct drm_minor *minor = i915->drm.primary; + + debugfs_create_file("i915_drrs_status", 0444, minor->debugfs_root, + i915, &intel_drrs_debugfs_status_fops); + + debugfs_create_file("i915_drrs_ctl", 0644, minor->debugfs_root, + i915, &intel_drrs_debugfs_ctl_fops); +} diff --git a/drivers/gpu/drm/i915/display/intel_drrs.h b/drivers/gpu/drm/i915/display/intel_drrs.h index 3ad1be1ad9c1..052055988341 100644 --- a/drivers/gpu/drm/i915/display/intel_drrs.h +++ b/drivers/gpu/drm/i915/display/intel_drrs.h @@ -24,5 +24,6 @@ void intel_drrs_invalidate(struct drm_i915_private *dev_priv, void intel_drrs_flush(struct drm_i915_private *dev_priv, unsigned int frontbuffer_bits); void intel_crtc_drrs_init(struct intel_crtc *crtc); +void intel_drrs_debugfs_register(struct drm_i915_private *i915); #endif /* __INTEL_DRRS_H__ */ -- cgit From 2e25c1fba7145f610c7e4744f3ed99ffff559152 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 3 Oct 2022 14:32:45 +0300 Subject: drm/i915: Make the DRRS debugfs contents more consistent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The stuff in the DRRS debugs is currently a hodgepode mix of camelcase, lowercase, spaces, undescores, you name it. Convert over to a reasonably common style. Also move the busy bits thing to be the last sine it's generally the least interesting thing in there. Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221003113249.16213-3-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_drrs.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_drrs.c b/drivers/gpu/drm/i915/display/intel_drrs.c index 030a3566538a..3639d8aa71c9 100644 --- a/drivers/gpu/drm/i915/display/intel_drrs.c +++ b/drivers/gpu/drm/i915/display/intel_drrs.c @@ -325,19 +325,19 @@ static int intel_drrs_debugfs_status_show(struct seq_file *m, void *unused) mutex_lock(&crtc->drrs.mutex); /* DRRS Supported */ - seq_printf(m, "\tDRRS Enabled: %s\n", + seq_printf(m, "\tDRRS enabled: %s\n", str_yes_no(crtc_state->has_drrs)); - seq_printf(m, "\tDRRS Active: %s\n", + seq_printf(m, "\tDRRS active: %s\n", str_yes_no(intel_drrs_is_active(crtc))); - seq_printf(m, "\tBusy_frontbuffer_bits: 0x%X\n", - crtc->drrs.busy_frontbuffer_bits); - seq_printf(m, "\tDRRS refresh rate: %s\n", crtc->drrs.refresh_rate == DRRS_REFRESH_RATE_LOW ? "low" : "high"); + seq_printf(m, "\tDRRS busy frontbuffer bits: 0x%X\n", + crtc->drrs.busy_frontbuffer_bits); + mutex_unlock(&crtc->drrs.mutex); } -- cgit From adc831bfc8852034d0834a5a8bf7e35e2faeb8b2 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 3 Oct 2022 14:32:46 +0300 Subject: drm/i915: Make DRRS debugfs per-crtc/connector MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since I already broke anything that relied on the old contents of the DRRS debugfs files might as well finish the breakage and convert the files to be per-crtc/connector so we don't need to have annoying code in igt to parse these. Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221003113249.16213-4-ville.syrjala@linux.intel.com --- .../gpu/drm/i915/display/intel_display_debugfs.c | 4 +- drivers/gpu/drm/i915/display/intel_drrs.c | 134 ++++++++++----------- drivers/gpu/drm/i915/display/intel_drrs.h | 3 +- 3 files changed, 69 insertions(+), 72 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c index df5a217d46ce..372a5b427e4f 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c @@ -1629,7 +1629,6 @@ void intel_display_debugfs_register(struct drm_i915_private *i915) minor->debugfs_root, minor); intel_dmc_debugfs_register(i915); - intel_drrs_debugfs_register(i915); intel_fbc_debugfs_register(i915); intel_hpd_debugfs_register(i915); skl_watermark_ipc_debugfs_register(i915); @@ -1945,6 +1944,8 @@ void intel_connector_debugfs_add(struct intel_connector *intel_connector) if (!root) return; + intel_drrs_connector_debugfs_add(intel_connector); + if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { debugfs_create_file("i915_panel_timings", S_IRUGO, root, connector, &i915_panel_fops); @@ -1997,6 +1998,7 @@ void intel_crtc_debugfs_add(struct drm_crtc *crtc) return; crtc_updates_add(crtc); + intel_drrs_crtc_debugfs_add(to_intel_crtc(crtc)); intel_fbc_crtc_debugfs_add(to_intel_crtc(crtc)); debugfs_create_file("i915_current_bpc", 0444, crtc->debugfs_entry, crtc, diff --git a/drivers/gpu/drm/i915/display/intel_drrs.c b/drivers/gpu/drm/i915/display/intel_drrs.c index 3639d8aa71c9..a5d6682475d1 100644 --- a/drivers/gpu/drm/i915/display/intel_drrs.c +++ b/drivers/gpu/drm/i915/display/intel_drrs.c @@ -300,46 +300,26 @@ void intel_crtc_drrs_init(struct intel_crtc *crtc) static int intel_drrs_debugfs_status_show(struct seq_file *m, void *unused) { - struct drm_i915_private *i915 = m->private; - struct drm_connector_list_iter conn_iter; - struct intel_connector *connector; - struct intel_crtc *crtc; - - drm_connector_list_iter_begin(&i915->drm, &conn_iter); - for_each_intel_connector_iter(connector, &conn_iter) { - seq_printf(m, "[CONNECTOR:%d:%s] DRRS type: %s\n", - connector->base.base.id, connector->base.name, - intel_drrs_type_str(intel_panel_drrs_type(connector))); - } - drm_connector_list_iter_end(&conn_iter); - - seq_puts(m, "\n"); - - for_each_intel_crtc(&i915->drm, crtc) { - const struct intel_crtc_state *crtc_state = - to_intel_crtc_state(crtc->base.state); + struct intel_crtc *crtc = m->private; + const struct intel_crtc_state *crtc_state = + to_intel_crtc_state(crtc->base.state); - seq_printf(m, "[CRTC:%d:%s]:\n", - crtc->base.base.id, crtc->base.name); - - mutex_lock(&crtc->drrs.mutex); + mutex_lock(&crtc->drrs.mutex); - /* DRRS Supported */ - seq_printf(m, "\tDRRS enabled: %s\n", - str_yes_no(crtc_state->has_drrs)); + seq_printf(m, "DRRS enabled: %s\n", + str_yes_no(crtc_state->has_drrs)); - seq_printf(m, "\tDRRS active: %s\n", - str_yes_no(intel_drrs_is_active(crtc))); + seq_printf(m, "DRRS active: %s\n", + str_yes_no(intel_drrs_is_active(crtc))); - seq_printf(m, "\tDRRS refresh rate: %s\n", - crtc->drrs.refresh_rate == DRRS_REFRESH_RATE_LOW ? - "low" : "high"); + seq_printf(m, "DRRS refresh rate: %s\n", + crtc->drrs.refresh_rate == DRRS_REFRESH_RATE_LOW ? + "low" : "high"); - seq_printf(m, "\tDRRS busy frontbuffer bits: 0x%X\n", - crtc->drrs.busy_frontbuffer_bits); + seq_printf(m, "DRRS busy frontbuffer bits: 0x%x\n", + crtc->drrs.busy_frontbuffer_bits); - mutex_unlock(&crtc->drrs.mutex); - } + mutex_unlock(&crtc->drrs.mutex); return 0; } @@ -348,58 +328,72 @@ DEFINE_SHOW_ATTRIBUTE(intel_drrs_debugfs_status); static int intel_drrs_debugfs_ctl_set(void *data, u64 val) { - struct drm_i915_private *i915 = data; - struct intel_crtc *crtc; + struct intel_crtc *crtc = data; + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + struct intel_crtc_state *crtc_state; + struct drm_crtc_commit *commit; + int ret; - for_each_intel_crtc(&i915->drm, crtc) { - struct intel_crtc_state *crtc_state; - struct drm_crtc_commit *commit; - int ret; + ret = drm_modeset_lock_single_interruptible(&crtc->base.mutex); + if (ret) + return ret; - ret = drm_modeset_lock_single_interruptible(&crtc->base.mutex); - if (ret) - return ret; + crtc_state = to_intel_crtc_state(crtc->base.state); - crtc_state = to_intel_crtc_state(crtc->base.state); + if (!crtc_state->hw.active || + !crtc_state->has_drrs) + goto out; - if (!crtc_state->hw.active || - !crtc_state->has_drrs) + commit = crtc_state->uapi.commit; + if (commit) { + ret = wait_for_completion_interruptible(&commit->hw_done); + if (ret) goto out; + } - commit = crtc_state->uapi.commit; - if (commit) { - ret = wait_for_completion_interruptible(&commit->hw_done); - if (ret) - goto out; - } - - drm_dbg(&i915->drm, - "Manually %sactivating DRRS\n", val ? "" : "de"); + drm_dbg(&i915->drm, + "Manually %sactivating DRRS\n", val ? "" : "de"); - if (val) - intel_drrs_activate(crtc_state); - else - intel_drrs_deactivate(crtc_state); + if (val) + intel_drrs_activate(crtc_state); + else + intel_drrs_deactivate(crtc_state); out: - drm_modeset_unlock(&crtc->base.mutex); - if (ret) - return ret; - } + drm_modeset_unlock(&crtc->base.mutex); - return 0; + return ret; } DEFINE_SIMPLE_ATTRIBUTE(intel_drrs_debugfs_ctl_fops, NULL, intel_drrs_debugfs_ctl_set, "%llu\n"); -void intel_drrs_debugfs_register(struct drm_i915_private *i915) +void intel_drrs_crtc_debugfs_add(struct intel_crtc *crtc) { - struct drm_minor *minor = i915->drm.primary; + debugfs_create_file("i915_drrs_status", 0444, crtc->base.debugfs_entry, + crtc, &intel_drrs_debugfs_status_fops); + + debugfs_create_file("i915_drrs_ctl", 0644, crtc->base.debugfs_entry, + crtc, &intel_drrs_debugfs_ctl_fops); +} - debugfs_create_file("i915_drrs_status", 0444, minor->debugfs_root, - i915, &intel_drrs_debugfs_status_fops); +static int intel_drrs_debugfs_type_show(struct seq_file *m, void *unused) +{ + struct intel_connector *connector = m->private; + + seq_printf(m, "DRRS type: %s\n", + intel_drrs_type_str(intel_panel_drrs_type(connector))); + + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(intel_drrs_debugfs_type); + +void intel_drrs_connector_debugfs_add(struct intel_connector *connector) +{ + if (intel_panel_drrs_type(connector) == DRRS_TYPE_NONE) + return; - debugfs_create_file("i915_drrs_ctl", 0644, minor->debugfs_root, - i915, &intel_drrs_debugfs_ctl_fops); + debugfs_create_file("i915_drrs_type", 0444, connector->base.debugfs_entry, + connector, &intel_drrs_debugfs_type_fops); } diff --git a/drivers/gpu/drm/i915/display/intel_drrs.h b/drivers/gpu/drm/i915/display/intel_drrs.h index 052055988341..041248bf5d67 100644 --- a/drivers/gpu/drm/i915/display/intel_drrs.h +++ b/drivers/gpu/drm/i915/display/intel_drrs.h @@ -24,6 +24,7 @@ void intel_drrs_invalidate(struct drm_i915_private *dev_priv, void intel_drrs_flush(struct drm_i915_private *dev_priv, unsigned int frontbuffer_bits); void intel_crtc_drrs_init(struct intel_crtc *crtc); -void intel_drrs_debugfs_register(struct drm_i915_private *i915); +void intel_drrs_crtc_debugfs_add(struct intel_crtc *crtc); +void intel_drrs_connector_debugfs_add(struct intel_connector *connector); #endif /* __INTEL_DRRS_H__ */ -- cgit From 9519c86523ea136e981ceff30489cdb7b2ecae08 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 3 Oct 2022 14:32:47 +0300 Subject: drm/i915: Fix locking in DRRS debugfs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Grab the crtc mutex so that looking at the crtc state is actually safe. Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221003113249.16213-5-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_drrs.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_drrs.c b/drivers/gpu/drm/i915/display/intel_drrs.c index a5d6682475d1..2b94a62ef65a 100644 --- a/drivers/gpu/drm/i915/display/intel_drrs.c +++ b/drivers/gpu/drm/i915/display/intel_drrs.c @@ -301,8 +301,14 @@ void intel_crtc_drrs_init(struct intel_crtc *crtc) static int intel_drrs_debugfs_status_show(struct seq_file *m, void *unused) { struct intel_crtc *crtc = m->private; - const struct intel_crtc_state *crtc_state = - to_intel_crtc_state(crtc->base.state); + const struct intel_crtc_state *crtc_state; + int ret; + + ret = drm_modeset_lock_single_interruptible(&crtc->base.mutex); + if (ret) + return ret; + + crtc_state = to_intel_crtc_state(crtc->base.state); mutex_lock(&crtc->drrs.mutex); @@ -321,6 +327,8 @@ static int intel_drrs_debugfs_status_show(struct seq_file *m, void *unused) mutex_unlock(&crtc->drrs.mutex); + drm_modeset_unlock(&crtc->base.mutex); + return 0; } -- cgit From 4ed1cc997f24c861df7a13d6309479b980d901b2 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 27 Sep 2022 17:41:31 -0700 Subject: mei: add support to GSC extended header GSC extend header is of variable size and data is provided in a sgl list inside the header and not in the data buffers, need to enable the path. Signed-off-by: Tomas Winkler Signed-off-by: Daniele Ceraolo Spurio Cc: Vitaly Lubart Cc: Greg Kroah-Hartman Reviewed-by: Greg Kroah-Hartman Link: https://patchwork.freedesktop.org/patch/msgid/20220928004145.745803-2-daniele.ceraolospurio@intel.com --- drivers/misc/mei/client.c | 55 ++++++++++++++++++++++-------- drivers/misc/mei/hbm.c | 13 +++++++ drivers/misc/mei/hw-me.c | 7 +++- drivers/misc/mei/hw.h | 81 ++++++++++++++++++++++++++++++++++++++++++++ drivers/misc/mei/interrupt.c | 47 +++++++++++++++++++++---- drivers/misc/mei/mei_dev.h | 4 +++ 6 files changed, 184 insertions(+), 23 deletions(-) diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index 0b2fbe1335a7..6c8b71ae32c8 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -322,6 +322,7 @@ void mei_io_cb_free(struct mei_cl_cb *cb) list_del(&cb->list); kfree(cb->buf.data); + kfree(cb->ext_hdr); kfree(cb); } @@ -401,6 +402,7 @@ static struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, cb->buf_idx = 0; cb->fop_type = type; cb->vtag = 0; + cb->ext_hdr = NULL; return cb; } @@ -1740,6 +1742,17 @@ static inline u8 mei_ext_hdr_set_vtag(void *ext, u8 vtag) return vtag_hdr->hdr.length; } +static inline bool mei_ext_hdr_is_gsc(struct mei_ext_hdr *ext) +{ + return ext && ext->type == MEI_EXT_HDR_GSC; +} + +static inline u8 mei_ext_hdr_set_gsc(struct mei_ext_hdr *ext, struct mei_ext_hdr *gsc_hdr) +{ + memcpy(ext, gsc_hdr, mei_ext_hdr_len(gsc_hdr)); + return ext->length; +} + /** * mei_msg_hdr_init - allocate and initialize mei message header * @@ -1752,14 +1765,17 @@ static struct mei_msg_hdr *mei_msg_hdr_init(const struct mei_cl_cb *cb) size_t hdr_len; struct mei_ext_meta_hdr *meta; struct mei_msg_hdr *mei_hdr; - bool is_ext, is_vtag; + bool is_ext, is_hbm, is_gsc, is_vtag; + struct mei_ext_hdr *next_ext; if (!cb) return ERR_PTR(-EINVAL); /* Extended header for vtag is attached only on the first fragment */ is_vtag = (cb->vtag && cb->buf_idx == 0); - is_ext = is_vtag; + is_hbm = cb->cl->me_cl->client_id == 0; + is_gsc = ((!is_hbm) && cb->cl->dev->hbm_f_gsc_supported && mei_ext_hdr_is_gsc(cb->ext_hdr)); + is_ext = is_vtag || is_gsc; /* Compute extended header size */ hdr_len = sizeof(*mei_hdr); @@ -1771,6 +1787,9 @@ static struct mei_msg_hdr *mei_msg_hdr_init(const struct mei_cl_cb *cb) if (is_vtag) hdr_len += sizeof(struct mei_ext_hdr_vtag); + if (is_gsc) + hdr_len += mei_ext_hdr_len(cb->ext_hdr); + setup_hdr: mei_hdr = kzalloc(hdr_len, GFP_KERNEL); if (!mei_hdr) @@ -1785,10 +1804,20 @@ setup_hdr: goto out; meta = (struct mei_ext_meta_hdr *)mei_hdr->extension; + meta->size = 0; + next_ext = (struct mei_ext_hdr *)meta->hdrs; if (is_vtag) { meta->count++; - meta->size += mei_ext_hdr_set_vtag(meta->hdrs, cb->vtag); + meta->size += mei_ext_hdr_set_vtag(next_ext, cb->vtag); + next_ext = mei_ext_next(next_ext); + } + + if (is_gsc) { + meta->count++; + meta->size += mei_ext_hdr_set_gsc(next_ext, cb->ext_hdr); + next_ext = mei_ext_next(next_ext); } + out: mei_hdr->length = hdr_len - sizeof(*mei_hdr); return mei_hdr; @@ -1812,14 +1841,14 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, struct mei_msg_hdr *mei_hdr = NULL; size_t hdr_len; size_t hbuf_len, dr_len; - size_t buf_len; + size_t buf_len = 0; size_t data_len; int hbuf_slots; u32 dr_slots; u32 dma_len; int rets; bool first_chunk; - const void *data; + const void *data = NULL; if (WARN_ON(!cl || !cl->dev)) return -ENODEV; @@ -1839,8 +1868,10 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, return 0; } - buf_len = buf->size - cb->buf_idx; - data = buf->data + cb->buf_idx; + if (buf->data) { + buf_len = buf->size - cb->buf_idx; + data = buf->data + cb->buf_idx; + } hbuf_slots = mei_hbuf_empty_slots(dev); if (hbuf_slots < 0) { rets = -EOVERFLOW; @@ -1858,9 +1889,6 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, goto err; } - cl_dbg(dev, cl, "Extended Header %d vtag = %d\n", - mei_hdr->extended, cb->vtag); - hdr_len = sizeof(*mei_hdr) + mei_hdr->length; /** @@ -1889,7 +1917,7 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, } mei_hdr->length += data_len; - if (mei_hdr->dma_ring) + if (mei_hdr->dma_ring && buf->data) mei_dma_ring_write(dev, buf->data + cb->buf_idx, buf_len); rets = mei_write_message(dev, mei_hdr, hdr_len, data, data_len); @@ -1983,9 +2011,6 @@ ssize_t mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb) goto err; } - cl_dbg(dev, cl, "Extended Header %d vtag = %d\n", - mei_hdr->extended, cb->vtag); - hdr_len = sizeof(*mei_hdr) + mei_hdr->length; if (rets == 0) { @@ -2030,7 +2055,7 @@ ssize_t mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb) mei_hdr->length += data_len; - if (mei_hdr->dma_ring) + if (mei_hdr->dma_ring && buf->data) mei_dma_ring_write(dev, buf->data, buf_len); rets = mei_write_message(dev, mei_hdr, hdr_len, data, data_len); diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c index de712cbf5d07..12a62a911e42 100644 --- a/drivers/misc/mei/hbm.c +++ b/drivers/misc/mei/hbm.c @@ -340,9 +340,13 @@ static int mei_hbm_capabilities_req(struct mei_device *dev) req.hbm_cmd = MEI_HBM_CAPABILITIES_REQ_CMD; if (dev->hbm_f_vt_supported) req.capability_requested[0] |= HBM_CAP_VT; + if (dev->hbm_f_cd_supported) req.capability_requested[0] |= HBM_CAP_CD; + if (dev->hbm_f_gsc_supported) + req.capability_requested[0] |= HBM_CAP_GSC; + ret = mei_hbm_write_message(dev, &mei_hdr, &req); if (ret) { dev_err(dev->dev, @@ -1200,6 +1204,12 @@ static void mei_hbm_config_features(struct mei_device *dev) dev->version.minor_version >= HBM_MINOR_VERSION_VT)) dev->hbm_f_vt_supported = 1; + /* GSC support */ + if (dev->version.major_version > HBM_MAJOR_VERSION_GSC || + (dev->version.major_version == HBM_MAJOR_VERSION_GSC && + dev->version.minor_version >= HBM_MINOR_VERSION_GSC)) + dev->hbm_f_gsc_supported = 1; + /* Capability message Support */ dev->hbm_f_cap_supported = 0; if (dev->version.major_version > HBM_MAJOR_VERSION_CAP || @@ -1367,6 +1377,9 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) if (!(capability_res->capability_granted[0] & HBM_CAP_CD)) dev->hbm_f_cd_supported = 0; + if (!(capability_res->capability_granted[0] & HBM_CAP_GSC)) + dev->hbm_f_gsc_supported = 0; + if (dev->hbm_f_dr_supported) { if (mei_dmam_ring_alloc(dev)) dev_info(dev->dev, "running w/o dma ring\n"); diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c index 9e2f781c6ed5..da4ef0b51954 100644 --- a/drivers/misc/mei/hw-me.c +++ b/drivers/misc/mei/hw-me.c @@ -590,9 +590,14 @@ static int mei_me_hbuf_write(struct mei_device *dev, u32 dw_cnt; int empty_slots; - if (WARN_ON(!hdr || !data || hdr_len & 0x3)) + if (WARN_ON(!hdr || hdr_len & 0x3)) return -EINVAL; + if (!data && data_len) { + dev_err(dev->dev, "wrong parameters null data with data_len = %zu\n", data_len); + return -EINVAL; + } + dev_dbg(dev->dev, MEI_HDR_FMT, MEI_HDR_PRM((struct mei_msg_hdr *)hdr)); empty_slots = mei_hbuf_empty_slots(dev); diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h index e7e020dba6b1..70d405c67f0e 100644 --- a/drivers/misc/mei/hw.h +++ b/drivers/misc/mei/hw.h @@ -92,6 +92,12 @@ #define HBM_MINOR_VERSION_VT 2 #define HBM_MAJOR_VERSION_VT 2 +/* + * MEI version with GSC support + */ +#define HBM_MINOR_VERSION_GSC 2 +#define HBM_MAJOR_VERSION_GSC 2 + /* * MEI version with capabilities message support */ @@ -229,10 +235,12 @@ enum mei_cl_disconnect_status { * * @MEI_EXT_HDR_NONE: sentinel * @MEI_EXT_HDR_VTAG: vtag header + * @MEI_EXT_HDR_GSC: gsc header */ enum mei_ext_hdr_type { MEI_EXT_HDR_NONE = 0, MEI_EXT_HDR_VTAG = 1, + MEI_EXT_HDR_GSC = 2, }; /** @@ -305,6 +313,60 @@ static inline bool mei_ext_last(struct mei_ext_meta_hdr *meta, return (u8 *)ext >= (u8 *)meta + sizeof(*meta) + (meta->size * 4); } +struct mei_gsc_sgl { + u32 low; + u32 high; + u32 length; +} __packed; + +#define GSC_HECI_MSG_KERNEL 0 +#define GSC_HECI_MSG_USER 1 + +#define GSC_ADDRESS_TYPE_GTT 0 +#define GSC_ADDRESS_TYPE_PPGTT 1 +#define GSC_ADDRESS_TYPE_PHYSICAL_CONTINUOUS 2 /* max of 64K */ +#define GSC_ADDRESS_TYPE_PHYSICAL_SGL 3 + +/** + * struct mei_ext_hdr_gsc_h2f - extended header: gsc host to firmware interface + * + * @hdr: extended header + * @client_id: GSC_HECI_MSG_KERNEL or GSC_HECI_MSG_USER + * @addr_type: GSC_ADDRESS_TYPE_{GTT, PPGTT, PHYSICAL_CONTINUOUS, PHYSICAL_SGL} + * @fence_id: synchronization marker + * @input_address_count: number of input sgl buffers + * @output_address_count: number of output sgl buffers + * @reserved: reserved + * @sgl: sg list + */ +struct mei_ext_hdr_gsc_h2f { + struct mei_ext_hdr hdr; + u8 client_id; + u8 addr_type; + u32 fence_id; + u8 input_address_count; + u8 output_address_count; + u8 reserved[2]; + struct mei_gsc_sgl sgl[]; +} __packed; + +/** + * struct mei_ext_hdr_gsc_f2h - gsc firmware to host interface + * + * @hdr: extended header + * @client_id: GSC_HECI_MSG_KERNEL or GSC_HECI_MSG_USER + * @reserved: reserved + * @fence_id: synchronization marker + * @written: number of bytes written to firmware + */ +struct mei_ext_hdr_gsc_f2h { + struct mei_ext_hdr hdr; + u8 client_id; + u8 reserved; + u32 fence_id; + u32 written; +} __packed; + /** * mei_ext_next - following extended header on the TLV list * @@ -320,6 +382,21 @@ static inline struct mei_ext_hdr *mei_ext_next(struct mei_ext_hdr *ext) return (struct mei_ext_hdr *)((u8 *)ext + (ext->length * 4)); } +/** + * mei_ext_hdr_len - get ext header length in bytes + * + * @ext: extend header + * + * Return: extend header length in bytes + */ +static inline u32 mei_ext_hdr_len(const struct mei_ext_hdr *ext) +{ + if (!ext) + return 0; + + return ext->length * sizeof(u32); +} + /** * struct mei_msg_hdr - MEI BUS Interface Section * @@ -682,6 +759,10 @@ struct hbm_dma_ring_ctrl { /* virtual tag supported */ #define HBM_CAP_VT BIT(0) + +/* gsc extended header support */ +#define HBM_CAP_GSC BIT(1) + /* client dma supported */ #define HBM_CAP_CD BIT(2) diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 0706322154cb..0a0e984e5673 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -98,9 +98,12 @@ static int mei_cl_irq_read_msg(struct mei_cl *cl, struct mei_device *dev = cl->dev; struct mei_cl_cb *cb; + struct mei_ext_hdr_vtag *vtag_hdr = NULL; + struct mei_ext_hdr_gsc_f2h *gsc_f2h = NULL; + size_t buf_sz; u32 length; - int ext_len; + u32 ext_len; length = mei_hdr->length; ext_len = 0; @@ -122,18 +125,24 @@ static int mei_cl_irq_read_msg(struct mei_cl *cl, } if (mei_hdr->extended) { - struct mei_ext_hdr *ext; - struct mei_ext_hdr_vtag *vtag_hdr = NULL; - - ext = mei_ext_begin(meta); + struct mei_ext_hdr *ext = mei_ext_begin(meta); do { switch (ext->type) { case MEI_EXT_HDR_VTAG: vtag_hdr = (struct mei_ext_hdr_vtag *)ext; break; + case MEI_EXT_HDR_GSC: + gsc_f2h = (struct mei_ext_hdr_gsc_f2h *)ext; + cb->ext_hdr = kzalloc(sizeof(*gsc_f2h), GFP_KERNEL); + if (!cb->ext_hdr) { + cb->status = -ENOMEM; + goto discard; + } + break; case MEI_EXT_HDR_NONE: fallthrough; default: + cl_err(dev, cl, "unknown extended header\n"); cb->status = -EPROTO; break; } @@ -141,12 +150,14 @@ static int mei_cl_irq_read_msg(struct mei_cl *cl, ext = mei_ext_next(ext); } while (!mei_ext_last(meta, ext)); - if (!vtag_hdr) { - cl_dbg(dev, cl, "vtag not found in extended header.\n"); + if (!vtag_hdr && !gsc_f2h) { + cl_dbg(dev, cl, "no vtag or gsc found in extended header.\n"); cb->status = -EPROTO; goto discard; } + } + if (vtag_hdr) { cl_dbg(dev, cl, "vtag: %d\n", vtag_hdr->vtag); if (cb->vtag && cb->vtag != vtag_hdr->vtag) { cl_err(dev, cl, "mismatched tag: %d != %d\n", @@ -157,6 +168,28 @@ static int mei_cl_irq_read_msg(struct mei_cl *cl, cb->vtag = vtag_hdr->vtag; } + if (gsc_f2h) { + u32 ext_hdr_len = mei_ext_hdr_len(&gsc_f2h->hdr); + + if (!dev->hbm_f_gsc_supported) { + cl_err(dev, cl, "gsc extended header is not supported\n"); + cb->status = -EPROTO; + goto discard; + } + + if (length) { + cl_err(dev, cl, "no data allowed in cb with gsc\n"); + cb->status = -EPROTO; + goto discard; + } + if (ext_hdr_len > sizeof(*gsc_f2h)) { + cl_err(dev, cl, "gsc extended header is too big %u\n", ext_hdr_len); + cb->status = -EPROTO; + goto discard; + } + memcpy(cb->ext_hdr, gsc_f2h, ext_hdr_len); + } + if (!mei_cl_is_connected(cl)) { cl_dbg(dev, cl, "not connected\n"); cb->status = -ENODEV; diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 6bb3e1ba9ded..31784bbc2d2a 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -206,6 +206,7 @@ struct mei_cl; * @status: io status of the cb * @internal: communication between driver and FW flag * @blocking: transmission blocking mode + * @ext_hdr: extended header */ struct mei_cl_cb { struct list_head list; @@ -218,6 +219,7 @@ struct mei_cl_cb { int status; u32 internal:1; u32 blocking:1; + struct mei_ext_hdr *ext_hdr; }; /** @@ -494,6 +496,7 @@ struct mei_dev_timeouts { * @hbm_f_vt_supported : hbm feature vtag supported * @hbm_f_cap_supported : hbm feature capabilities message supported * @hbm_f_cd_supported : hbm feature client dma supported + * @hbm_f_gsc_supported : hbm feature gsc supported * * @fw_ver : FW versions * @@ -585,6 +588,7 @@ struct mei_device { unsigned int hbm_f_vt_supported:1; unsigned int hbm_f_cap_supported:1; unsigned int hbm_f_cd_supported:1; + unsigned int hbm_f_gsc_supported:1; struct mei_fw_version fw_ver[MEI_MAX_FW_VER_BLOCKS]; -- cgit From 5d5bc18971543e82f6adf0b31745cf6545bc47a7 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 27 Sep 2022 17:41:32 -0700 Subject: mei: bus: enable sending gsc commands GSC command is and extended header containing a scatter gather list and without a data buffer. Using MEI_CL_IO_SGL flag, the caller send the GSC command as a data and the function internally moves it to the extended header. Signed-off-by: Tomas Winkler Signed-off-by: Daniele Ceraolo Spurio Cc: Vitaly Lubart Cc: Greg Kroah-Hartman Reviewed-by: Greg Kroah-Hartman Link: https://patchwork.freedesktop.org/patch/msgid/20220928004145.745803-3-daniele.ceraolospurio@intel.com --- drivers/misc/mei/bus.c | 20 ++++++++++++++++++-- drivers/misc/mei/mei_dev.h | 4 ++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 46aa3554e97b..225f0b04c021 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -100,9 +100,18 @@ ssize_t __mei_cl_send(struct mei_cl *cl, const u8 *buf, size_t length, u8 vtag, cb->internal = !!(mode & MEI_CL_IO_TX_INTERNAL); cb->blocking = !!(mode & MEI_CL_IO_TX_BLOCKING); memcpy(cb->buf.data, buf, length); + /* hack we point data to header */ + if (mode & MEI_CL_IO_SGL) { + cb->ext_hdr = (struct mei_ext_hdr *)cb->buf.data; + cb->buf.data = NULL; + cb->buf.size = 0; + } rets = mei_cl_write(cl, cb); + if (mode & MEI_CL_IO_SGL && rets == 0) + rets = length; + out: mutex_unlock(&bus->device_lock); @@ -205,9 +214,16 @@ copy: goto free; } - r_length = min_t(size_t, length, cb->buf_idx); - memcpy(buf, cb->buf.data, r_length); + /* for the GSC type - copy the extended header to the buffer */ + if (cb->ext_hdr && cb->ext_hdr->type == MEI_EXT_HDR_GSC) { + r_length = min_t(size_t, length, cb->ext_hdr->length * sizeof(u32)); + memcpy(buf, cb->ext_hdr, r_length); + } else { + r_length = min_t(size_t, length, cb->buf_idx); + memcpy(buf, cb->buf.data, r_length); + } rets = r_length; + if (vtag) *vtag = cb->vtag; diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 31784bbc2d2a..8d8018428d9d 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -116,12 +116,16 @@ enum mei_cb_file_ops { * @MEI_CL_IO_TX_INTERNAL: internal communication between driver and FW * * @MEI_CL_IO_RX_NONBLOCK: recv is non-blocking + * + * @MEI_CL_IO_SGL: send command with sgl list. */ enum mei_cl_io_mode { MEI_CL_IO_TX_BLOCKING = BIT(0), MEI_CL_IO_TX_INTERNAL = BIT(1), MEI_CL_IO_RX_NONBLOCK = BIT(2), + + MEI_CL_IO_SGL = BIT(3), }; /* -- cgit From 2af56dde08a1ae9ef8cfb1186d78d2b9620dc997 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 27 Sep 2022 17:41:33 -0700 Subject: mei: adjust extended header kdocs Fix kdoc for struct mei_ext_hdr and mei_ext_begin(). Signed-off-by: Tomas Winkler Signed-off-by: Daniele Ceraolo Spurio Cc: Greg Kroah-Hartman Reviewed-by: Greg Kroah-Hartman Link: https://patchwork.freedesktop.org/patch/msgid/20220928004145.745803-4-daniele.ceraolospurio@intel.com --- drivers/misc/mei/hw.h | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h index 70d405c67f0e..319418ddf4fb 100644 --- a/drivers/misc/mei/hw.h +++ b/drivers/misc/mei/hw.h @@ -247,8 +247,7 @@ enum mei_ext_hdr_type { * struct mei_ext_hdr - extend header descriptor (TLV) * @type: enum mei_ext_hdr_type * @length: length excluding descriptor - * @ext_payload: payload of the specific extended header - * @hdr: place holder for actual header + * @data: the extended header payload */ struct mei_ext_hdr { u8 type; @@ -287,12 +286,11 @@ struct mei_ext_hdr_vtag { * Extended header iterator functions */ /** - * mei_ext_hdr - extended header iterator begin + * mei_ext_begin - extended header iterator begin * * @meta: meta header of the extended header list * - * Return: - * The first extended header + * Return: The first extended header */ static inline struct mei_ext_hdr *mei_ext_begin(struct mei_ext_meta_hdr *meta) { -- cgit From 2266e58a1c08efacc97a46fd3793a3b1a9323741 Mon Sep 17 00:00:00 2001 From: Vitaly Lubart Date: Tue, 27 Sep 2022 17:41:34 -0700 Subject: mei: bus: extend bus API to support command streamer API Add mei bus API for sending gsc commands: mei_cldev_send_gsc_command() The GSC commands are originated in the graphics stack and are in form of SGL DMA buffers. The GSC commands are synchronous, the response is received in the same call on the out sg list buffers. The function setups pointers for in and out sg lists in the mei sgl extended header and sends it to the firmware. Signed-off-by: Vitaly Lubart Signed-off-by: Tomas Winkler Signed-off-by: Daniele Ceraolo Spurio Cc: Greg Kroah-Hartman Reviewed-by: Greg Kroah-Hartman Link: https://patchwork.freedesktop.org/patch/msgid/20220928004145.745803-5-daniele.ceraolospurio@intel.com --- drivers/misc/mei/bus.c | 126 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/mei_cl_bus.h | 6 +++ 2 files changed, 132 insertions(+) diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 225f0b04c021..1fbe127ff633 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "mei_dev.h" @@ -838,6 +839,131 @@ out: } EXPORT_SYMBOL_GPL(mei_cldev_disable); +/** + * mei_cldev_send_gsc_command - sends a gsc command, by sending + * a gsl mei message to gsc and receiving reply from gsc + * + * @cldev: me client device + * @client_id: client id to send the command to + * @fence_id: fence id to send the command to + * @sg_in: scatter gather list containing addresses for rx message buffer + * @total_in_len: total length of data in 'in' sg, can be less than the sum of buffers sizes + * @sg_out: scatter gather list containing addresses for tx message buffer + * + * Return: + * * written size in bytes + * * < 0 on error + */ +ssize_t mei_cldev_send_gsc_command(struct mei_cl_device *cldev, + u8 client_id, u32 fence_id, + struct scatterlist *sg_in, + size_t total_in_len, + struct scatterlist *sg_out) +{ + struct mei_cl *cl; + struct mei_device *bus; + ssize_t ret = 0; + + struct mei_ext_hdr_gsc_h2f *ext_hdr; + size_t buf_sz = sizeof(struct mei_ext_hdr_gsc_h2f); + int sg_out_nents, sg_in_nents; + int i; + struct scatterlist *sg; + struct mei_ext_hdr_gsc_f2h rx_msg; + unsigned int sg_len; + + if (!cldev || !sg_in || !sg_out) + return -EINVAL; + + cl = cldev->cl; + bus = cldev->bus; + + dev_dbg(bus->dev, "client_id %u, fence_id %u\n", client_id, fence_id); + + if (!bus->hbm_f_gsc_supported) + return -EOPNOTSUPP; + + sg_out_nents = sg_nents(sg_out); + sg_in_nents = sg_nents(sg_in); + /* at least one entry in tx and rx sgls must be present */ + if (sg_out_nents <= 0 || sg_in_nents <= 0) + return -EINVAL; + + buf_sz += (sg_out_nents + sg_in_nents) * sizeof(struct mei_gsc_sgl); + ext_hdr = kzalloc(buf_sz, GFP_KERNEL); + if (!ext_hdr) + return -ENOMEM; + + /* construct the GSC message */ + ext_hdr->hdr.type = MEI_EXT_HDR_GSC; + ext_hdr->hdr.length = buf_sz / sizeof(u32); /* length is in dw */ + + ext_hdr->client_id = client_id; + ext_hdr->addr_type = GSC_ADDRESS_TYPE_PHYSICAL_SGL; + ext_hdr->fence_id = fence_id; + ext_hdr->input_address_count = sg_in_nents; + ext_hdr->output_address_count = sg_out_nents; + ext_hdr->reserved[0] = 0; + ext_hdr->reserved[1] = 0; + + /* copy in-sgl to the message */ + for (i = 0, sg = sg_in; i < sg_in_nents; i++, sg++) { + ext_hdr->sgl[i].low = lower_32_bits(sg_dma_address(sg)); + ext_hdr->sgl[i].high = upper_32_bits(sg_dma_address(sg)); + sg_len = min_t(unsigned int, sg_dma_len(sg), PAGE_SIZE); + ext_hdr->sgl[i].length = (sg_len <= total_in_len) ? sg_len : total_in_len; + total_in_len -= ext_hdr->sgl[i].length; + } + + /* copy out-sgl to the message */ + for (i = sg_in_nents, sg = sg_out; i < sg_in_nents + sg_out_nents; i++, sg++) { + ext_hdr->sgl[i].low = lower_32_bits(sg_dma_address(sg)); + ext_hdr->sgl[i].high = upper_32_bits(sg_dma_address(sg)); + sg_len = min_t(unsigned int, sg_dma_len(sg), PAGE_SIZE); + ext_hdr->sgl[i].length = sg_len; + } + + /* send the message to GSC */ + ret = __mei_cl_send(cl, (u8 *)ext_hdr, buf_sz, 0, MEI_CL_IO_SGL); + if (ret < 0) { + dev_err(bus->dev, "__mei_cl_send failed, returned %zd\n", ret); + goto end; + } + if (ret != buf_sz) { + dev_err(bus->dev, "__mei_cl_send returned %zd instead of expected %zd\n", + ret, buf_sz); + ret = -EIO; + goto end; + } + + /* receive the reply from GSC, note that at this point sg_in should contain the reply */ + ret = __mei_cl_recv(cl, (u8 *)&rx_msg, sizeof(rx_msg), NULL, MEI_CL_IO_SGL, 0); + + if (ret != sizeof(rx_msg)) { + dev_err(bus->dev, "__mei_cl_recv returned %zd instead of expected %zd\n", + ret, sizeof(rx_msg)); + if (ret >= 0) + ret = -EIO; + goto end; + } + + /* check rx_msg.client_id and rx_msg.fence_id match the ones we send */ + if (rx_msg.client_id != client_id || rx_msg.fence_id != fence_id) { + dev_err(bus->dev, "received client_id/fence_id %u/%u instead of %u/%u sent\n", + rx_msg.client_id, rx_msg.fence_id, client_id, fence_id); + ret = -EFAULT; + goto end; + } + + dev_dbg(bus->dev, "gsc command: successfully written %u bytes\n", rx_msg.written); + ret = rx_msg.written; + +end: + kfree(ext_hdr); + return ret; +} +EXPORT_SYMBOL_GPL(mei_cldev_send_gsc_command); + /** * mei_cl_device_find - find matching entry in the driver id table * diff --git a/include/linux/mei_cl_bus.h b/include/linux/mei_cl_bus.h index df1fab44ea5c..fd6e0620658d 100644 --- a/include/linux/mei_cl_bus.h +++ b/include/linux/mei_cl_bus.h @@ -11,6 +11,7 @@ struct mei_cl_device; struct mei_device; +struct scatterlist; typedef void (*mei_cldev_cb_t)(struct mei_cl_device *cldev); @@ -116,6 +117,11 @@ void mei_cldev_set_drvdata(struct mei_cl_device *cldev, void *data); int mei_cldev_enable(struct mei_cl_device *cldev); int mei_cldev_disable(struct mei_cl_device *cldev); bool mei_cldev_enabled(const struct mei_cl_device *cldev); +ssize_t mei_cldev_send_gsc_command(struct mei_cl_device *cldev, + u8 client_id, u32 fence_id, + struct scatterlist *sg_in, + size_t total_in_len, + struct scatterlist *sg_out); void *mei_cldev_dma_map(struct mei_cl_device *cldev, u8 buffer_id, size_t size); int mei_cldev_dma_unmap(struct mei_cl_device *cldev); -- cgit From c72891256a8068a4c6e335f3e6944e53539230bb Mon Sep 17 00:00:00 2001 From: Vitaly Lubart Date: Tue, 27 Sep 2022 17:41:35 -0700 Subject: mei: pxp: add command streamer API to the PXP driver The discrete graphics card with GSC firmware using command streamer API hence it requires to enhance pxp module with the new gsc_command() handler. The handler is implemented via mei_pxp_gsc_command() which is just a thin wrapper around mei_cldev_send_gsc_command() Signed-off-by: Vitaly Lubart Signed-off-by: Tomas Winkler Signed-off-by: Daniele Ceraolo Spurio Cc: Greg Kroah-Hartman Reviewed-by: Alan Previn Reviewed-by: Greg Kroah-Hartman Link: https://patchwork.freedesktop.org/patch/msgid/20220928004145.745803-6-daniele.ceraolospurio@intel.com --- drivers/misc/mei/pxp/mei_pxp.c | 25 +++++++++++++++++++++++++ include/drm/i915_pxp_tee_interface.h | 5 +++++ 2 files changed, 30 insertions(+) diff --git a/drivers/misc/mei/pxp/mei_pxp.c b/drivers/misc/mei/pxp/mei_pxp.c index 5c39457e3f53..f221464c4009 100644 --- a/drivers/misc/mei/pxp/mei_pxp.c +++ b/drivers/misc/mei/pxp/mei_pxp.c @@ -77,10 +77,35 @@ mei_pxp_receive_message(struct device *dev, void *buffer, size_t size) return byte; } +/** + * mei_pxp_gsc_command() - sends a gsc command, by sending + * a sgl mei message to gsc and receiving reply from gsc + * + * @dev: device corresponding to the mei_cl_device + * @client_id: client id to send the command to + * @fence_id: fence id to send the command to + * @sg_in: scatter gather list containing addresses for rx message buffer + * @total_in_len: total length of data in 'in' sg, can be less than the sum of buffers sizes + * @sg_out: scatter gather list containing addresses for tx message buffer + * + * Return: bytes sent on Success, <0 on Failure + */ +static ssize_t mei_pxp_gsc_command(struct device *dev, u8 client_id, u32 fence_id, + struct scatterlist *sg_in, size_t total_in_len, + struct scatterlist *sg_out) +{ + struct mei_cl_device *cldev; + + cldev = to_mei_cl_device(dev); + + return mei_cldev_send_gsc_command(cldev, client_id, fence_id, sg_in, total_in_len, sg_out); +} + static const struct i915_pxp_component_ops mei_pxp_ops = { .owner = THIS_MODULE, .send = mei_pxp_send_message, .recv = mei_pxp_receive_message, + .gsc_command = mei_pxp_gsc_command, }; static int mei_component_master_bind(struct device *dev) diff --git a/include/drm/i915_pxp_tee_interface.h b/include/drm/i915_pxp_tee_interface.h index af593ec64469..a702b6ec17f7 100644 --- a/include/drm/i915_pxp_tee_interface.h +++ b/include/drm/i915_pxp_tee_interface.h @@ -8,6 +8,7 @@ #include #include +struct scatterlist; /** * struct i915_pxp_component_ops - ops for PXP services. @@ -23,6 +24,10 @@ struct i915_pxp_component_ops { int (*send)(struct device *dev, const void *message, size_t size); int (*recv)(struct device *dev, void *buffer, size_t size); + ssize_t (*gsc_command)(struct device *dev, u8 client_id, u32 fence_id, + struct scatterlist *sg_in, size_t total_in_len, + struct scatterlist *sg_out); + }; /** -- cgit From bd58904a328fe53a5b8b8f03127c98b072e0986d Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 27 Sep 2022 17:41:36 -0700 Subject: mei: pxp: support matching with a gfx discrete card With on-boards graphics card, both i915 and MEI are in the same device hierarchy with the same parent, while for discrete gfx card the MEI is its child device. Adjust the match function for that scenario by matching MEI parent device with i915. Signed-off-by: Tomas Winkler Signed-off-by: Daniele Ceraolo Spurio Cc: Vitaly Lubart Cc: Greg Kroah-Hartman Reviewed-by: Alan Previn Reviewed-by: Greg Kroah-Hartman Link: https://patchwork.freedesktop.org/patch/msgid/20220928004145.745803-7-daniele.ceraolospurio@intel.com --- drivers/misc/mei/pxp/mei_pxp.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/misc/mei/pxp/mei_pxp.c b/drivers/misc/mei/pxp/mei_pxp.c index f221464c4009..8dd09b1722eb 100644 --- a/drivers/misc/mei/pxp/mei_pxp.c +++ b/drivers/misc/mei/pxp/mei_pxp.c @@ -156,17 +156,24 @@ static int mei_pxp_component_match(struct device *dev, int subcomponent, { struct device *base = data; + if (!dev) + return 0; + if (!dev->driver || strcmp(dev->driver->name, "i915") || subcomponent != I915_COMPONENT_PXP) return 0; base = base->parent; - if (!base) + if (!base) /* mei device */ return 0; - base = base->parent; - dev = dev->parent; + base = base->parent; /* pci device */ + /* for dgfx */ + if (base && dev == base) + return 1; + /* for pch */ + dev = dev->parent; return (base && dev && dev == base); } -- cgit From c5be8fc973830675a6463836e32b9a6e47852447 Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Tue, 27 Sep 2022 17:41:37 -0700 Subject: drm/i915/pxp: load the pxp module when we have a gsc-loaded huc The mei_pxp module is required to send the command to load authenticate the HuC to the GSC even if pxp is not in use for protected content management. Signed-off-by: Daniele Ceraolo Spurio Cc: Alan Previn Reviewed-by: Alan Previn Link: https://patchwork.freedesktop.org/patch/msgid/20220928004145.745803-8-daniele.ceraolospurio@intel.com --- drivers/gpu/drm/i915/Makefile | 10 +++++---- drivers/gpu/drm/i915/pxp/intel_pxp.c | 32 ++++++++++++++++++---------- drivers/gpu/drm/i915/pxp/intel_pxp.h | 32 ---------------------------- drivers/gpu/drm/i915/pxp/intel_pxp_irq.h | 8 +++++++ drivers/gpu/drm/i915/pxp/intel_pxp_session.c | 8 ++++++- drivers/gpu/drm/i915/pxp/intel_pxp_session.h | 11 +++++++--- drivers/gpu/drm/i915/pxp/intel_pxp_tee.c | 10 ++++++--- 7 files changed, 57 insertions(+), 54 deletions(-) diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index a26edcdadc21..26fc2f23c4e0 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -309,15 +309,17 @@ i915-y += \ i915-y += i915_perf.o -# Protected execution platform (PXP) support -i915-$(CONFIG_DRM_I915_PXP) += \ +# Protected execution platform (PXP) support. Base support is required for HuC +i915-y += \ pxp/intel_pxp.o \ + pxp/intel_pxp_tee.o + +i915-$(CONFIG_DRM_I915_PXP) += \ pxp/intel_pxp_cmd.o \ pxp/intel_pxp_debugfs.o \ pxp/intel_pxp_irq.o \ pxp/intel_pxp_pm.o \ - pxp/intel_pxp_session.o \ - pxp/intel_pxp_tee.o + pxp/intel_pxp_session.o # Post-mortem debug and GPU hang state capture i915-$(CONFIG_DRM_I915_CAPTURE_ERROR) += i915_gpu_error.o diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp.c b/drivers/gpu/drm/i915/pxp/intel_pxp.c index 69cdaaddc4a9..5efe61f67546 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp.c @@ -103,19 +103,15 @@ static int create_vcs_context(struct intel_pxp *pxp) static void destroy_vcs_context(struct intel_pxp *pxp) { - intel_engine_destroy_pinned_context(fetch_and_zero(&pxp->ce)); + if (pxp->ce) + intel_engine_destroy_pinned_context(fetch_and_zero(&pxp->ce)); } -void intel_pxp_init(struct intel_pxp *pxp) +static void pxp_init_full(struct intel_pxp *pxp) { struct intel_gt *gt = pxp_to_gt(pxp); int ret; - if (!HAS_PXP(gt->i915)) - return; - - mutex_init(&pxp->tee_mutex); - /* * we'll use the completion to check if there is a termination pending, * so we start it as completed and we reinit it when a termination @@ -124,8 +120,7 @@ void intel_pxp_init(struct intel_pxp *pxp) init_completion(&pxp->termination); complete_all(&pxp->termination); - mutex_init(&pxp->arb_mutex); - INIT_WORK(&pxp->session_work, intel_pxp_session_work); + intel_pxp_session_management_init(pxp); ret = create_vcs_context(pxp); if (ret) @@ -143,11 +138,26 @@ out_context: destroy_vcs_context(pxp); } -void intel_pxp_fini(struct intel_pxp *pxp) +void intel_pxp_init(struct intel_pxp *pxp) { - if (!intel_pxp_is_enabled(pxp)) + struct intel_gt *gt = pxp_to_gt(pxp); + + /* we rely on the mei PXP module */ + if (!IS_ENABLED(CONFIG_INTEL_MEI_PXP)) return; + /* + * If HuC is loaded by GSC but PXP is disabled, we can skip the init of + * the full PXP session/object management and just init the tee channel. + */ + if (HAS_PXP(gt->i915)) + pxp_init_full(pxp); + else if (intel_huc_is_loaded_by_gsc(>->uc.huc) && intel_uc_uses_huc(>->uc)) + intel_pxp_tee_component_init(pxp); +} + +void intel_pxp_fini(struct intel_pxp *pxp) +{ pxp->arb_is_valid = false; intel_pxp_tee_component_fini(pxp); diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp.h b/drivers/gpu/drm/i915/pxp/intel_pxp.h index 73847e535cab..2da309088c6d 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp.h +++ b/drivers/gpu/drm/i915/pxp/intel_pxp.h @@ -12,7 +12,6 @@ struct intel_pxp; struct drm_i915_gem_object; -#ifdef CONFIG_DRM_I915_PXP struct intel_gt *pxp_to_gt(const struct intel_pxp *pxp); bool intel_pxp_is_enabled(const struct intel_pxp *pxp); bool intel_pxp_is_active(const struct intel_pxp *pxp); @@ -32,36 +31,5 @@ int intel_pxp_key_check(struct intel_pxp *pxp, bool assign); void intel_pxp_invalidate(struct intel_pxp *pxp); -#else -static inline void intel_pxp_init(struct intel_pxp *pxp) -{ -} - -static inline void intel_pxp_fini(struct intel_pxp *pxp) -{ -} - -static inline int intel_pxp_start(struct intel_pxp *pxp) -{ - return -ENODEV; -} - -static inline bool intel_pxp_is_enabled(const struct intel_pxp *pxp) -{ - return false; -} - -static inline bool intel_pxp_is_active(const struct intel_pxp *pxp) -{ - return false; -} - -static inline int intel_pxp_key_check(struct intel_pxp *pxp, - struct drm_i915_gem_object *obj, - bool assign) -{ - return -ENODEV; -} -#endif #endif /* __INTEL_PXP_H__ */ diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_irq.h b/drivers/gpu/drm/i915/pxp/intel_pxp_irq.h index 8b5793654844..8c292dc86f68 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_irq.h +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_irq.h @@ -27,6 +27,14 @@ void intel_pxp_irq_handler(struct intel_pxp *pxp, u16 iir); static inline void intel_pxp_irq_handler(struct intel_pxp *pxp, u16 iir) { } + +static inline void intel_pxp_irq_enable(struct intel_pxp *pxp) +{ +} + +static inline void intel_pxp_irq_disable(struct intel_pxp *pxp) +{ +} #endif #endif /* __INTEL_PXP_IRQ_H__ */ diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_session.c b/drivers/gpu/drm/i915/pxp/intel_pxp_session.c index 1bb5b5249157..ecff0935adbf 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_session.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_session.c @@ -137,7 +137,7 @@ static void pxp_terminate_complete(struct intel_pxp *pxp) complete_all(&pxp->termination); } -void intel_pxp_session_work(struct work_struct *work) +static void pxp_session_work(struct work_struct *work) { struct intel_pxp *pxp = container_of(work, typeof(*pxp), session_work); struct intel_gt *gt = pxp_to_gt(pxp); @@ -172,3 +172,9 @@ void intel_pxp_session_work(struct work_struct *work) intel_runtime_pm_put(gt->uncore->rpm, wakeref); } + +void intel_pxp_session_management_init(struct intel_pxp *pxp) +{ + mutex_init(&pxp->arb_mutex); + INIT_WORK(&pxp->session_work, pxp_session_work); +} diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_session.h b/drivers/gpu/drm/i915/pxp/intel_pxp_session.h index ba4c9d2b94b7..903ac52cffa1 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_session.h +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_session.h @@ -8,8 +8,13 @@ #include -struct work_struct; - -void intel_pxp_session_work(struct work_struct *work); +struct intel_pxp; +#ifdef CONFIG_DRM_I915_PXP +void intel_pxp_session_management_init(struct intel_pxp *pxp); +#else +static inline void intel_pxp_session_management_init(struct intel_pxp *pxp) +{ +} +#endif #endif /* __INTEL_PXP_SESSION_H__ */ diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c index 4b6f5655fab5..2c1fc49ecec1 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c @@ -97,7 +97,8 @@ static int i915_pxp_tee_component_bind(struct device *i915_kdev, return 0; /* the component is required to fully start the PXP HW */ - intel_pxp_init_hw(pxp); + if (intel_pxp_is_enabled(pxp)) + intel_pxp_init_hw(pxp); intel_runtime_pm_put(&i915->runtime_pm, wakeref); @@ -111,8 +112,9 @@ static void i915_pxp_tee_component_unbind(struct device *i915_kdev, struct intel_pxp *pxp = i915_dev_to_pxp(i915_kdev); intel_wakeref_t wakeref; - with_intel_runtime_pm_if_in_use(&i915->runtime_pm, wakeref) - intel_pxp_fini_hw(pxp); + if (intel_pxp_is_enabled(pxp)) + with_intel_runtime_pm_if_in_use(&i915->runtime_pm, wakeref) + intel_pxp_fini_hw(pxp); mutex_lock(&pxp->tee_mutex); pxp->pxp_component = NULL; @@ -130,6 +132,8 @@ int intel_pxp_tee_component_init(struct intel_pxp *pxp) struct intel_gt *gt = pxp_to_gt(pxp); struct drm_i915_private *i915 = gt->i915; + mutex_init(&pxp->tee_mutex); + ret = component_add_typed(i915->drm.dev, &i915_pxp_tee_component_ops, I915_COMPONENT_PXP); if (ret < 0) { -- cgit From 9058f9d795ea9ad59fd579249a6d724d78dfeaf8 Mon Sep 17 00:00:00 2001 From: Vitaly Lubart Date: Tue, 27 Sep 2022 17:41:38 -0700 Subject: drm/i915/pxp: implement function for sending tee stream command Command to be sent via the stream interface are written to a local memory page, whose address is then provided to the GSC. The interface supports providing a full sg with multiple pages for both input and output messages, but since for now we only aim to support short and synchronous messages we can use a single page for both input and output. Note that the mei interface expects an sg of 4k pages, while our lmem pages are 64k. If we ever need to support more than 4k we'll need to convert. Added a TODO comment to the code to record this. Signed-off-by: Vitaly Lubart Signed-off-by: Tomas Winkler Signed-off-by: Daniele Ceraolo Spurio Cc: Rodrigo Vivi Cc: Alan Previn Reviewed-by: Alan Previn Link: https://patchwork.freedesktop.org/patch/msgid/20220928004145.745803-9-daniele.ceraolospurio@intel.com --- drivers/gpu/drm/i915/pxp/intel_pxp_tee.c | 115 ++++++++++++++++++++++++++++- drivers/gpu/drm/i915/pxp/intel_pxp_tee.h | 5 ++ drivers/gpu/drm/i915/pxp/intel_pxp_types.h | 6 ++ 3 files changed, 125 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c index 2c1fc49ecec1..f5912a446f2e 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c @@ -8,6 +8,8 @@ #include #include +#include "gem/i915_gem_lmem.h" + #include "i915_drv.h" #include "intel_pxp.h" #include "intel_pxp_session.h" @@ -69,6 +71,47 @@ unlock: return ret; } +int intel_pxp_tee_stream_message(struct intel_pxp *pxp, + u8 client_id, u32 fence_id, + void *msg_in, size_t msg_in_len, + void *msg_out, size_t msg_out_len) +{ + /* TODO: for bigger objects we need to use a sg of 4k pages */ + const size_t max_msg_size = PAGE_SIZE; + struct drm_i915_private *i915 = pxp_to_gt(pxp)->i915; + struct i915_pxp_component *pxp_component = pxp->pxp_component; + unsigned int offset = 0; + struct scatterlist *sg; + int ret; + + if (msg_in_len > max_msg_size || msg_out_len > max_msg_size) + return -ENOSPC; + + mutex_lock(&pxp->tee_mutex); + + if (unlikely(!pxp_component || !pxp_component->ops->gsc_command)) { + ret = -ENODEV; + goto unlock; + } + + GEM_BUG_ON(!pxp->stream_cmd.obj); + + sg = i915_gem_object_get_sg_dma(pxp->stream_cmd.obj, 0, &offset); + + memcpy(pxp->stream_cmd.vaddr, msg_in, msg_in_len); + + ret = pxp_component->ops->gsc_command(pxp_component->tee_dev, client_id, + fence_id, sg, msg_in_len, sg); + if (ret < 0) + drm_err(&i915->drm, "Failed to send PXP TEE gsc command\n"); + else + memcpy(msg_out, pxp->stream_cmd.vaddr, msg_out_len); + +unlock: + mutex_unlock(&pxp->tee_mutex); + return ret; +} + /** * i915_pxp_tee_component_bind - bind function to pass the function pointers to pxp_tee * @i915_kdev: pointer to i915 kernel device @@ -126,6 +169,66 @@ static const struct component_ops i915_pxp_tee_component_ops = { .unbind = i915_pxp_tee_component_unbind, }; +static int alloc_streaming_command(struct intel_pxp *pxp) +{ + struct drm_i915_private *i915 = pxp_to_gt(pxp)->i915; + struct drm_i915_gem_object *obj = NULL; + void *cmd; + int err; + + pxp->stream_cmd.obj = NULL; + pxp->stream_cmd.vaddr = NULL; + + if (!IS_DGFX(i915)) + return 0; + + /* allocate lmem object of one page for PXP command memory and store it */ + obj = i915_gem_object_create_lmem(i915, PAGE_SIZE, I915_BO_ALLOC_CONTIGUOUS); + if (IS_ERR(obj)) { + drm_err(&i915->drm, "Failed to allocate pxp streaming command!\n"); + return PTR_ERR(obj); + } + + err = i915_gem_object_pin_pages_unlocked(obj); + if (err) { + drm_err(&i915->drm, "Failed to pin gsc message page!\n"); + goto out_put; + } + + /* map the lmem into the virtual memory pointer */ + cmd = i915_gem_object_pin_map_unlocked(obj, i915_coherent_map_type(i915, obj, true)); + if (IS_ERR(cmd)) { + drm_err(&i915->drm, "Failed to map gsc message page!\n"); + err = PTR_ERR(cmd); + goto out_unpin; + } + + memset(cmd, 0, obj->base.size); + + pxp->stream_cmd.obj = obj; + pxp->stream_cmd.vaddr = cmd; + + return 0; + +out_unpin: + i915_gem_object_unpin_pages(obj); +out_put: + i915_gem_object_put(obj); + return err; +} + +static void free_streaming_command(struct intel_pxp *pxp) +{ + struct drm_i915_gem_object *obj = fetch_and_zero(&pxp->stream_cmd.obj); + + if (!obj) + return; + + i915_gem_object_unpin_map(obj); + i915_gem_object_unpin_pages(obj); + i915_gem_object_put(obj); +} + int intel_pxp_tee_component_init(struct intel_pxp *pxp) { int ret; @@ -134,16 +237,24 @@ int intel_pxp_tee_component_init(struct intel_pxp *pxp) mutex_init(&pxp->tee_mutex); + ret = alloc_streaming_command(pxp); + if (ret) + return ret; + ret = component_add_typed(i915->drm.dev, &i915_pxp_tee_component_ops, I915_COMPONENT_PXP); if (ret < 0) { drm_err(&i915->drm, "Failed to add PXP component (%d)\n", ret); - return ret; + goto out_free; } pxp->pxp_component_added = true; return 0; + +out_free: + free_streaming_command(pxp); + return ret; } void intel_pxp_tee_component_fini(struct intel_pxp *pxp) @@ -155,6 +266,8 @@ void intel_pxp_tee_component_fini(struct intel_pxp *pxp) component_del(i915->drm.dev, &i915_pxp_tee_component_ops); pxp->pxp_component_added = false; + + free_streaming_command(pxp); } int intel_pxp_tee_cmd_create_arb_session(struct intel_pxp *pxp, diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_tee.h b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.h index c136053ce340..aeb3dfe7ce96 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_tee.h +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.h @@ -14,4 +14,9 @@ void intel_pxp_tee_component_fini(struct intel_pxp *pxp); int intel_pxp_tee_cmd_create_arb_session(struct intel_pxp *pxp, int arb_session_id); +int intel_pxp_tee_stream_message(struct intel_pxp *pxp, + u8 client_id, u32 fence_id, + void *msg_in, size_t msg_in_len, + void *msg_out, size_t msg_out_len); + #endif /* __INTEL_PXP_TEE_H__ */ diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_types.h b/drivers/gpu/drm/i915/pxp/intel_pxp_types.h index 7ce5f37ee12e..f74b1e11a505 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_types.h +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_types.h @@ -53,6 +53,12 @@ struct intel_pxp { /** @tee_mutex: protects the tee channel binding and messaging. */ struct mutex tee_mutex; + /** @stream_cmd: LMEM obj used to send stream PXP commands to the GSC */ + struct { + struct drm_i915_gem_object *obj; /* contains PXP command memory */ + void *vaddr; /* virtual memory for PXP command */ + } stream_cmd; + /** * @hw_state_invalidated: if the HW perceives an attack on the integrity * of the encryption it will invalidate the keys and expect SW to -- cgit From 887a193b4fb13e886d34bea4a1d8711fd775c7cf Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 27 Sep 2022 17:41:39 -0700 Subject: drm/i915/pxp: add huc authentication and loading command Add support for loading HuC via a pxp stream command. V4: 1. Remove unnecessary include in intel_pxp_huc.h (Jani) 2. Adjust copyright year to 2022 Signed-off-by: Tomas Winkler Signed-off-by: Vitaly Lubart Signed-off-by: Daniele Ceraolo Spurio Cc: Alan Previn Reviewed-by: Alan Previn Link: https://patchwork.freedesktop.org/patch/msgid/20220928004145.745803-10-daniele.ceraolospurio@intel.com --- drivers/gpu/drm/i915/Makefile | 3 +- drivers/gpu/drm/i915/pxp/intel_pxp_huc.c | 69 ++++++++++++++++++++++ drivers/gpu/drm/i915/pxp/intel_pxp_huc.h | 13 ++++ drivers/gpu/drm/i915/pxp/intel_pxp_tee_interface.h | 23 +++++++- 4 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 drivers/gpu/drm/i915/pxp/intel_pxp_huc.c create mode 100644 drivers/gpu/drm/i915/pxp/intel_pxp_huc.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 26fc2f23c4e0..f8cc1eb52626 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -312,7 +312,8 @@ i915-y += i915_perf.o # Protected execution platform (PXP) support. Base support is required for HuC i915-y += \ pxp/intel_pxp.o \ - pxp/intel_pxp_tee.o + pxp/intel_pxp_tee.o \ + pxp/intel_pxp_huc.o i915-$(CONFIG_DRM_I915_PXP) += \ pxp/intel_pxp_cmd.o \ diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_huc.c b/drivers/gpu/drm/i915/pxp/intel_pxp_huc.c new file mode 100644 index 000000000000..7ec36d94e758 --- /dev/null +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_huc.c @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright(c) 2021-2022, Intel Corporation. All rights reserved. + */ + +#include "drm/i915_drm.h" +#include "i915_drv.h" + +#include "gem/i915_gem_region.h" +#include "gt/intel_gt.h" + +#include "intel_pxp.h" +#include "intel_pxp_huc.h" +#include "intel_pxp_tee.h" +#include "intel_pxp_types.h" +#include "intel_pxp_tee_interface.h" + +int intel_pxp_huc_load_and_auth(struct intel_pxp *pxp) +{ + struct intel_gt *gt = pxp_to_gt(pxp); + struct intel_huc *huc = >->uc.huc; + struct pxp_tee_start_huc_auth_in huc_in = {0}; + struct pxp_tee_start_huc_auth_out huc_out = {0}; + dma_addr_t huc_phys_addr; + u8 client_id = 0; + u8 fence_id = 0; + int err; + + if (!pxp->pxp_component) + return -ENODEV; + + huc_phys_addr = i915_gem_object_get_dma_address(huc->fw.obj, 0); + + /* write the PXP message into the lmem (the sg list) */ + huc_in.header.api_version = PXP_TEE_43_APIVER; + huc_in.header.command_id = PXP_TEE_43_START_HUC_AUTH; + huc_in.header.status = 0; + huc_in.header.buffer_len = sizeof(huc_in.huc_base_address); + huc_in.huc_base_address = huc_phys_addr; + + err = intel_pxp_tee_stream_message(pxp, client_id, fence_id, + &huc_in, sizeof(huc_in), + &huc_out, sizeof(huc_out)); + if (err < 0) { + drm_err(>->i915->drm, + "Failed to send HuC load and auth command to GSC [%d]!\n", + err); + return err; + } + + /* + * HuC does sometimes survive suspend/resume (it depends on how "deep" + * a sleep state the device reaches) so we can end up here on resume + * with HuC already loaded, in which case the GSC will return + * PXP_STATUS_OP_NOT_PERMITTED. We can therefore consider the GuC + * correctly transferred in this scenario; if the same error is ever + * returned with HuC not loaded we'll still catch it when we check the + * authentication bit later. + */ + if (huc_out.header.status != PXP_STATUS_SUCCESS && + huc_out.header.status != PXP_STATUS_OP_NOT_PERMITTED) { + drm_err(>->i915->drm, + "HuC load failed with GSC error = 0x%x\n", + huc_out.header.status); + return -EPROTO; + } + + return 0; +} diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_huc.h b/drivers/gpu/drm/i915/pxp/intel_pxp_huc.h new file mode 100644 index 000000000000..e40847a91c39 --- /dev/null +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_huc.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright(c) 2021-2022, Intel Corporation. All rights reserved. + */ + +#ifndef __INTEL_PXP_HUC_H__ +#define __INTEL_PXP_HUC_H__ + +struct intel_pxp; + +int intel_pxp_huc_load_and_auth(struct intel_pxp *pxp); + +#endif /* __INTEL_PXP_HUC_H__ */ diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_tee_interface.h b/drivers/gpu/drm/i915/pxp/intel_pxp_tee_interface.h index 36e9b0868f5c..7edc1760f142 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_tee_interface.h +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_tee_interface.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: MIT */ /* - * Copyright(c) 2020, Intel Corporation. All rights reserved. + * Copyright(c) 2020-2022, Intel Corporation. All rights reserved. */ #ifndef __INTEL_PXP_TEE_INTERFACE_H__ @@ -9,8 +9,20 @@ #include #define PXP_TEE_APIVER 0x40002 +#define PXP_TEE_43_APIVER 0x00040003 #define PXP_TEE_ARB_CMDID 0x1e #define PXP_TEE_ARB_PROTECTION_MODE 0x2 +#define PXP_TEE_43_START_HUC_AUTH 0x0000003A + +/* + * there are a lot of status codes for PXP, but we only define the ones we + * actually can handle in the driver. other failure codes will be printed to + * error msg for debug. + */ +enum pxp_status { + PXP_STATUS_SUCCESS = 0x0, + PXP_STATUS_OP_NOT_PERMITTED = 0x4013 +}; /* PXP TEE message header */ struct pxp_tee_cmd_header { @@ -33,4 +45,13 @@ struct pxp_tee_create_arb_out { struct pxp_tee_cmd_header header; } __packed; +struct pxp_tee_start_huc_auth_in { + struct pxp_tee_cmd_header header; + __le64 huc_base_address; +}; + +struct pxp_tee_start_huc_auth_out { + struct pxp_tee_cmd_header header; +}; + #endif /* __INTEL_PXP_TEE_INTERFACE_H__ */ -- cgit From 087b681805f1de084f89f1041af67295aa981192 Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Tue, 27 Sep 2022 17:41:40 -0700 Subject: drm/i915/dg2: setup HuC loading via GSC The GSC will perform both the load and the authentication, so we just need to check the auth bit after the GSC has replied. Since we require the PXP module to load the HuC, the earliest we can trigger the load is during the pxp_bind operation. Note that GSC-loaded HuC survives GT reset, so we need to just mark it as ready when we re-init the GT HW. V2: move setting of HuC fw error state to the failure path of the HuC auth function, so it covers both the legacy and new auth flows V4: 1. Fix typo in the commit message 2. style fix in intel_huc_wait_for_auth_complete() Signed-off-by: Daniele Ceraolo Spurio Signed-off-by: Vitaly Lubart Signed-off-by: Tomas Winkler Reviewed-by: Alan Previn Link: https://patchwork.freedesktop.org/patch/msgid/20220928004145.745803-11-daniele.ceraolospurio@intel.com --- drivers/gpu/drm/i915/gt/uc/intel_huc.c | 41 ++++++++++++++++++++----------- drivers/gpu/drm/i915/gt/uc/intel_huc.h | 2 ++ drivers/gpu/drm/i915/gt/uc/intel_huc_fw.c | 34 +++++++++++++++++++++++++ drivers/gpu/drm/i915/gt/uc/intel_huc_fw.h | 1 + drivers/gpu/drm/i915/pxp/intel_pxp_tee.c | 14 ++++++++++- 5 files changed, 77 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_huc.c b/drivers/gpu/drm/i915/gt/uc/intel_huc.c index 3bb8838e325a..f0188931d8e4 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_huc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_huc.c @@ -125,6 +125,28 @@ void intel_huc_fini(struct intel_huc *huc) intel_uc_fw_fini(&huc->fw); } +int intel_huc_wait_for_auth_complete(struct intel_huc *huc) +{ + struct intel_gt *gt = huc_to_gt(huc); + int ret; + + ret = __intel_wait_for_register(gt->uncore, + huc->status.reg, + huc->status.mask, + huc->status.value, + 2, 50, NULL); + + if (ret) { + drm_err(>->i915->drm, "HuC: Firmware not verified %d\n", ret); + intel_uc_fw_change_status(&huc->fw, INTEL_UC_FIRMWARE_LOAD_FAIL); + return ret; + } + + intel_uc_fw_change_status(&huc->fw, INTEL_UC_FIRMWARE_RUNNING); + drm_info(>->i915->drm, "HuC authenticated\n"); + return 0; +} + /** * intel_huc_auth() - Authenticate HuC uCode * @huc: intel_huc structure @@ -161,27 +183,18 @@ int intel_huc_auth(struct intel_huc *huc) } /* Check authentication status, it should be done by now */ - ret = __intel_wait_for_register(gt->uncore, - huc->status.reg, - huc->status.mask, - huc->status.value, - 2, 50, NULL); - if (ret) { - DRM_ERROR("HuC: Firmware not verified %d\n", ret); + ret = intel_huc_wait_for_auth_complete(huc); + if (ret) goto fail; - } - intel_uc_fw_change_status(&huc->fw, INTEL_UC_FIRMWARE_RUNNING); - drm_info(>->i915->drm, "HuC authenticated\n"); return 0; fail: i915_probe_error(gt->i915, "HuC: Authentication failed %d\n", ret); - intel_uc_fw_change_status(&huc->fw, INTEL_UC_FIRMWARE_LOAD_FAIL); return ret; } -static bool huc_is_authenticated(struct intel_huc *huc) +bool intel_huc_is_authenticated(struct intel_huc *huc) { struct intel_gt *gt = huc_to_gt(huc); intel_wakeref_t wakeref; @@ -223,7 +236,7 @@ int intel_huc_check_status(struct intel_huc *huc) break; } - return huc_is_authenticated(huc); + return intel_huc_is_authenticated(huc); } void intel_huc_update_auth_status(struct intel_huc *huc) @@ -231,7 +244,7 @@ void intel_huc_update_auth_status(struct intel_huc *huc) if (!intel_uc_fw_is_loadable(&huc->fw)) return; - if (huc_is_authenticated(huc)) + if (intel_huc_is_authenticated(huc)) intel_uc_fw_change_status(&huc->fw, INTEL_UC_FIRMWARE_RUNNING); } diff --git a/drivers/gpu/drm/i915/gt/uc/intel_huc.h b/drivers/gpu/drm/i915/gt/uc/intel_huc.h index d7e25b6e879e..51f9d96a3ca3 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_huc.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_huc.h @@ -26,8 +26,10 @@ void intel_huc_init_early(struct intel_huc *huc); int intel_huc_init(struct intel_huc *huc); void intel_huc_fini(struct intel_huc *huc); int intel_huc_auth(struct intel_huc *huc); +int intel_huc_wait_for_auth_complete(struct intel_huc *huc); int intel_huc_check_status(struct intel_huc *huc); void intel_huc_update_auth_status(struct intel_huc *huc); +bool intel_huc_is_authenticated(struct intel_huc *huc); static inline int intel_huc_sanitize(struct intel_huc *huc) { diff --git a/drivers/gpu/drm/i915/gt/uc/intel_huc_fw.c b/drivers/gpu/drm/i915/gt/uc/intel_huc_fw.c index 9d6ab1e01639..4f246416db17 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_huc_fw.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_huc_fw.c @@ -3,9 +3,43 @@ * Copyright © 2014-2019 Intel Corporation */ +#include "gt/intel_gsc.h" #include "gt/intel_gt.h" +#include "intel_huc.h" #include "intel_huc_fw.h" #include "i915_drv.h" +#include "pxp/intel_pxp_huc.h" + +int intel_huc_fw_load_and_auth_via_gsc(struct intel_huc *huc) +{ + int ret; + + if (!intel_huc_is_loaded_by_gsc(huc)) + return -ENODEV; + + if (!intel_uc_fw_is_loadable(&huc->fw)) + return -ENOEXEC; + + /* + * If we abort a suspend, HuC might still be loaded when the mei + * component gets re-bound and this function called again. If so, just + * mark the HuC as loaded. + */ + if (intel_huc_is_authenticated(huc)) { + intel_uc_fw_change_status(&huc->fw, INTEL_UC_FIRMWARE_RUNNING); + return 0; + } + + GEM_WARN_ON(intel_uc_fw_is_loaded(&huc->fw)); + + ret = intel_pxp_huc_load_and_auth(&huc_to_gt(huc)->pxp); + if (ret) + return ret; + + intel_uc_fw_change_status(&huc->fw, INTEL_UC_FIRMWARE_TRANSFERRED); + + return intel_huc_wait_for_auth_complete(huc); +} /** * intel_huc_fw_upload() - load HuC uCode to device via DMA transfer diff --git a/drivers/gpu/drm/i915/gt/uc/intel_huc_fw.h b/drivers/gpu/drm/i915/gt/uc/intel_huc_fw.h index 12f264ee3e0b..db42e238b45f 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_huc_fw.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_huc_fw.h @@ -8,6 +8,7 @@ struct intel_huc; +int intel_huc_fw_load_and_auth_via_gsc(struct intel_huc *huc); int intel_huc_fw_upload(struct intel_huc *huc); #endif diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c index f5912a446f2e..58471517d1e6 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c @@ -15,6 +15,7 @@ #include "intel_pxp_session.h" #include "intel_pxp_tee.h" #include "intel_pxp_tee_interface.h" +#include "intel_pxp_huc.h" static inline struct intel_pxp *i915_dev_to_pxp(struct device *i915_kdev) { @@ -127,13 +128,24 @@ static int i915_pxp_tee_component_bind(struct device *i915_kdev, { struct drm_i915_private *i915 = kdev_to_i915(i915_kdev); struct intel_pxp *pxp = i915_dev_to_pxp(i915_kdev); + struct intel_uc *uc = &pxp_to_gt(pxp)->uc; intel_wakeref_t wakeref; + int ret = 0; mutex_lock(&pxp->tee_mutex); pxp->pxp_component = data; pxp->pxp_component->tee_dev = tee_kdev; mutex_unlock(&pxp->tee_mutex); + if (intel_uc_uses_huc(uc) && intel_huc_is_loaded_by_gsc(&uc->huc)) { + with_intel_runtime_pm(&i915->runtime_pm, wakeref) { + /* load huc via pxp */ + ret = intel_huc_fw_load_and_auth_via_gsc(&uc->huc); + if (ret < 0) + drm_err(&i915->drm, "failed to load huc via gsc %d\n", ret); + } + } + /* if we are suspended, the HW will be re-initialized on resume */ wakeref = intel_runtime_pm_get_if_in_use(&i915->runtime_pm); if (!wakeref) @@ -145,7 +157,7 @@ static int i915_pxp_tee_component_bind(struct device *i915_kdev, intel_runtime_pm_put(&i915->runtime_pm, wakeref); - return 0; + return ret; } static void i915_pxp_tee_component_unbind(struct device *i915_kdev, -- cgit From 27536e03271da3dafcdddf735102041a26ad5bd0 Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Tue, 27 Sep 2022 17:41:41 -0700 Subject: drm/i915/huc: track delayed HuC load with a fence Given that HuC load is delayed on DG2, this patch adds support for a fence that can be used to wait for load completion. No waiters are added in this patch (they're coming up in the next one), to keep the focus of the patch on the tracking logic. The full HuC loading flow on boot DG2 is as follows: 1) i915 exports the GSC as an aux device; 2) the mei-gsc driver is loaded on the aux device; 3) the mei-pxp component is loaded; 4) mei-pxp calls back into i915 and we load the HuC. Between steps 1 and 2 there can be several seconds of gap, mainly due to the kernel doing other work during the boot. The resume flow is slightly different, because we don't need to re-expose or re-probe the aux device, so we go directly to step 3 once i915 and mei-gsc have completed their resume flow. Here's an example of the boot timing, captured with some logs added to i915: [ 17.908307] [drm] adding GSC device [ 17.915717] [drm] i915 probe done [ 22.282917] [drm] mei-gsc bound [ 22.938153] [drm] HuC authenticated Also to note is that if something goes wrong during GSC HW init the mei-gsc driver will still bind, but steps 3 and 4 will not happen. The status tracking is done by registering a bus_notifier to receive a callback when the mei-gsc driver binds, with a large enough timeout to account for delays. Once mei-gsc is bound, we switch to a smaller timeout to wait for the mei-pxp component to load. The fence is signalled on HuC load complete or if anything goes wrong in any of the tracking steps. Timeout are enforced via hrtimer callbacks. v2: fix includes (Jani) v5: gsc_notifier() remove unneeded () Signed-off-by: Daniele Ceraolo Spurio Reviewed-by: Alan Previn Link: https://patchwork.freedesktop.org/patch/msgid/20220928004145.745803-12-daniele.ceraolospurio@intel.com --- drivers/gpu/drm/i915/gt/intel_gsc.c | 22 +++- drivers/gpu/drm/i915/gt/uc/intel_huc.c | 199 +++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/gt/uc/intel_huc.h | 23 ++++ 3 files changed, 241 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gsc.c b/drivers/gpu/drm/i915/gt/intel_gsc.c index d56f75b605d8..976fdf27e790 100644 --- a/drivers/gpu/drm/i915/gt/intel_gsc.c +++ b/drivers/gpu/drm/i915/gt/intel_gsc.c @@ -143,8 +143,14 @@ static void gsc_destroy_one(struct drm_i915_private *i915, struct intel_gsc_intf *intf = &gsc->intf[intf_id]; if (intf->adev) { - auxiliary_device_delete(&intf->adev->aux_dev); - auxiliary_device_uninit(&intf->adev->aux_dev); + struct auxiliary_device *aux_dev = &intf->adev->aux_dev; + + if (intf_id == 0) + intel_huc_unregister_gsc_notifier(&gsc_to_gt(gsc)->uc.huc, + aux_dev->dev.bus); + + auxiliary_device_delete(aux_dev); + auxiliary_device_uninit(aux_dev); intf->adev = NULL; } @@ -243,14 +249,24 @@ add_device: goto fail; } + intf->adev = adev; /* needed by the notifier */ + + if (intf_id == 0) + intel_huc_register_gsc_notifier(&gsc_to_gt(gsc)->uc.huc, + aux_dev->dev.bus); + ret = auxiliary_device_add(aux_dev); if (ret < 0) { drm_err(&i915->drm, "gsc aux add failed %d\n", ret); + if (intf_id == 0) + intel_huc_unregister_gsc_notifier(&gsc_to_gt(gsc)->uc.huc, + aux_dev->dev.bus); + intf->adev = NULL; + /* adev will be freed with the put_device() and .release sequence */ auxiliary_device_uninit(aux_dev); goto fail; } - intf->adev = adev; return; fail: diff --git a/drivers/gpu/drm/i915/gt/uc/intel_huc.c b/drivers/gpu/drm/i915/gt/uc/intel_huc.c index f0188931d8e4..5f2144c78f8a 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_huc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_huc.c @@ -10,6 +10,9 @@ #include "intel_huc.h" #include "i915_drv.h" +#include +#include + /** * DOC: HuC * @@ -42,6 +45,164 @@ * HuC-specific commands. */ +/* + * MEI-GSC load is an async process. The probing of the exposed aux device + * (see intel_gsc.c) usually happens a few seconds after i915 probe, depending + * on when the kernel schedules it. Unless something goes terribly wrong, we're + * guaranteed for this to happen during boot, so the big timeout is a safety net + * that we never expect to need. + * MEI-PXP + HuC load usually takes ~300ms, but if the GSC needs to be resumed + * and/or reset, this can take longer. + */ +#define GSC_INIT_TIMEOUT_MS 10000 +#define PXP_INIT_TIMEOUT_MS 2000 + +static int sw_fence_dummy_notify(struct i915_sw_fence *sf, + enum i915_sw_fence_notify state) +{ + return NOTIFY_DONE; +} + +static void __delayed_huc_load_complete(struct intel_huc *huc) +{ + if (!i915_sw_fence_done(&huc->delayed_load.fence)) + i915_sw_fence_complete(&huc->delayed_load.fence); +} + +static void delayed_huc_load_complete(struct intel_huc *huc) +{ + hrtimer_cancel(&huc->delayed_load.timer); + __delayed_huc_load_complete(huc); +} + +static void __gsc_init_error(struct intel_huc *huc) +{ + huc->delayed_load.status = INTEL_HUC_DELAYED_LOAD_ERROR; + __delayed_huc_load_complete(huc); +} + +static void gsc_init_error(struct intel_huc *huc) +{ + hrtimer_cancel(&huc->delayed_load.timer); + __gsc_init_error(huc); +} + +static void gsc_init_done(struct intel_huc *huc) +{ + hrtimer_cancel(&huc->delayed_load.timer); + + /* MEI-GSC init is done, now we wait for MEI-PXP to bind */ + huc->delayed_load.status = INTEL_HUC_WAITING_ON_PXP; + if (!i915_sw_fence_done(&huc->delayed_load.fence)) + hrtimer_start(&huc->delayed_load.timer, + ms_to_ktime(PXP_INIT_TIMEOUT_MS), + HRTIMER_MODE_REL); +} + +static enum hrtimer_restart huc_delayed_load_timer_callback(struct hrtimer *hrtimer) +{ + struct intel_huc *huc = container_of(hrtimer, struct intel_huc, delayed_load.timer); + + if (!intel_huc_is_authenticated(huc)) { + drm_err(&huc_to_gt(huc)->i915->drm, + "timed out waiting for GSC init to load HuC\n"); + + __gsc_init_error(huc); + } + + return HRTIMER_NORESTART; +} + +static void huc_delayed_load_start(struct intel_huc *huc) +{ + ktime_t delay; + + GEM_BUG_ON(intel_huc_is_authenticated(huc)); + + /* + * On resume we don't have to wait for MEI-GSC to be re-probed, but we + * do need to wait for MEI-PXP to reset & re-bind + */ + switch (huc->delayed_load.status) { + case INTEL_HUC_WAITING_ON_GSC: + delay = ms_to_ktime(GSC_INIT_TIMEOUT_MS); + break; + case INTEL_HUC_WAITING_ON_PXP: + delay = ms_to_ktime(PXP_INIT_TIMEOUT_MS); + break; + default: + gsc_init_error(huc); + return; + } + + /* + * This fence is always complete unless we're waiting for the + * GSC device to come up to load the HuC. We arm the fence here + * and complete it when we confirm that the HuC is loaded from + * the PXP bind callback. + */ + GEM_BUG_ON(!i915_sw_fence_done(&huc->delayed_load.fence)); + i915_sw_fence_fini(&huc->delayed_load.fence); + i915_sw_fence_reinit(&huc->delayed_load.fence); + i915_sw_fence_await(&huc->delayed_load.fence); + i915_sw_fence_commit(&huc->delayed_load.fence); + + hrtimer_start(&huc->delayed_load.timer, delay, HRTIMER_MODE_REL); +} + +static int gsc_notifier(struct notifier_block *nb, unsigned long action, void *data) +{ + struct device *dev = data; + struct intel_huc *huc = container_of(nb, struct intel_huc, delayed_load.nb); + struct intel_gsc_intf *intf = &huc_to_gt(huc)->gsc.intf[0]; + + if (!intf->adev || &intf->adev->aux_dev.dev != dev) + return 0; + + switch (action) { + case BUS_NOTIFY_BOUND_DRIVER: /* mei driver bound to aux device */ + gsc_init_done(huc); + break; + + case BUS_NOTIFY_DRIVER_NOT_BOUND: /* mei driver fails to be bound */ + case BUS_NOTIFY_UNBIND_DRIVER: /* mei driver about to be unbound */ + drm_info(&huc_to_gt(huc)->i915->drm, + "mei driver not bound, disabling HuC load\n"); + gsc_init_error(huc); + break; + } + + return 0; +} + +void intel_huc_register_gsc_notifier(struct intel_huc *huc, struct bus_type *bus) +{ + int ret; + + if (!intel_huc_is_loaded_by_gsc(huc)) + return; + + huc->delayed_load.nb.notifier_call = gsc_notifier; + ret = bus_register_notifier(bus, &huc->delayed_load.nb); + if (ret) { + drm_err(&huc_to_gt(huc)->i915->drm, + "failed to register GSC notifier\n"); + huc->delayed_load.nb.notifier_call = NULL; + gsc_init_error(huc); + } +} + +void intel_huc_unregister_gsc_notifier(struct intel_huc *huc, struct bus_type *bus) +{ + if (!huc->delayed_load.nb.notifier_call) + return; + + delayed_huc_load_complete(huc); + + bus_unregister_notifier(bus, &huc->delayed_load.nb); + huc->delayed_load.nb.notifier_call = NULL; +} + void intel_huc_init_early(struct intel_huc *huc) { struct drm_i915_private *i915 = huc_to_gt(huc)->i915; @@ -57,6 +218,17 @@ void intel_huc_init_early(struct intel_huc *huc) huc->status.mask = HUC_FW_VERIFIED; huc->status.value = HUC_FW_VERIFIED; } + + /* + * Initialize fence to be complete as this is expected to be complete + * unless there is a delayed HuC reload in progress. + */ + i915_sw_fence_init(&huc->delayed_load.fence, + sw_fence_dummy_notify); + i915_sw_fence_commit(&huc->delayed_load.fence); + + hrtimer_init(&huc->delayed_load.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + huc->delayed_load.timer.function = huc_delayed_load_timer_callback; } #define HUC_LOAD_MODE_STRING(x) (x ? "GSC" : "legacy") @@ -122,9 +294,25 @@ void intel_huc_fini(struct intel_huc *huc) if (!intel_uc_fw_is_loadable(&huc->fw)) return; + delayed_huc_load_complete(huc); + + i915_sw_fence_fini(&huc->delayed_load.fence); intel_uc_fw_fini(&huc->fw); } +void intel_huc_suspend(struct intel_huc *huc) +{ + if (!intel_uc_fw_is_loadable(&huc->fw)) + return; + + /* + * in the unlikely case that we're suspending before the GSC has + * completed its loading sequence, just stop waiting. We'll restart + * on resume. + */ + delayed_huc_load_complete(huc); +} + int intel_huc_wait_for_auth_complete(struct intel_huc *huc) { struct intel_gt *gt = huc_to_gt(huc); @@ -136,6 +324,9 @@ int intel_huc_wait_for_auth_complete(struct intel_huc *huc) huc->status.value, 2, 50, NULL); + /* mark the load process as complete even if the wait failed */ + delayed_huc_load_complete(huc); + if (ret) { drm_err(>->i915->drm, "HuC: Firmware not verified %d\n", ret); intel_uc_fw_change_status(&huc->fw, INTEL_UC_FIRMWARE_LOAD_FAIL); @@ -239,6 +430,12 @@ int intel_huc_check_status(struct intel_huc *huc) return intel_huc_is_authenticated(huc); } +static bool huc_has_delayed_load(struct intel_huc *huc) +{ + return intel_huc_is_loaded_by_gsc(huc) && + (huc->delayed_load.status != INTEL_HUC_DELAYED_LOAD_ERROR); +} + void intel_huc_update_auth_status(struct intel_huc *huc) { if (!intel_uc_fw_is_loadable(&huc->fw)) @@ -247,6 +444,8 @@ void intel_huc_update_auth_status(struct intel_huc *huc) if (intel_huc_is_authenticated(huc)) intel_uc_fw_change_status(&huc->fw, INTEL_UC_FIRMWARE_RUNNING); + else if (huc_has_delayed_load(huc)) + huc_delayed_load_start(huc); } /** diff --git a/drivers/gpu/drm/i915/gt/uc/intel_huc.h b/drivers/gpu/drm/i915/gt/uc/intel_huc.h index 51f9d96a3ca3..915d281c1c72 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_huc.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_huc.h @@ -7,9 +7,21 @@ #define _INTEL_HUC_H_ #include "i915_reg_defs.h" +#include "i915_sw_fence.h" #include "intel_uc_fw.h" #include "intel_huc_fw.h" +#include +#include + +struct bus_type; + +enum intel_huc_delayed_load_status { + INTEL_HUC_WAITING_ON_GSC = 0, + INTEL_HUC_WAITING_ON_PXP, + INTEL_HUC_DELAYED_LOAD_ERROR, +}; + struct intel_huc { /* Generic uC firmware management */ struct intel_uc_fw fw; @@ -20,17 +32,28 @@ struct intel_huc { u32 mask; u32 value; } status; + + struct { + struct i915_sw_fence fence; + struct hrtimer timer; + struct notifier_block nb; + enum intel_huc_delayed_load_status status; + } delayed_load; }; void intel_huc_init_early(struct intel_huc *huc); int intel_huc_init(struct intel_huc *huc); void intel_huc_fini(struct intel_huc *huc); +void intel_huc_suspend(struct intel_huc *huc); int intel_huc_auth(struct intel_huc *huc); int intel_huc_wait_for_auth_complete(struct intel_huc *huc); int intel_huc_check_status(struct intel_huc *huc); void intel_huc_update_auth_status(struct intel_huc *huc); bool intel_huc_is_authenticated(struct intel_huc *huc); +void intel_huc_register_gsc_notifier(struct intel_huc *huc, struct bus_type *bus); +void intel_huc_unregister_gsc_notifier(struct intel_huc *huc, struct bus_type *bus); + static inline int intel_huc_sanitize(struct intel_huc *huc) { intel_uc_fw_sanitize(&huc->fw); -- cgit From e6177ec586d19fc62bba833ca0f6939f1a750928 Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Tue, 27 Sep 2022 17:41:42 -0700 Subject: drm/i915/huc: stall media submission until HuC is loaded Wait on the fence to be signalled to avoid the submissions finding HuC not yet loaded. v2: use dedicaded wait_queue_entry for waiting in HuC load, as submitq can't be re-used for it. Signed-off-by: Daniele Ceraolo Spurio Cc: Tony Ye Acked-by: Tony Ye Reviewed-by: Alan Previn Link: https://patchwork.freedesktop.org/patch/msgid/20220928004145.745803-13-daniele.ceraolospurio@intel.com --- drivers/gpu/drm/i915/gt/uc/intel_huc.h | 6 ++++++ drivers/gpu/drm/i915/i915_request.c | 24 ++++++++++++++++++++++++ drivers/gpu/drm/i915/i915_request.h | 5 +++++ 3 files changed, 35 insertions(+) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_huc.h b/drivers/gpu/drm/i915/gt/uc/intel_huc.h index 915d281c1c72..52db03620c60 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_huc.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_huc.h @@ -81,6 +81,12 @@ static inline bool intel_huc_is_loaded_by_gsc(const struct intel_huc *huc) return huc->fw.loaded_via_gsc; } +static inline bool intel_huc_wait_required(struct intel_huc *huc) +{ + return intel_huc_is_used(huc) && intel_huc_is_loaded_by_gsc(huc) && + !intel_huc_is_authenticated(huc); +} + void intel_huc_load_status(struct intel_huc *huc, struct drm_printer *p); #endif diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index 62fad16a55e8..f949a9495758 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -1621,6 +1621,20 @@ i915_request_await_object(struct i915_request *to, return ret; } +static void i915_request_await_huc(struct i915_request *rq) +{ + struct intel_huc *huc = &rq->context->engine->gt->uc.huc; + + /* don't stall kernel submissions! */ + if (!rcu_access_pointer(rq->context->gem_context)) + return; + + if (intel_huc_wait_required(huc)) + i915_sw_fence_await_sw_fence(&rq->submit, + &huc->delayed_load.fence, + &rq->hucq); +} + static struct i915_request * __i915_request_ensure_parallel_ordering(struct i915_request *rq, struct intel_timeline *timeline) @@ -1702,6 +1716,16 @@ __i915_request_add_to_timeline(struct i915_request *rq) struct intel_timeline *timeline = i915_request_timeline(rq); struct i915_request *prev; + /* + * Media workloads may require HuC, so stall them until HuC loading is + * complete. Note that HuC not being loaded when a user submission + * arrives can only happen when HuC is loaded via GSC and in that case + * we still expect the window between us starting to accept submissions + * and HuC loading completion to be small (a few hundred ms). + */ + if (rq->engine->class == VIDEO_DECODE_CLASS) + i915_request_await_huc(rq); + /* * Dependency tracking and request ordering along the timeline * is special cased so that we can eliminate redundant ordering diff --git a/drivers/gpu/drm/i915/i915_request.h b/drivers/gpu/drm/i915/i915_request.h index 47041ec68df8..f5e1bb5e857a 100644 --- a/drivers/gpu/drm/i915/i915_request.h +++ b/drivers/gpu/drm/i915/i915_request.h @@ -348,6 +348,11 @@ struct i915_request { #define GUC_PRIO_FINI 0xfe u8 guc_prio; + /** + * @hucq: wait queue entry used to wait on the HuC load to complete + */ + wait_queue_entry_t hucq; + I915_SELFTEST_DECLARE(struct { struct list_head link; unsigned long delay; -- cgit From b76c14c8fb2af1e481d51a4eeab8e0c0594824c0 Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Tue, 27 Sep 2022 17:41:43 -0700 Subject: drm/i915/huc: better define HuC status getparam possible return values. The current HuC status getparam return values are a bit confusing in regards to what happens in some scenarios. In particular, most of the error cases cause the ioctl to return an error, but a couple of them, INIT_FAIL and LOAD_FAIL, are not explicitly handled and neither is their expected return value documented; these 2 error cases therefore end up into the catch-all umbrella of the "HuC not loaded" case, with this case therefore including both some error scenarios and the load in progress one. The updates included in this patch change the handling so that all error cases behave the same way, i.e. return an errno code, and so that the HuC load in progress case is unambiguous. The patch also includes a small change to the FW init path to make sure we always transition to an error state if something goes wrong. Signed-off-by: Daniele Ceraolo Spurio Cc: Tvrtko Ursulin Cc: Tony Ye Acked-by: Tvrtko Ursulin Acked-by: Tony Ye Reviewed-by: Alan Previn Link: https://patchwork.freedesktop.org/patch/msgid/20220928004145.745803-14-daniele.ceraolospurio@intel.com --- drivers/gpu/drm/i915/gt/uc/intel_guc.c | 1 + drivers/gpu/drm/i915/gt/uc/intel_huc.c | 14 +++++++------- drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c | 1 - include/uapi/drm/i915_drm.h | 16 ++++++++++++++++ 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.c b/drivers/gpu/drm/i915/gt/uc/intel_guc.c index bac06e3d6f2c..27b09ba1d295 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.c @@ -441,6 +441,7 @@ err_log: err_fw: intel_uc_fw_fini(&guc->fw); out: + intel_uc_fw_change_status(&guc->fw, INTEL_UC_FIRMWARE_INIT_FAIL); i915_probe_error(gt->i915, "failed with %d\n", ret); return ret; } diff --git a/drivers/gpu/drm/i915/gt/uc/intel_huc.c b/drivers/gpu/drm/i915/gt/uc/intel_huc.c index 5f2144c78f8a..4d1cc383b681 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_huc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_huc.c @@ -285,6 +285,7 @@ int intel_huc_init(struct intel_huc *huc) return 0; out: + intel_uc_fw_change_status(&huc->fw, INTEL_UC_FIRMWARE_INIT_FAIL); drm_info(&i915->drm, "HuC init failed with %d\n", err); return err; } @@ -404,13 +405,8 @@ bool intel_huc_is_authenticated(struct intel_huc *huc) * This function reads status register to verify if HuC * firmware was successfully loaded. * - * Returns: - * * -ENODEV if HuC is not present on this platform, - * * -EOPNOTSUPP if HuC firmware is disabled, - * * -ENOPKG if HuC firmware was not installed, - * * -ENOEXEC if HuC firmware is invalid or mismatched, - * * 0 if HuC firmware is not running, - * * 1 if HuC firmware is authenticated and running. + * The return values match what is expected for the I915_PARAM_HUC_STATUS + * getparam. */ int intel_huc_check_status(struct intel_huc *huc) { @@ -423,6 +419,10 @@ int intel_huc_check_status(struct intel_huc *huc) return -ENOPKG; case INTEL_UC_FIRMWARE_ERROR: return -ENOEXEC; + case INTEL_UC_FIRMWARE_INIT_FAIL: + return -ENOMEM; + case INTEL_UC_FIRMWARE_LOAD_FAIL: + return -EIO; default: break; } diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c index b91ad4aede1f..9fae911026d5 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c @@ -904,7 +904,6 @@ int intel_uc_fw_init(struct intel_uc_fw *uc_fw) out_unpin: i915_gem_object_unpin_pages(uc_fw->obj); out: - intel_uc_fw_change_status(uc_fw, INTEL_UC_FIRMWARE_INIT_FAIL); return err; } diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index 520ad2691a99..629198f1d8d8 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -645,6 +645,22 @@ typedef struct drm_i915_irq_wait { */ #define I915_SCHEDULER_CAP_STATIC_PRIORITY_MAP (1ul << 5) +/* + * Query the status of HuC load. + * + * The query can fail in the following scenarios with the listed error codes: + * -ENODEV if HuC is not present on this platform, + * -EOPNOTSUPP if HuC firmware usage is disabled, + * -ENOPKG if HuC firmware fetch failed, + * -ENOEXEC if HuC firmware is invalid or mismatched, + * -ENOMEM if i915 failed to prepare the FW objects for transfer to the uC, + * -EIO if the FW transfer or the FW authentication failed. + * + * If the IOCTL is successful, the returned parameter will be set to one of the + * following values: + * * 0 if HuC firmware load is not complete, + * * 1 if HuC firmware is authenticated and running. + */ #define I915_PARAM_HUC_STATUS 42 /* Query whether DRM_I915_GEM_EXECBUFFER2 supports the ability to opt-out of -- cgit From a70eebb80022148dfd4d5f60fffd1914ff8e3683 Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Tue, 27 Sep 2022 17:41:44 -0700 Subject: drm/i915/huc: define gsc-compatible HuC fw for DG2 The fw name is different and we need to record the fact that the blob is gsc-loaded, so add a new macro to help. Note: A-step DG2 G10 does not support HuC loading via GSC and would require a separate firmware to be loaded the legacy way, but that's not a production stepping so we're not going to bother. v2: rebase on new fw fetch logic Signed-off-by: Daniele Ceraolo Spurio Cc: Tony Ye Acked-by: Tony Ye Reviewed-by: Alan Previn Link: https://patchwork.freedesktop.org/patch/msgid/20220928004145.745803-15-daniele.ceraolospurio@intel.com --- drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c index 9fae911026d5..de2843dc1307 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c @@ -93,7 +93,8 @@ void intel_uc_fw_change_status(struct intel_uc_fw *uc_fw, fw_def(BROXTON, 0, guc_mmp(bxt, 70, 1, 1)) \ fw_def(SKYLAKE, 0, guc_mmp(skl, 70, 1, 1)) -#define INTEL_HUC_FIRMWARE_DEFS(fw_def, huc_raw, huc_mmp) \ +#define INTEL_HUC_FIRMWARE_DEFS(fw_def, huc_raw, huc_mmp, huc_gsc) \ + fw_def(DG2, 0, huc_gsc(dg2)) \ fw_def(ALDERLAKE_P, 0, huc_raw(tgl)) \ fw_def(ALDERLAKE_P, 0, huc_mmp(tgl, 7, 9, 3)) \ fw_def(ALDERLAKE_S, 0, huc_raw(tgl)) \ @@ -141,6 +142,9 @@ void intel_uc_fw_change_status(struct intel_uc_fw *uc_fw, #define MAKE_HUC_FW_PATH_BLANK(prefix_) \ __MAKE_UC_FW_PATH_BLANK(prefix_, "_huc") +#define MAKE_HUC_FW_PATH_GSC(prefix_) \ + __MAKE_UC_FW_PATH_BLANK(prefix_, "_huc_gsc") + #define MAKE_HUC_FW_PATH_MMP(prefix_, major_, minor_, patch_) \ __MAKE_UC_FW_PATH_MMP(prefix_, "_huc_", major_, minor_, patch_) @@ -153,7 +157,7 @@ void intel_uc_fw_change_status(struct intel_uc_fw *uc_fw, MODULE_FIRMWARE(uc_); INTEL_GUC_FIRMWARE_DEFS(INTEL_UC_MODULE_FW, MAKE_GUC_FW_PATH_MAJOR, MAKE_GUC_FW_PATH_MMP) -INTEL_HUC_FIRMWARE_DEFS(INTEL_UC_MODULE_FW, MAKE_HUC_FW_PATH_BLANK, MAKE_HUC_FW_PATH_MMP) +INTEL_HUC_FIRMWARE_DEFS(INTEL_UC_MODULE_FW, MAKE_HUC_FW_PATH_BLANK, MAKE_HUC_FW_PATH_MMP, MAKE_HUC_FW_PATH_GSC) /* * The next expansion of the table macros (in __uc_fw_auto_select below) provides @@ -168,6 +172,7 @@ struct __packed uc_fw_blob { u8 major; u8 minor; u8 patch; + bool loaded_via_gsc; }; #define UC_FW_BLOB_BASE(major_, minor_, patch_, path_) \ @@ -176,16 +181,16 @@ struct __packed uc_fw_blob { .patch = patch_, \ .path = path_, -#define UC_FW_BLOB_NEW(major_, minor_, patch_, path_) \ +#define UC_FW_BLOB_NEW(major_, minor_, patch_, gsc_, path_) \ { UC_FW_BLOB_BASE(major_, minor_, patch_, path_) \ - .legacy = false } + .legacy = false, .loaded_via_gsc = gsc_ } #define UC_FW_BLOB_OLD(major_, minor_, patch_, path_) \ { UC_FW_BLOB_BASE(major_, minor_, patch_, path_) \ .legacy = true } #define GUC_FW_BLOB(prefix_, major_, minor_) \ - UC_FW_BLOB_NEW(major_, minor_, 0, \ + UC_FW_BLOB_NEW(major_, minor_, 0, false, \ MAKE_GUC_FW_PATH_MAJOR(prefix_, major_, minor_)) #define GUC_FW_BLOB_MMP(prefix_, major_, minor_, patch_) \ @@ -193,12 +198,15 @@ struct __packed uc_fw_blob { MAKE_GUC_FW_PATH_MMP(prefix_, major_, minor_, patch_)) #define HUC_FW_BLOB(prefix_) \ - UC_FW_BLOB_NEW(0, 0, 0, MAKE_HUC_FW_PATH_BLANK(prefix_)) + UC_FW_BLOB_NEW(0, 0, 0, false, MAKE_HUC_FW_PATH_BLANK(prefix_)) #define HUC_FW_BLOB_MMP(prefix_, major_, minor_, patch_) \ UC_FW_BLOB_OLD(major_, minor_, patch_, \ MAKE_HUC_FW_PATH_MMP(prefix_, major_, minor_, patch_)) +#define HUC_FW_BLOB_GSC(prefix_) \ + UC_FW_BLOB_NEW(0, 0, 0, true, MAKE_HUC_FW_PATH_GSC(prefix_)) + struct __packed uc_fw_platform_requirement { enum intel_platform p; u8 rev; /* first platform rev using this FW */ @@ -224,7 +232,7 @@ __uc_fw_auto_select(struct drm_i915_private *i915, struct intel_uc_fw *uc_fw) INTEL_GUC_FIRMWARE_DEFS(MAKE_FW_LIST, GUC_FW_BLOB, GUC_FW_BLOB_MMP) }; static const struct uc_fw_platform_requirement blobs_huc[] = { - INTEL_HUC_FIRMWARE_DEFS(MAKE_FW_LIST, HUC_FW_BLOB, HUC_FW_BLOB_MMP) + INTEL_HUC_FIRMWARE_DEFS(MAKE_FW_LIST, HUC_FW_BLOB, HUC_FW_BLOB_MMP, HUC_FW_BLOB_GSC) }; static const struct fw_blobs_by_type blobs_all[INTEL_UC_FW_NUM_TYPES] = { [INTEL_UC_FW_TYPE_GUC] = { blobs_guc, ARRAY_SIZE(blobs_guc) }, @@ -272,6 +280,7 @@ __uc_fw_auto_select(struct drm_i915_private *i915, struct intel_uc_fw *uc_fw) uc_fw->file_wanted.path = blob->path; uc_fw->file_wanted.major_ver = blob->major; uc_fw->file_wanted.minor_ver = blob->minor; + uc_fw->loaded_via_gsc = blob->loaded_via_gsc; found = true; break; } -- cgit From bd8eb086611a7eb6bd03da2f4c3bddc64d082201 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 15 Sep 2022 16:31:56 +0000 Subject: drm/panel: db7430: Silent no spi_device_id warning Add spi_device_id entries to silent following SPI warning: SPI driver db7430-panel has no spi_device_id for samsung,lms397kf04 Signed-off-by: Wei Yongjun Signed-off-by: Linus Walleij Link: https://patchwork.freedesktop.org/patch/msgid/20220915163156.2519577-1-weiyongjun@huaweicloud.com --- drivers/gpu/drm/panel/panel-samsung-db7430.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-samsung-db7430.c b/drivers/gpu/drm/panel/panel-samsung-db7430.c index 04640c5256a8..117b26845083 100644 --- a/drivers/gpu/drm/panel/panel-samsung-db7430.c +++ b/drivers/gpu/drm/panel/panel-samsung-db7430.c @@ -331,9 +331,16 @@ static const struct of_device_id db7430_match[] = { }; MODULE_DEVICE_TABLE(of, db7430_match); +static const struct spi_device_id db7430_ids[] = { + { "lms397kf04" }, + { }, +}; +MODULE_DEVICE_TABLE(spi, db7430_ids); + static struct spi_driver db7430_driver = { .probe = db7430_probe, .remove = db7430_remove, + .id_table = db7430_ids, .driver = { .name = "db7430-panel", .of_match_table = db7430_match, -- cgit From b4c1b4ce5d273c9d2be360f6a655aeeb884f67e3 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 15 Sep 2022 16:34:31 +0000 Subject: drm/panel: tpg110: Silent no spi_device_id warning Add spi_device_id entries to silent following SPI warning: SPI driver tpo-tpg110-panel has no spi_device_id for tpo,tpg110 Signed-off-by: Wei Yongjun Signed-off-by: Linus Walleij Link: https://patchwork.freedesktop.org/patch/msgid/20220915163431.2519736-1-weiyongjun@huaweicloud.com --- drivers/gpu/drm/panel/panel-tpo-tpg110.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-tpo-tpg110.c b/drivers/gpu/drm/panel/panel-tpo-tpg110.c index 0b1f5a11a055..845304435e23 100644 --- a/drivers/gpu/drm/panel/panel-tpo-tpg110.c +++ b/drivers/gpu/drm/panel/panel-tpo-tpg110.c @@ -463,9 +463,16 @@ static const struct of_device_id tpg110_match[] = { }; MODULE_DEVICE_TABLE(of, tpg110_match); +static const struct spi_device_id tpg110_ids[] = { + { "tpg110" }, + { }, +}; +MODULE_DEVICE_TABLE(spi, tpg110_ids); + static struct spi_driver tpg110_driver = { .probe = tpg110_probe, .remove = tpg110_remove, + .id_table = tpg110_ids, .driver = { .name = "tpo-tpg110-panel", .of_match_table = tpg110_match, -- cgit From 353b6bf2c4f14f0049cc8db5c2cca26882ff76b4 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 15 Sep 2022 16:34:37 +0000 Subject: drm/panel: ws2401: Silent no spi_device_id warning Add spi_device_id entries to silent following SPI warning: SPI driver ws2401-panel has no spi_device_id for samsung,lms380kf01 Signed-off-by: Wei Yongjun Signed-off-by: Linus Walleij Link: https://patchwork.freedesktop.org/patch/msgid/20220915163437.2519754-1-weiyongjun@huaweicloud.com --- drivers/gpu/drm/panel/panel-widechips-ws2401.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-widechips-ws2401.c b/drivers/gpu/drm/panel/panel-widechips-ws2401.c index 236f3cb2b594..2591ff8f0d4e 100644 --- a/drivers/gpu/drm/panel/panel-widechips-ws2401.c +++ b/drivers/gpu/drm/panel/panel-widechips-ws2401.c @@ -425,9 +425,16 @@ static const struct of_device_id ws2401_match[] = { }; MODULE_DEVICE_TABLE(of, ws2401_match); +static const struct spi_device_id ws2401_ids[] = { + { "lms380kf01" }, + { }, +}; +MODULE_DEVICE_TABLE(spi, ws2401_ids); + static struct spi_driver ws2401_driver = { .probe = ws2401_probe, .remove = ws2401_remove, + .id_table = ws2401_ids, .driver = { .name = "ws2401-panel", .of_match_table = ws2401_match, -- cgit From 10517777d302d2e09bee3bf272dd28c0b0c8f3d0 Mon Sep 17 00:00:00 2001 From: Pin-yen Lin Date: Tue, 4 Oct 2022 12:49:42 +0800 Subject: drm/bridge: it6505: Adapt runtime power management framework Use pm_runtime_(get|put)_sync to control the bridge power, and add SET_SYSTEM_SLEEP_PM_OPS with pm_runtime_force_(suspend|resume) to it6505 driver. Without SET_SYSTEM_SLEEP_PM_OPS, the bridge will be powered on unnecessarily when no external display is connected. Fixes: b5c84a9edcd4 ("drm/bridge: add it6505 driver") Signed-off-by: Pin-yen Lin Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20221004044943.2407781-2-treapking@chromium.org --- drivers/gpu/drm/bridge/ite-it6505.c | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c index 2767b70fa2cb..ae1105334ca5 100644 --- a/drivers/gpu/drm/bridge/ite-it6505.c +++ b/drivers/gpu/drm/bridge/ite-it6505.c @@ -421,6 +421,7 @@ struct it6505 { struct notifier_block event_nb; struct extcon_dev *extcon; struct work_struct extcon_wq; + int extcon_state; enum drm_connector_status connector_status; enum link_train_status link_state; struct work_struct link_works; @@ -2685,31 +2686,41 @@ static void it6505_extcon_work(struct work_struct *work) { struct it6505 *it6505 = container_of(work, struct it6505, extcon_wq); struct device *dev = &it6505->client->dev; - int state = extcon_get_state(it6505->extcon, EXTCON_DISP_DP); - unsigned int pwroffretry = 0; + int state, ret; if (it6505->enable_drv_hold) return; mutex_lock(&it6505->extcon_lock); + state = extcon_get_state(it6505->extcon, EXTCON_DISP_DP); DRM_DEV_DEBUG_DRIVER(dev, "EXTCON_DISP_DP = 0x%02x", state); - if (state > 0) { + + if (state == it6505->extcon_state || unlikely(state < 0)) + goto unlock; + it6505->extcon_state = state; + if (state) { DRM_DEV_DEBUG_DRIVER(dev, "start to power on"); msleep(100); - it6505_poweron(it6505); + ret = pm_runtime_get_sync(dev); + + /* + * On system resume, extcon_work can be triggered before + * pm_runtime_force_resume re-enables runtime power management. + * Handling the error here to make sure the bridge is powered on. + */ + if (ret) + it6505_poweron(it6505); } else { DRM_DEV_DEBUG_DRIVER(dev, "start to power off"); - while (it6505_poweroff(it6505) && pwroffretry++ < 5) { - DRM_DEV_DEBUG_DRIVER(dev, "power off fail %d times", - pwroffretry); - } + pm_runtime_put_sync(dev); drm_helper_hpd_irq_event(it6505->bridge.dev); memset(it6505->dpcd, 0, sizeof(it6505->dpcd)); DRM_DEV_DEBUG_DRIVER(dev, "power off it6505 success!"); } +unlock: mutex_unlock(&it6505->extcon_lock); } @@ -3032,8 +3043,10 @@ static __maybe_unused int it6505_bridge_suspend(struct device *dev) return it6505_poweroff(it6505); } -static SIMPLE_DEV_PM_OPS(it6505_bridge_pm_ops, it6505_bridge_suspend, - it6505_bridge_resume); +static const struct dev_pm_ops it6505_bridge_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(it6505_bridge_suspend, it6505_bridge_resume, NULL) +}; static int it6505_init_pdata(struct it6505 *it6505) { @@ -3315,6 +3328,7 @@ static int it6505_i2c_probe(struct i2c_client *client, DRM_DEV_DEBUG_DRIVER(dev, "it6505 device name: %s", dev_name(dev)); debugfs_init(it6505); + pm_runtime_enable(dev); it6505->bridge.funcs = &it6505_bridge_funcs; it6505->bridge.type = DRM_MODE_CONNECTOR_DisplayPort; -- cgit From 439adf72726462a0245822d1434f908d451a46ad Mon Sep 17 00:00:00 2001 From: Pin-yen Lin Date: Tue, 4 Oct 2022 12:49:43 +0800 Subject: drm/bridge: it6505: Add pre_enable/post_disable callback Add atomic_pre_enable and atomic_post_disable callback to make sure the bridge is not powered off until atomic_post_disable is called. This prevents a power leakage when it6505 is powered off, but the upstream DRM bridge is still sending display signals. Fixes: b5c84a9edcd4 ("drm/bridge: add it6505 driver") Signed-off-by: Pin-yen Lin Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20221004044943.2407781-3-treapking@chromium.org --- drivers/gpu/drm/bridge/ite-it6505.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c index ae1105334ca5..a4302492cf8d 100644 --- a/drivers/gpu/drm/bridge/ite-it6505.c +++ b/drivers/gpu/drm/bridge/ite-it6505.c @@ -2991,6 +2991,28 @@ static void it6505_bridge_atomic_disable(struct drm_bridge *bridge, } } +static void it6505_bridge_atomic_pre_enable(struct drm_bridge *bridge, + struct drm_bridge_state *old_state) +{ + struct it6505 *it6505 = bridge_to_it6505(bridge); + struct device *dev = &it6505->client->dev; + + DRM_DEV_DEBUG_DRIVER(dev, "start"); + + pm_runtime_get_sync(dev); +} + +static void it6505_bridge_atomic_post_disable(struct drm_bridge *bridge, + struct drm_bridge_state *old_state) +{ + struct it6505 *it6505 = bridge_to_it6505(bridge); + struct device *dev = &it6505->client->dev; + + DRM_DEV_DEBUG_DRIVER(dev, "start"); + + pm_runtime_put_sync(dev); +} + static enum drm_connector_status it6505_bridge_detect(struct drm_bridge *bridge) { @@ -3025,6 +3047,8 @@ static const struct drm_bridge_funcs it6505_bridge_funcs = { .mode_valid = it6505_bridge_mode_valid, .atomic_enable = it6505_bridge_atomic_enable, .atomic_disable = it6505_bridge_atomic_disable, + .atomic_pre_enable = it6505_bridge_atomic_pre_enable, + .atomic_post_disable = it6505_bridge_atomic_post_disable, .detect = it6505_bridge_detect, .get_edid = it6505_bridge_get_edid, }; -- cgit From 96c92551b5ec2c0c5b0de0b4fa36cec27d4ae5ae Mon Sep 17 00:00:00 2001 From: Jilin Yuan Date: Wed, 7 Sep 2022 19:36:44 +0800 Subject: drm/edid: fix repeated words in comments Delete the redundant word 'on'. Signed-off-by: Jilin Yuan Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20220907113644.32831-1-yuanjilin@cdjrlc.com --- drivers/gpu/drm/drm_edid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 90a5e26eafa8..2c6ce81784cf 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -6825,7 +6825,7 @@ drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame, * by non-zero YQ when receiving RGB. There doesn't seem to be any * good way to tell which version of CEA-861 the sink supports, so * we limit non-zero YQ to HDMI 2.0 sinks only as HDMI 2.0 is based - * on on CEA-861-F. + * on CEA-861-F. */ if (!is_hdmi2_sink(connector) || rgb_quant_range == HDMI_QUANTIZATION_RANGE_LIMITED) -- cgit From c24538f538ef2f70c10f4326c1c0efd6ec6561c9 Mon Sep 17 00:00:00 2001 From: Gwan-gyeong Mun Date: Mon, 3 Oct 2022 20:02:42 +0300 Subject: drm/i915/gt: Remove unused function prototype Remove unused function prototype; intel_gt_create_kobj() Cc: Andi Shyti Signed-off-by: Gwan-gyeong Mun Reviewed-by: Andi Shyti Signed-off-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20221003170242.1246830-1-gwan-gyeong.mun@intel.com --- drivers/gpu/drm/i915/gt/intel_gt_sysfs.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_sysfs.h b/drivers/gpu/drm/i915/gt/intel_gt_sysfs.h index 6232923a420d..d637c6c3a69f 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_sysfs.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_sysfs.h @@ -18,11 +18,6 @@ bool is_object_gt(struct kobject *kobj); struct drm_i915_private *kobj_to_i915(struct kobject *kobj); -struct kobject * -intel_gt_create_kobj(struct intel_gt *gt, - struct kobject *dir, - const char *name); - static inline struct intel_gt *kobj_to_gt(struct kobject *kobj) { return container_of(kobj, struct intel_gt, sysfs_gt); -- cgit From f633a206ca3485adcfef4186b0c0f1ab03743b25 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 24 Aug 2022 19:43:42 +0200 Subject: drm: document uAPI page-flip flags Document flags accepted by the page-flip and atomic IOCTLs. v2 (Pekka): - Mention DRM_EVENT_FLIP_COMPLETE in DRM_MODE_PAGE_FLIP_EVENT docs. - Expand DRM_MODE_ATOMIC_NONBLOCK and DRM_MODE_ATOMIC_ALLOW_MODESET description. v3: - Fix struct field ref syntax (Daniel) - Clarify when artifacts are no longer displayed (Daniel) - Add note about sinks deciding to show artifacts on their own (Pekka, Daniel) v4: - Fix typo (Pekka) Signed-off-by: Simon Ser Reviewed-by: Pekka Paalanen Acked-by: Daniel Vetter Cc: Ville Syrjala Link: https://patchwork.freedesktop.org/patch/505107/ --- include/uapi/drm/drm_mode.h | 63 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index fa953309d9ce..46becedf5b2f 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -935,12 +935,31 @@ struct hdr_output_metadata { }; }; +/** + * DRM_MODE_PAGE_FLIP_EVENT + * + * Request that the kernel sends back a vblank event (see + * struct drm_event_vblank) with the &DRM_EVENT_FLIP_COMPLETE type when the + * page-flip is done. + */ #define DRM_MODE_PAGE_FLIP_EVENT 0x01 +/** + * DRM_MODE_PAGE_FLIP_ASYNC + * + * Request that the page-flip is performed as soon as possible, ie. with no + * delay due to waiting for vblank. This may cause tearing to be visible on + * the screen. + */ #define DRM_MODE_PAGE_FLIP_ASYNC 0x02 #define DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE 0x4 #define DRM_MODE_PAGE_FLIP_TARGET_RELATIVE 0x8 #define DRM_MODE_PAGE_FLIP_TARGET (DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE | \ DRM_MODE_PAGE_FLIP_TARGET_RELATIVE) +/** + * DRM_MODE_PAGE_FLIP_FLAGS + * + * Bitmask of flags suitable for &drm_mode_crtc_page_flip_target.flags. + */ #define DRM_MODE_PAGE_FLIP_FLAGS (DRM_MODE_PAGE_FLIP_EVENT | \ DRM_MODE_PAGE_FLIP_ASYNC | \ DRM_MODE_PAGE_FLIP_TARGET) @@ -1034,11 +1053,53 @@ struct drm_mode_destroy_dumb { __u32 handle; }; -/* page-flip flags are valid, plus: */ +/** + * DRM_MODE_ATOMIC_TEST_ONLY + * + * Do not apply the atomic commit, instead check whether the hardware supports + * this configuration. + * + * See &drm_mode_config_funcs.atomic_check for more details on test-only + * commits. + */ #define DRM_MODE_ATOMIC_TEST_ONLY 0x0100 +/** + * DRM_MODE_ATOMIC_NONBLOCK + * + * Do not block while applying the atomic commit. The &DRM_IOCTL_MODE_ATOMIC + * IOCTL returns immediately instead of waiting for the changes to be applied + * in hardware. Note, the driver will still check that the update can be + * applied before retuning. + */ #define DRM_MODE_ATOMIC_NONBLOCK 0x0200 +/** + * DRM_MODE_ATOMIC_ALLOW_MODESET + * + * Allow the update to result in temporary or transient visible artifacts while + * the update is being applied. Applying the update may also take significantly + * more time than a page flip. All visual artifacts will disappear by the time + * the update is completed, as signalled through the vblank event's timestamp + * (see struct drm_event_vblank). + * + * This flag must be set when the KMS update might cause visible artifacts. + * Without this flag such KMS update will return a EINVAL error. What kind of + * update may cause visible artifacts depends on the driver and the hardware. + * User-space that needs to know beforehand if an update might cause visible + * artifacts can use &DRM_MODE_ATOMIC_TEST_ONLY without + * &DRM_MODE_ATOMIC_ALLOW_MODESET to see if it fails. + * + * To the best of the driver's knowledge, visual artifacts are guaranteed to + * not appear when this flag is not set. Some sinks might display visual + * artifacts outside of the driver's control. + */ #define DRM_MODE_ATOMIC_ALLOW_MODESET 0x0400 +/** + * DRM_MODE_ATOMIC_FLAGS + * + * Bitfield of flags accepted by the &DRM_IOCTL_MODE_ATOMIC IOCTL in + * &drm_mode_atomic.flags. + */ #define DRM_MODE_ATOMIC_FLAGS (\ DRM_MODE_PAGE_FLIP_EVENT |\ DRM_MODE_PAGE_FLIP_ASYNC |\ -- cgit From 26b15eb0940c9a52aa997f6e6f00e3a6e628f107 Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Mon, 3 Oct 2022 18:28:19 +0100 Subject: drm/i915/ttm: implement access_memory It looks like we need this for local-memory, if we want to use ptrace. Something more is still needed if we want to handle non-mappable memory, which looks quite annoying. v2: - ttm_bo_kmap doesn't seem to work well here, and seems to expect contiguous resource. v3(Andi): - s/PAGE_SIZE/bytes/ when passing in the size of the mapping. References: https://gitlab.freedesktop.org/drm/intel/-/issues/6989 Signed-off-by: Matthew Auld Cc: Andrzej Hajda Cc: Nirmoy Das Cc: Andi Shyti Reviewed-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20221003172819.99245-1-matthew.auld@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 45 +++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c index 3dc6acfcf4ec..d11cd9c57247 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c @@ -699,6 +699,50 @@ static unsigned long i915_ttm_io_mem_pfn(struct ttm_buffer_object *bo, return ((base + sg_dma_address(sg)) >> PAGE_SHIFT) + ofs; } +static int i915_ttm_access_memory(struct ttm_buffer_object *bo, + unsigned long offset, void *buf, + int len, int write) +{ + struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo); + resource_size_t iomap = obj->mm.region->iomap.base - + obj->mm.region->region.start; + unsigned long page = offset >> PAGE_SHIFT; + unsigned long bytes_left = len; + + /* + * TODO: For now just let it fail if the resource is non-mappable, + * otherwise we need to perform the memcpy from the gpu here, without + * interfering with the object (like moving the entire thing). + */ + if (!i915_ttm_resource_mappable(bo->resource)) + return -EIO; + + offset -= page << PAGE_SHIFT; + do { + unsigned long bytes = min(bytes_left, PAGE_SIZE - offset); + void __iomem *ptr; + dma_addr_t daddr; + + daddr = i915_gem_object_get_dma_address(obj, page); + ptr = ioremap_wc(iomap + daddr + offset, bytes); + if (!ptr) + return -EIO; + + if (write) + memcpy_toio(ptr, buf, bytes); + else + memcpy_fromio(buf, ptr, bytes); + iounmap(ptr); + + page++; + buf += bytes; + bytes_left -= bytes; + offset = 0; + } while (bytes_left); + + return len; +} + /* * All callbacks need to take care not to downcast a struct ttm_buffer_object * without checking its subclass, since it might be a TTM ghost object. @@ -715,6 +759,7 @@ static struct ttm_device_funcs i915_ttm_bo_driver = { .delete_mem_notify = i915_ttm_delete_mem_notify, .io_mem_reserve = i915_ttm_io_mem_reserve, .io_mem_pfn = i915_ttm_io_mem_pfn, + .access_memory = i915_ttm_access_memory, }; /** -- cgit From d1af925ba062d78580a98ed8b1a013c0ac2b54ae Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 3 Oct 2022 14:32:48 +0300 Subject: drm/i915: Tighten DRRS capability reporting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only report DRRS capability for the connector if its fixed_modes list contains at least two modes capable of seamless DRRS switch between them. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221003113249.16213-6-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_panel.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_panel.c b/drivers/gpu/drm/i915/display/intel_panel.c index 41cec9dc4223..d18c56cf957d 100644 --- a/drivers/gpu/drm/i915/display/intel_panel.c +++ b/drivers/gpu/drm/i915/display/intel_panel.c @@ -147,10 +147,25 @@ int intel_panel_get_modes(struct intel_connector *connector) return num_modes; } +static bool has_drrs_modes(struct intel_connector *connector) +{ + const struct drm_display_mode *mode1; + + list_for_each_entry(mode1, &connector->panel.fixed_modes, head) { + const struct drm_display_mode *mode2 = mode1; + + list_for_each_entry_continue(mode2, &connector->panel.fixed_modes, head) { + if (is_alt_drrs_mode(mode1, mode2)) + return true; + } + } + + return false; +} + enum drrs_type intel_panel_drrs_type(struct intel_connector *connector) { - if (list_empty(&connector->panel.fixed_modes) || - list_is_singular(&connector->panel.fixed_modes)) + if (!has_drrs_modes(connector)) return DRRS_TYPE_NONE; return connector->panel.vbt.drrs_type; -- cgit From 22d9a2554dfa41301071c7ebb7002efa306a9290 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 3 Oct 2022 14:32:49 +0300 Subject: drm/i915: Setup final panel drrs_type already during init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that we track the VBT drrs type per-panel we can move the has_drrs_modes() check to the panel init rather than doing it for every intel_panel_drrs_type() call. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221003113249.16213-7-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_panel.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_panel.c b/drivers/gpu/drm/i915/display/intel_panel.c index d18c56cf957d..2b4b359b8342 100644 --- a/drivers/gpu/drm/i915/display/intel_panel.c +++ b/drivers/gpu/drm/i915/display/intel_panel.c @@ -165,9 +165,6 @@ static bool has_drrs_modes(struct intel_connector *connector) enum drrs_type intel_panel_drrs_type(struct intel_connector *connector) { - if (!has_drrs_modes(connector)) - return DRRS_TYPE_NONE; - return connector->panel.vbt.drrs_type; } @@ -668,6 +665,9 @@ int intel_panel_init(struct intel_connector *connector) intel_backlight_init_funcs(panel); + if (!has_drrs_modes(connector)) + connector->panel.vbt.drrs_type = DRRS_TYPE_NONE; + drm_dbg_kms(connector->base.dev, "[CONNECTOR:%d:%s] DRRS type: %s\n", connector->base.base.id, connector->base.name, -- cgit From 42172b551c0b9042d830e84beff5abd721cb5413 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Wed, 7 Sep 2022 14:24:10 -0700 Subject: drm/i915: Document and future-proof preemption control policy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Intel hardware allows some preemption settings to be controlled either by the kernel-mode driver exclusively, or placed under control of the user-mode drivers; on Linux we always select the userspace control option. The various registers involved in this are not documented very clearly; let's add some clarifying comments to help explain how this all works and provide some history on why our Linux drivers take the approach they do (which I believe differs from the path taken by certain other operating systems' drivers). While we're at it, let's also remove the graphics version 12 upper bound on this programming. As described, we don't have any plans to move away from UMD control of preemption settings on future platforms, and there's currently no reason to believe that the hardware will fundamentally change how these registers and settings work after version 12. Bspec: 45921, 45858, 45863 Cc: Joonas Lahtinen Cc: Jordan Justen Cc: Lionel Landwerlin Suggested-by: Joonas Lahtinen Signed-off-by: Matt Roper Reviewed-by: Wayne Boyer Acked-by: Tapani Pälli Link: https://patchwork.freedesktop.org/patch/msgid/20220907212410.22623-1-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/gt/intel_workarounds.c | 58 +++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c index ff5220694f46..b8eb20a155f0 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds.c +++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c @@ -2396,12 +2396,64 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) FF_DOP_CLOCK_GATE_DISABLE); } - if (IS_GRAPHICS_VER(i915, 9, 12)) { - /* FtrPerCtxtPreemptionGranularityControl:skl,bxt,kbl,cfl,cnl,icl,tgl */ + /* + * Intel platforms that support fine-grained preemption (i.e., gen9 and + * beyond) allow the kernel-mode driver to choose between two different + * options for controlling preemption granularity and behavior. + * + * Option 1 (hardware default): + * Preemption settings are controlled in a global manner via + * kernel-only register CS_DEBUG_MODE1 (0x20EC). Any granularity + * and settings chosen by the kernel-mode driver will apply to all + * userspace clients. + * + * Option 2: + * Preemption settings are controlled on a per-context basis via + * register CS_CHICKEN1 (0x2580). CS_CHICKEN1 is saved/restored on + * context switch and is writable by userspace (e.g., via + * MI_LOAD_REGISTER_IMMEDIATE instructions placed in a batch buffer) + * which allows different userspace drivers/clients to select + * different settings, or to change those settings on the fly in + * response to runtime needs. This option was known by name + * "FtrPerCtxtPreemptionGranularityControl" at one time, although + * that name is somewhat misleading as other non-granularity + * preemption settings are also impacted by this decision. + * + * On Linux, our policy has always been to let userspace drivers + * control preemption granularity/settings (Option 2). This was + * originally mandatory on gen9 to prevent ABI breakage (old gen9 + * userspace developed before object-level preemption was enabled would + * not behave well if i915 were to go with Option 1 and enable that + * preemption in a global manner). On gen9 each context would have + * object-level preemption disabled by default (see + * WaDisable3DMidCmdPreemption in gen9_ctx_workarounds_init), but + * userspace drivers could opt-in to object-level preemption as they + * saw fit. For post-gen9 platforms, we continue to utilize Option 2; + * even though it is no longer necessary for ABI compatibility when + * enabling a new platform, it does ensure that userspace will be able + * to implement any workarounds that show up requiring temporary + * adjustments to preemption behavior at runtime. + * + * Notes/Workarounds: + * - Wa_14015141709: On DG2 and early steppings of MTL, + * CS_CHICKEN1[0] does not disable object-level preemption as + * it is supposed to (nor does CS_DEBUG_MODE1[0] if we had been + * using Option 1). Effectively this means userspace is unable + * to disable object-level preemption on these platforms/steppings + * despite the setting here. + * + * - Wa_16013994831: May require that userspace program + * CS_CHICKEN1[10] when certain runtime conditions are true. + * Userspace requires Option 2 to be in effect for their update of + * CS_CHICKEN1[10] to be effective. + * + * Other workarounds may appear in the future that will also require + * Option 2 behavior to allow proper userspace implementation. + */ + if (GRAPHICS_VER(i915) >= 9) wa_masked_en(wal, GEN7_FF_SLICE_CS_CHICKEN1, GEN9_FFSC_PERCTX_PREEMPT_CTRL); - } if (IS_SKYLAKE(i915) || IS_KABYLAKE(i915) || -- cgit From 18feaf6d0784dcba888859109676adf1e0260dfd Mon Sep 17 00:00:00 2001 From: Ankit Nautiyal Date: Fri, 16 Sep 2022 15:35:48 +0530 Subject: drm/edid: Fix minimum bpc supported with DSC1.2 for HDMI sink HF-VSDB/SCDB has bits to advertise support for 16, 12 and 10 bpc. If none of the bits are set, the minimum bpc supported with DSC is 8. This patch corrects the min bpc supported to be 8, instead of 0. Fixes: 76ee7b905678 ("drm/edid: Parse DSC1.2 cap fields from HFVSDB block") Cc: Ankit Nautiyal Cc: Uma Shankar Cc: Jani Nikula Cc: Maarten Lankhorst v2: s/DSC1.2/DSC 1.2 Signed-off-by: Ankit Nautiyal Reviewed-by: Jani Nikula Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20220916100551.2531750-2-ankit.k.nautiyal@intel.com --- drivers/gpu/drm/drm_edid.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 2c6ce81784cf..39e669520552 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -5819,7 +5819,8 @@ static void drm_parse_hdmi_forum_scds(struct drm_connector *connector, else if (hf_scds[11] & DRM_EDID_DSC_10BPC) hdmi_dsc->bpc_supported = 10; else - hdmi_dsc->bpc_supported = 0; + /* Supports min 8 BPC if DSC 1.2 is supported*/ + hdmi_dsc->bpc_supported = 8; dsc_max_frl_rate = (hf_scds[12] & DRM_EDID_DSC_MAX_FRL_RATE_MASK) >> 4; drm_get_max_frl_rate(dsc_max_frl_rate, &hdmi_dsc->max_lanes, -- cgit From 5e706c4db90cd7fd8d9b883efced08558379934f Mon Sep 17 00:00:00 2001 From: Ankit Nautiyal Date: Fri, 16 Sep 2022 15:35:49 +0530 Subject: drm/edid: Split DSC parsing into separate function Move the DSC parsing logic into separate function. v2: Rebase. Signed-off-by: Ankit Nautiyal Reviewed-by: Jani Nikula Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20220916100551.2531750-3-ankit.k.nautiyal@intel.com --- drivers/gpu/drm/drm_edid.c | 128 ++++++++++++++++++++++++--------------------- 1 file changed, 69 insertions(+), 59 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 39e669520552..b949f83716ed 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -5752,6 +5752,73 @@ static void drm_parse_ycbcr420_deep_color_info(struct drm_connector *connector, hdmi->y420_dc_modes = dc_mask; } +static void drm_parse_dsc_info(struct drm_hdmi_dsc_cap *hdmi_dsc, + const u8 *hf_scds) +{ + u8 dsc_max_slices; + u8 dsc_max_frl_rate; + + hdmi_dsc->v_1p2 = hf_scds[11] & DRM_EDID_DSC_1P2; + + if (!hdmi_dsc->v_1p2) + return; + + hdmi_dsc->native_420 = hf_scds[11] & DRM_EDID_DSC_NATIVE_420; + hdmi_dsc->all_bpp = hf_scds[11] & DRM_EDID_DSC_ALL_BPP; + + if (hf_scds[11] & DRM_EDID_DSC_16BPC) + hdmi_dsc->bpc_supported = 16; + else if (hf_scds[11] & DRM_EDID_DSC_12BPC) + hdmi_dsc->bpc_supported = 12; + else if (hf_scds[11] & DRM_EDID_DSC_10BPC) + hdmi_dsc->bpc_supported = 10; + else + /* Supports min 8 BPC if DSC 1.2 is supported*/ + hdmi_dsc->bpc_supported = 8; + + dsc_max_frl_rate = (hf_scds[12] & DRM_EDID_DSC_MAX_FRL_RATE_MASK) >> 4; + drm_get_max_frl_rate(dsc_max_frl_rate, &hdmi_dsc->max_lanes, + &hdmi_dsc->max_frl_rate_per_lane); + hdmi_dsc->total_chunk_kbytes = hf_scds[13] & DRM_EDID_DSC_TOTAL_CHUNK_KBYTES; + + dsc_max_slices = hf_scds[12] & DRM_EDID_DSC_MAX_SLICES; + + switch (dsc_max_slices) { + case 1: + hdmi_dsc->max_slices = 1; + hdmi_dsc->clk_per_slice = 340; + break; + case 2: + hdmi_dsc->max_slices = 2; + hdmi_dsc->clk_per_slice = 340; + break; + case 3: + hdmi_dsc->max_slices = 4; + hdmi_dsc->clk_per_slice = 340; + break; + case 4: + hdmi_dsc->max_slices = 8; + hdmi_dsc->clk_per_slice = 340; + break; + case 5: + hdmi_dsc->max_slices = 8; + hdmi_dsc->clk_per_slice = 400; + break; + case 6: + hdmi_dsc->max_slices = 12; + hdmi_dsc->clk_per_slice = 400; + break; + case 7: + hdmi_dsc->max_slices = 16; + hdmi_dsc->clk_per_slice = 400; + break; + case 0: + default: + hdmi_dsc->max_slices = 0; + hdmi_dsc->clk_per_slice = 0; + } +} + /* Sink Capability Data Structure */ static void drm_parse_hdmi_forum_scds(struct drm_connector *connector, const u8 *hf_scds) @@ -5798,71 +5865,14 @@ static void drm_parse_hdmi_forum_scds(struct drm_connector *connector, if (hf_scds[7]) { u8 max_frl_rate; - u8 dsc_max_frl_rate; - u8 dsc_max_slices; struct drm_hdmi_dsc_cap *hdmi_dsc = &hdmi->dsc_cap; DRM_DEBUG_KMS("hdmi_21 sink detected. parsing edid\n"); max_frl_rate = (hf_scds[7] & DRM_EDID_MAX_FRL_RATE_MASK) >> 4; drm_get_max_frl_rate(max_frl_rate, &hdmi->max_lanes, &hdmi->max_frl_rate_per_lane); - hdmi_dsc->v_1p2 = hf_scds[11] & DRM_EDID_DSC_1P2; - - if (hdmi_dsc->v_1p2) { - hdmi_dsc->native_420 = hf_scds[11] & DRM_EDID_DSC_NATIVE_420; - hdmi_dsc->all_bpp = hf_scds[11] & DRM_EDID_DSC_ALL_BPP; - - if (hf_scds[11] & DRM_EDID_DSC_16BPC) - hdmi_dsc->bpc_supported = 16; - else if (hf_scds[11] & DRM_EDID_DSC_12BPC) - hdmi_dsc->bpc_supported = 12; - else if (hf_scds[11] & DRM_EDID_DSC_10BPC) - hdmi_dsc->bpc_supported = 10; - else - /* Supports min 8 BPC if DSC 1.2 is supported*/ - hdmi_dsc->bpc_supported = 8; - - dsc_max_frl_rate = (hf_scds[12] & DRM_EDID_DSC_MAX_FRL_RATE_MASK) >> 4; - drm_get_max_frl_rate(dsc_max_frl_rate, &hdmi_dsc->max_lanes, - &hdmi_dsc->max_frl_rate_per_lane); - hdmi_dsc->total_chunk_kbytes = hf_scds[13] & DRM_EDID_DSC_TOTAL_CHUNK_KBYTES; - - dsc_max_slices = hf_scds[12] & DRM_EDID_DSC_MAX_SLICES; - switch (dsc_max_slices) { - case 1: - hdmi_dsc->max_slices = 1; - hdmi_dsc->clk_per_slice = 340; - break; - case 2: - hdmi_dsc->max_slices = 2; - hdmi_dsc->clk_per_slice = 340; - break; - case 3: - hdmi_dsc->max_slices = 4; - hdmi_dsc->clk_per_slice = 340; - break; - case 4: - hdmi_dsc->max_slices = 8; - hdmi_dsc->clk_per_slice = 340; - break; - case 5: - hdmi_dsc->max_slices = 8; - hdmi_dsc->clk_per_slice = 400; - break; - case 6: - hdmi_dsc->max_slices = 12; - hdmi_dsc->clk_per_slice = 400; - break; - case 7: - hdmi_dsc->max_slices = 16; - hdmi_dsc->clk_per_slice = 400; - break; - case 0: - default: - hdmi_dsc->max_slices = 0; - hdmi_dsc->clk_per_slice = 0; - } - } + + drm_parse_dsc_info(hdmi_dsc, hf_scds); } drm_parse_ycbcr420_deep_color_info(connector, hf_scds); -- cgit From a07e6f56b3eb0bdc8fe42d04296fe66ea8ad4380 Mon Sep 17 00:00:00 2001 From: Ankit Nautiyal Date: Fri, 16 Sep 2022 15:35:50 +0530 Subject: drm/edid: Refactor HFVSDB parsing for DSC1.2 DSC capabilities are given in bytes 11-13 of VSDB (i.e. bytes 8-10 of SCDS). Since minimum length of Data block is 7, all bytes greater than 7 must be read only after checking the length of the data block. This patch adds check for data block length before reading relavant DSC bytes. Signed-off-by: Ankit Nautiyal Reviewed-by: Jani Nikula Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20220916100551.2531750-4-ankit.k.nautiyal@intel.com --- drivers/gpu/drm/drm_edid.c | 93 ++++++++++++++++++++++++---------------------- 1 file changed, 49 insertions(+), 44 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index b949f83716ed..b3ddd2f03f70 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -5755,9 +5755,6 @@ static void drm_parse_ycbcr420_deep_color_info(struct drm_connector *connector, static void drm_parse_dsc_info(struct drm_hdmi_dsc_cap *hdmi_dsc, const u8 *hf_scds) { - u8 dsc_max_slices; - u8 dsc_max_frl_rate; - hdmi_dsc->v_1p2 = hf_scds[11] & DRM_EDID_DSC_1P2; if (!hdmi_dsc->v_1p2) @@ -5776,47 +5773,54 @@ static void drm_parse_dsc_info(struct drm_hdmi_dsc_cap *hdmi_dsc, /* Supports min 8 BPC if DSC 1.2 is supported*/ hdmi_dsc->bpc_supported = 8; - dsc_max_frl_rate = (hf_scds[12] & DRM_EDID_DSC_MAX_FRL_RATE_MASK) >> 4; - drm_get_max_frl_rate(dsc_max_frl_rate, &hdmi_dsc->max_lanes, - &hdmi_dsc->max_frl_rate_per_lane); - hdmi_dsc->total_chunk_kbytes = hf_scds[13] & DRM_EDID_DSC_TOTAL_CHUNK_KBYTES; + if (cea_db_payload_len(hf_scds) >= 12 && hf_scds[12]) { + u8 dsc_max_slices; + u8 dsc_max_frl_rate; - dsc_max_slices = hf_scds[12] & DRM_EDID_DSC_MAX_SLICES; + dsc_max_frl_rate = (hf_scds[12] & DRM_EDID_DSC_MAX_FRL_RATE_MASK) >> 4; + drm_get_max_frl_rate(dsc_max_frl_rate, &hdmi_dsc->max_lanes, + &hdmi_dsc->max_frl_rate_per_lane); - switch (dsc_max_slices) { - case 1: - hdmi_dsc->max_slices = 1; - hdmi_dsc->clk_per_slice = 340; - break; - case 2: - hdmi_dsc->max_slices = 2; - hdmi_dsc->clk_per_slice = 340; - break; - case 3: - hdmi_dsc->max_slices = 4; - hdmi_dsc->clk_per_slice = 340; - break; - case 4: - hdmi_dsc->max_slices = 8; - hdmi_dsc->clk_per_slice = 340; - break; - case 5: - hdmi_dsc->max_slices = 8; - hdmi_dsc->clk_per_slice = 400; - break; - case 6: - hdmi_dsc->max_slices = 12; - hdmi_dsc->clk_per_slice = 400; - break; - case 7: - hdmi_dsc->max_slices = 16; - hdmi_dsc->clk_per_slice = 400; - break; - case 0: - default: - hdmi_dsc->max_slices = 0; - hdmi_dsc->clk_per_slice = 0; + dsc_max_slices = hf_scds[12] & DRM_EDID_DSC_MAX_SLICES; + + switch (dsc_max_slices) { + case 1: + hdmi_dsc->max_slices = 1; + hdmi_dsc->clk_per_slice = 340; + break; + case 2: + hdmi_dsc->max_slices = 2; + hdmi_dsc->clk_per_slice = 340; + break; + case 3: + hdmi_dsc->max_slices = 4; + hdmi_dsc->clk_per_slice = 340; + break; + case 4: + hdmi_dsc->max_slices = 8; + hdmi_dsc->clk_per_slice = 340; + break; + case 5: + hdmi_dsc->max_slices = 8; + hdmi_dsc->clk_per_slice = 400; + break; + case 6: + hdmi_dsc->max_slices = 12; + hdmi_dsc->clk_per_slice = 400; + break; + case 7: + hdmi_dsc->max_slices = 16; + hdmi_dsc->clk_per_slice = 400; + break; + case 0: + default: + hdmi_dsc->max_slices = 0; + hdmi_dsc->clk_per_slice = 0; + } } + + if (cea_db_payload_len(hf_scds) >= 13 && hf_scds[13]) + hdmi_dsc->total_chunk_kbytes = hf_scds[13] & DRM_EDID_DSC_TOTAL_CHUNK_KBYTES; } /* Sink Capability Data Structure */ @@ -5825,6 +5829,7 @@ static void drm_parse_hdmi_forum_scds(struct drm_connector *connector, { struct drm_display_info *display = &connector->display_info; struct drm_hdmi_info *hdmi = &display->hdmi; + struct drm_hdmi_dsc_cap *hdmi_dsc = &hdmi->dsc_cap; display->has_hdmi_infoframe = true; @@ -5865,17 +5870,17 @@ static void drm_parse_hdmi_forum_scds(struct drm_connector *connector, if (hf_scds[7]) { u8 max_frl_rate; - struct drm_hdmi_dsc_cap *hdmi_dsc = &hdmi->dsc_cap; DRM_DEBUG_KMS("hdmi_21 sink detected. parsing edid\n"); max_frl_rate = (hf_scds[7] & DRM_EDID_MAX_FRL_RATE_MASK) >> 4; drm_get_max_frl_rate(max_frl_rate, &hdmi->max_lanes, &hdmi->max_frl_rate_per_lane); - - drm_parse_dsc_info(hdmi_dsc, hf_scds); } drm_parse_ycbcr420_deep_color_info(connector, hf_scds); + + if (cea_db_payload_len(hf_scds) >= 11 && hf_scds[11]) + drm_parse_dsc_info(hdmi_dsc, hf_scds); } static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector, -- cgit From 5e931c88b6912a4614994ea9198929b5241b1a1b Mon Sep 17 00:00:00 2001 From: Ankit Nautiyal Date: Fri, 16 Sep 2022 15:35:51 +0530 Subject: drm/edid: Avoid multiple log lines for HFVSDB parsing Replace multiple log lines with a single log line at the end of parsing HF-VSDB. Also use drm_dbg_kms instead of DRM_DBG_KMS, and add log for DSC1.2 support. v2: Fixed the formatting issues in the logging (Jani). Signed-off-by: Ankit Nautiyal Reviewed-by: Jani Nikula Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20220916100551.2531750-5-ankit.k.nautiyal@intel.com --- drivers/gpu/drm/drm_edid.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index b3ddd2f03f70..7c63d2c92e99 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -5830,6 +5830,9 @@ static void drm_parse_hdmi_forum_scds(struct drm_connector *connector, struct drm_display_info *display = &connector->display_info; struct drm_hdmi_info *hdmi = &display->hdmi; struct drm_hdmi_dsc_cap *hdmi_dsc = &hdmi->dsc_cap; + int max_tmds_clock = 0; + u8 max_frl_rate = 0; + bool dsc_support = false; display->has_hdmi_infoframe = true; @@ -5849,14 +5852,13 @@ static void drm_parse_hdmi_forum_scds(struct drm_connector *connector, */ if (hf_scds[5]) { - /* max clock is 5000 KHz times block value */ - u32 max_tmds_clock = hf_scds[5] * 5000; struct drm_scdc *scdc = &hdmi->scdc; + /* max clock is 5000 KHz times block value */ + max_tmds_clock = hf_scds[5] * 5000; + if (max_tmds_clock > 340000) { display->max_tmds_clock = max_tmds_clock; - DRM_DEBUG_KMS("HF-VSDB: max TMDS clock %d kHz\n", - display->max_tmds_clock); } if (scdc->supported) { @@ -5869,9 +5871,6 @@ static void drm_parse_hdmi_forum_scds(struct drm_connector *connector, } if (hf_scds[7]) { - u8 max_frl_rate; - - DRM_DEBUG_KMS("hdmi_21 sink detected. parsing edid\n"); max_frl_rate = (hf_scds[7] & DRM_EDID_MAX_FRL_RATE_MASK) >> 4; drm_get_max_frl_rate(max_frl_rate, &hdmi->max_lanes, &hdmi->max_frl_rate_per_lane); @@ -5879,8 +5878,14 @@ static void drm_parse_hdmi_forum_scds(struct drm_connector *connector, drm_parse_ycbcr420_deep_color_info(connector, hf_scds); - if (cea_db_payload_len(hf_scds) >= 11 && hf_scds[11]) + if (cea_db_payload_len(hf_scds) >= 11 && hf_scds[11]) { drm_parse_dsc_info(hdmi_dsc, hf_scds); + dsc_support = true; + } + + drm_dbg_kms(connector->dev, + "HF-VSDB: max TMDS clock: %d KHz, HDMI 2.1 support: %s, DSC 1.2 support: %s\n", + max_tmds_clock, str_yes_no(max_frl_rate), str_yes_no(dsc_support)); } static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector, -- cgit From 67d7469a1772e013eee0adcb3963149576d89342 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 27 Sep 2022 19:59:58 +0300 Subject: drm/edid: Clarify why we only accept the "range limits only" descriptor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current comment fails to clarify why we only accept the "range limits only" variant of the range descriptor. Reword it to make some actual sense. Cc: Nicholas Kazlauskas Cc: Harry Wentland Cc: Leo Li Cc: Rodrigo Siqueira Cc: amd-gfx@lists.freedesktop.org Reviewed-by: Manasi Navare Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220927170006.27855-2-ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_edid.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 7c63d2c92e99..09a140e173c4 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -6052,10 +6052,13 @@ void get_monitor_range(const struct detailed_timing *timing, return; /* - * Check for flag range limits only. If flag == 1 then - * no additional timing information provided. - * Default GTF, GTF Secondary curve and CVT are not - * supported + * These limits are used to determine the VRR refresh + * rate range. Only the "range limits only" variant + * of the range descriptor seems to guarantee that + * any and all timings are accepted by the sink, as + * opposed to just timings conforming to the indicated + * formula (GTF/GTF2/CVT). Thus other variants of the + * range descriptor are not accepted here. */ if (range->flags != DRM_EDID_RANGE_LIMITS_ONLY_FLAG) return; -- cgit From afd4429eba283ea284ccf1e910bef649226f892d Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 27 Sep 2022 19:59:59 +0300 Subject: drm/edid: Define more flags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace a bunch of hex constants with proper definitions. Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220927170006.27855-3-ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_edid.c | 18 +++++++++--------- include/drm/drm_edid.h | 14 +++++++++----- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 09a140e173c4..72713fe9378b 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -2984,7 +2984,7 @@ is_rb(const struct detailed_timing *descriptor, void *data) BUILD_BUG_ON(offsetof(typeof(*descriptor), data.other_data.data.range.formula.cvt.flags) != 15); if (descriptor->data.other_data.data.range.flags == DRM_EDID_CVT_SUPPORT_FLAG && - descriptor->data.other_data.data.range.formula.cvt.flags & 0x10) + descriptor->data.other_data.data.range.formula.cvt.flags & DRM_EDID_CVT_FLAGS_REDUCED_BLANKING) *res = true; } @@ -3012,7 +3012,7 @@ find_gtf2(const struct detailed_timing *descriptor, void *data) BUILD_BUG_ON(offsetof(typeof(*descriptor), data.other_data.data.range.flags) != 10); - if (descriptor->data.other_data.data.range.flags == 0x02) + if (descriptor->data.other_data.data.range.flags == DRM_EDID_SECONDARY_GTF_SUPPORT_FLAG) *res = descriptor; } @@ -3415,7 +3415,7 @@ range_pixel_clock(const struct edid *edid, const u8 *t) return 0; /* 1.4 with CVT support gives us real precision, yay */ - if (edid->revision >= 4 && t[10] == 0x04) + if (edid->revision >= 4 && t[10] == DRM_EDID_CVT_SUPPORT_FLAG) return (t[9] * 10000) - ((t[12] >> 2) * 250); /* 1.3 is pathetic, so fuzz up a bit */ @@ -3441,7 +3441,7 @@ static bool mode_in_range(const struct drm_display_mode *mode, return false; /* 1.4 max horizontal check */ - if (edid->revision >= 4 && t[10] == 0x04) + if (edid->revision >= 4 && t[10] == DRM_EDID_CVT_SUPPORT_FLAG) if (t[13] && mode->hdisplay > 8 * (t[13] + (256 * (t[12]&0x3)))) return false; @@ -3581,13 +3581,13 @@ do_inferred_modes(const struct detailed_timing *timing, void *c) return; /* GTF not defined yet */ switch (range->flags) { - case 0x02: /* secondary gtf, XXX could do more */ - case 0x00: /* default gtf */ + case DRM_EDID_SECONDARY_GTF_SUPPORT_FLAG: /* XXX could do more */ + case DRM_EDID_DEFAULT_GTF_SUPPORT_FLAG: closure->modes += drm_gtf_modes_for_range(closure->connector, closure->drm_edid, timing); break; - case 0x04: /* cvt, only in 1.4+ */ + case DRM_EDID_CVT_SUPPORT_FLAG: if (!version_greater(closure->drm_edid, 1, 3)) break; @@ -3595,7 +3595,7 @@ do_inferred_modes(const struct detailed_timing *timing, void *c) closure->drm_edid, timing); break; - case 0x01: /* just the ranges, no formula */ + case DRM_EDID_RANGE_LIMITS_ONLY_FLAG: default: break; } @@ -6402,7 +6402,7 @@ static int _drm_edid_connector_update(struct drm_connector *connector, num_modes += add_cea_modes(connector, drm_edid); num_modes += add_alternate_cea_modes(connector, drm_edid); num_modes += add_displayid_detailed_modes(connector, drm_edid); - if (drm_edid->edid->features & DRM_EDID_FEATURE_DEFAULT_GTF) + if (drm_edid->edid->features & DRM_EDID_FEATURE_CONTINUOUS_FREQ) num_modes += add_inferred_modes(connector, drm_edid); if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75)) diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 2181977ae683..28dd80343afa 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -92,10 +92,13 @@ struct detailed_data_string { u8 str[13]; } __attribute__((packed)); -#define DRM_EDID_DEFAULT_GTF_SUPPORT_FLAG 0x00 -#define DRM_EDID_RANGE_LIMITS_ONLY_FLAG 0x01 -#define DRM_EDID_SECONDARY_GTF_SUPPORT_FLAG 0x02 -#define DRM_EDID_CVT_SUPPORT_FLAG 0x04 +#define DRM_EDID_DEFAULT_GTF_SUPPORT_FLAG 0x00 /* 1.3 */ +#define DRM_EDID_RANGE_LIMITS_ONLY_FLAG 0x01 /* 1.4 */ +#define DRM_EDID_SECONDARY_GTF_SUPPORT_FLAG 0x02 /* 1.3 */ +#define DRM_EDID_CVT_SUPPORT_FLAG 0x04 /* 1.4 */ + +#define DRM_EDID_CVT_FLAGS_STANDARD_BLANKING (1 << 3) +#define DRM_EDID_CVT_FLAGS_REDUCED_BLANKING (1 << 4) struct detailed_data_monitor_range { u8 min_vfreq; @@ -201,7 +204,8 @@ struct detailed_timing { #define DRM_EDID_DIGITAL_TYPE_DP (5 << 0) /* 1.4 */ #define DRM_EDID_DIGITAL_DFP_1_X (1 << 0) /* 1.3 */ -#define DRM_EDID_FEATURE_DEFAULT_GTF (1 << 0) +#define DRM_EDID_FEATURE_DEFAULT_GTF (1 << 0) /* 1.2 */ +#define DRM_EDID_FEATURE_CONTINUOUS_FREQ (1 << 0) /* 1.4 */ #define DRM_EDID_FEATURE_PREFERRED_TIMING (1 << 1) #define DRM_EDID_FEATURE_STANDARD_COLOR (1 << 2) /* If analog */ -- cgit From ca2582c66b930c14b28f158afeb42a8d178c78b7 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 27 Sep 2022 20:00:00 +0300 Subject: drm/edid: Only parse VRR range for continuous frequency displays MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since we only use the parsed vrefresh range to determine if VRR should be supported we should only accept continuous frequency displays here. Cc: Manasi Navare Cc: Nicholas Kazlauskas Cc: Harry Wentland Cc: Leo Li Cc: Rodrigo Siqueira Cc: amd-gfx@lists.freedesktop.org Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220927170006.27855-4-ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_edid.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 72713fe9378b..e0d8ed9bead7 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -6072,7 +6072,10 @@ static void drm_get_monitor_range(struct drm_connector *connector, { struct drm_display_info *info = &connector->display_info; - if (!version_greater(drm_edid, 1, 1)) + if (!version_greater(drm_edid, 1, 3)) + return; + + if (!(drm_edid->edid->features & DRM_EDID_FEATURE_CONTINUOUS_FREQ)) return; drm_for_each_detailed_block(drm_edid, get_monitor_range, -- cgit From 86101bb7e00401e060fa2eaaa141e40ccb379e18 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 27 Sep 2022 20:00:01 +0300 Subject: drm/edid: Extract drm_gtf2_mode() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extract the GTF vs. GTF2 logic into a separate function. We'll have a second user soon. Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220927170006.27855-5-ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_edid.c | 47 +++++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index e0d8ed9bead7..03b3c8841254 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3113,6 +3113,35 @@ static int drm_mode_hsync(const struct drm_display_mode *mode) return DIV_ROUND_CLOSEST(mode->clock, mode->htotal); } +static struct drm_display_mode * +drm_gtf2_mode(struct drm_device *dev, + const struct drm_edid *drm_edid, + int hsize, int vsize, int vrefresh_rate) +{ + struct drm_display_mode *mode; + + /* + * This is potentially wrong if there's ever a monitor with + * more than one ranges section, each claiming a different + * secondary GTF curve. Please don't do that. + */ + mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0); + if (!mode) + return NULL; + + if (drm_mode_hsync(mode) > drm_gtf2_hbreak(drm_edid)) { + drm_mode_destroy(dev, mode); + mode = drm_gtf_mode_complex(dev, hsize, vsize, + vrefresh_rate, 0, 0, + drm_gtf2_m(drm_edid), + drm_gtf2_2c(drm_edid), + drm_gtf2_k(drm_edid), + drm_gtf2_2j(drm_edid)); + } + + return mode; +} + /* * Take the standard timing params (in this case width, aspect, and refresh) * and convert them into a real mode using CVT/GTF/DMT. @@ -3201,23 +3230,7 @@ static struct drm_display_mode *drm_mode_std(struct drm_connector *connector, mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0); break; case LEVEL_GTF2: - /* - * This is potentially wrong if there's ever a monitor with - * more than one ranges section, each claiming a different - * secondary GTF curve. Please don't do that. - */ - mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0); - if (!mode) - return NULL; - if (drm_mode_hsync(mode) > drm_gtf2_hbreak(drm_edid)) { - drm_mode_destroy(dev, mode); - mode = drm_gtf_mode_complex(dev, hsize, vsize, - vrefresh_rate, 0, 0, - drm_gtf2_m(drm_edid), - drm_gtf2_2c(drm_edid), - drm_gtf2_k(drm_edid), - drm_gtf2_2j(drm_edid)); - } + mode = drm_gtf2_mode(dev, drm_edid, hsize, vsize, vrefresh_rate); break; case LEVEL_CVT: mode = drm_cvt_mode(dev, hsize, vsize, vrefresh_rate, 0, 0, -- cgit From 47d4ae2192cb44ccf845c5cca79f9cb6d8394f09 Mon Sep 17 00:00:00 2001 From: José Roberto de Souza Date: Wed, 7 Sep 2022 11:15:43 +0300 Subject: drm/i915/mtl: Extend PSR support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Meteorlake and display 14 platform don't have any PSR differences when comparing to Alderlake-P display, so it was only necessary to extend some checks to properly program hardware. BSpec: 55229, 49196 Cc: Mika Kahola Signed-off-by: José Roberto de Souza Signed-off-by: Jouni Högander Reviewed-by: Stanislav Lisovskiy Signed-off-by: Radhakrishna Sripada Link: https://patchwork.freedesktop.org/patch/msgid/20220907081543.92268-1-mika.kahola@intel.com --- drivers/gpu/drm/i915/display/intel_psr.c | 31 ++++++++++++++++++++----------- drivers/gpu/drm/i915/i915_reg.h | 5 +++++ 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index d4cce627d7a8..16cf17b1e9d9 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -533,7 +533,7 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp) val |= psr_compute_idle_frames(intel_dp) << EDP_PSR2_IDLE_FRAME_SHIFT; - if (!IS_ALDERLAKE_P(dev_priv)) + if (DISPLAY_VER(dev_priv) <= 13 && !IS_ALDERLAKE_P(dev_priv)) val |= EDP_SU_TRACK_ENABLE; if (DISPLAY_VER(dev_priv) >= 10 && DISPLAY_VER(dev_priv) <= 12) @@ -616,7 +616,7 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp) static bool transcoder_has_psr2(struct drm_i915_private *dev_priv, enum transcoder trans) { - if (IS_ALDERLAKE_P(dev_priv)) + if (IS_ALDERLAKE_P(dev_priv) || DISPLAY_VER(dev_priv) >= 14) return trans == TRANSCODER_A || trans == TRANSCODER_B; else if (DISPLAY_VER(dev_priv) >= 12) return trans == TRANSCODER_A; @@ -696,7 +696,7 @@ dc3co_is_pipe_port_compatible(struct intel_dp *intel_dp, struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); enum port port = dig_port->base.port; - if (IS_ALDERLAKE_P(dev_priv)) + if (IS_ALDERLAKE_P(dev_priv) || DISPLAY_VER(dev_priv) >= 14) return pipe <= PIPE_B && port <= PORT_B; else return pipe == PIPE_A && port == PORT_A; @@ -795,11 +795,11 @@ static bool psr2_granularity_check(struct intel_dp *intel_dp, return intel_dp->psr.su_y_granularity == 4; /* - * adl_p has 1 line granularity. For other platforms with SW tracking we - * can adjust the y coordinates to match sink requirement if multiple of - * 4. + * adl_p and display 14+ platforms has 1 line granularity. + * For other platforms with SW tracking we can adjust the y coordinates + * to match sink requirement if multiple of 4. */ - if (IS_ALDERLAKE_P(dev_priv)) + if (IS_ALDERLAKE_P(dev_priv) || DISPLAY_VER(dev_priv) >= 14) y_granularity = intel_dp->psr.su_y_granularity; else if (intel_dp->psr.su_y_granularity <= 2) y_granularity = 4; @@ -883,7 +883,8 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp, * resolution requires DSC to be enabled, priority is given to DSC * over PSR2. */ - if (crtc_state->dsc.compression_enable) { + if (crtc_state->dsc.compression_enable && + (DISPLAY_VER(dev_priv) <= 13 && !IS_ALDERLAKE_P(dev_priv))) { drm_dbg_kms(&dev_priv->drm, "PSR2 cannot be enabled since DSC is enabled\n"); return false; @@ -1474,7 +1475,7 @@ static u32 man_trk_ctl_enable_bit_get(struct drm_i915_private *dev_priv) static u32 man_trk_ctl_single_full_frame_bit_get(struct drm_i915_private *dev_priv) { - return IS_ALDERLAKE_P(dev_priv) ? + return IS_ALDERLAKE_P(dev_priv) || DISPLAY_VER(dev_priv) >= 14 ? ADLP_PSR2_MAN_TRK_CTL_SF_SINGLE_FULL_FRAME : PSR2_MAN_TRK_CTL_SF_SINGLE_FULL_FRAME; } @@ -1627,7 +1628,7 @@ static void psr2_man_trk_ctl_calc(struct intel_crtc_state *crtc_state, if (clip->y1 == -1) goto exit; - if (IS_ALDERLAKE_P(dev_priv)) { + if (IS_ALDERLAKE_P(dev_priv) || DISPLAY_VER(dev_priv) >= 14) { val |= ADLP_PSR2_MAN_TRK_CTL_SU_REGION_START_ADDR(clip->y1); val |= ADLP_PSR2_MAN_TRK_CTL_SU_REGION_END_ADDR(clip->y2 - 1); } else { @@ -1664,7 +1665,15 @@ static void intel_psr2_sel_fetch_pipe_alignment(const struct intel_crtc_state *c struct drm_rect *pipe_clip) { struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); - const u16 y_alignment = crtc_state->su_y_granularity; + const struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config; + u16 y_alignment; + + /* ADLP aligns the SU region to vdsc slice height in case dsc is enabled */ + if (crtc_state->dsc.compression_enable && + (IS_ALDERLAKE_P(dev_priv) || DISPLAY_VER(dev_priv) >= 14)) + y_alignment = vdsc_cfg->slice_height; + else + y_alignment = crtc_state->su_y_granularity; pipe_clip->y1 -= pipe_clip->y1 % y_alignment; if (pipe_clip->y2 % y_alignment) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index e43bb0a911e9..975ce5e0a890 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -8346,6 +8346,11 @@ enum skl_power_gate { #define GEN12_CULLBIT2 _MMIO(0x7030) #define GEN12_STATE_ACK_DEBUG _MMIO(0x20BC) +#define _MTL_CLKGATE_DIS_TRANS_A 0x604E8 +#define _MTL_CLKGATE_DIS_TRANS_B 0x614E8 +#define MTL_CLKGATE_DIS_TRANS(trans) _MMIO_TRANS2(trans, _MTL_CLKGATE_DIS_TRANS_A) +#define MTL_CLKGATE_DIS_TRANS_DMASC_GATING_DIS REG_BIT(7) + #define MTL_LATENCY_LP0_LP1 _MMIO(0x45780) #define MTL_LATENCY_LP2_LP3 _MMIO(0x45784) #define MTL_LATENCY_LP4_LP5 _MMIO(0x45788) -- cgit From 9ed15f91310ceb722aa346ea58831ae0478d8018 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 27 Sep 2022 20:00:02 +0300 Subject: drm/edid: Use GTF2 for inferred modes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For some reason we only use the secondary GTF curve for the standard timings. Use it for inferred modes as well. Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220927170006.27855-6-ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_edid.c | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 03b3c8841254..28655eda515d 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3546,6 +3546,35 @@ static int drm_gtf_modes_for_range(struct drm_connector *connector, return modes; } +static int drm_gtf2_modes_for_range(struct drm_connector *connector, + const struct drm_edid *drm_edid, + const struct detailed_timing *timing) +{ + int i, modes = 0; + struct drm_display_mode *newmode; + struct drm_device *dev = connector->dev; + + for (i = 0; i < ARRAY_SIZE(extra_modes); i++) { + const struct minimode *m = &extra_modes[i]; + + newmode = drm_gtf2_mode(dev, drm_edid, m->w, m->h, m->r); + if (!newmode) + return modes; + + drm_mode_fixup_1366x768(newmode); + if (!mode_in_range(newmode, drm_edid, timing) || + !valid_inferred_mode(connector, newmode)) { + drm_mode_destroy(dev, newmode); + continue; + } + + drm_mode_probed_add(connector, newmode); + modes++; + } + + return modes; +} + static int drm_cvt_modes_for_range(struct drm_connector *connector, const struct drm_edid *drm_edid, const struct detailed_timing *timing) @@ -3594,7 +3623,11 @@ do_inferred_modes(const struct detailed_timing *timing, void *c) return; /* GTF not defined yet */ switch (range->flags) { - case DRM_EDID_SECONDARY_GTF_SUPPORT_FLAG: /* XXX could do more */ + case DRM_EDID_SECONDARY_GTF_SUPPORT_FLAG: + closure->modes += drm_gtf2_modes_for_range(closure->connector, + closure->drm_edid, + timing); + break; case DRM_EDID_DEFAULT_GTF_SUPPORT_FLAG: closure->modes += drm_gtf_modes_for_range(closure->connector, closure->drm_edid, -- cgit From bf72b5ef6e2b4e7d1a8a7086757a651831f907cc Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 27 Sep 2022 20:00:03 +0300 Subject: drm/edid: Use the correct formula for standard timings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prefer the timing formula indicated by the range descriptor for generating the non-DMT standard timings. Previously we just used CVT for all EDID 1.4 continuous frequency displays without even checking if the range descriptor indicates otherwise. Now we check the range descriptor first, and fall back to CVT if nothing else was indicated. EDID 1.4 more or less deprecates GTF/GTF2 but there are still a lot of 1.4 EDIDs out there that don't advertise CVT support, so seems safer to use the formula the EDID actually reports as supported. For EDID 1.3 we use GTF2 if indicated (as before), and for EDID 1.2+ we now just use GTF without even checking the feature flag. There seem to be quite a few EDIDs out there that don't set the GTF feature flag but still include a GTF range descriptor and non-DMT standard timings. This to me seems to be roughly what appendix B of EDID 1.4 suggests should be done. Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220927170006.27855-7-ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_edid.c | 49 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 28655eda515d..fdf23dc95131 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3077,20 +3077,53 @@ drm_gtf2_2j(const struct drm_edid *drm_edid) return descriptor ? descriptor->data.other_data.data.range.formula.gtf2.j : 0; } +static void +get_timing_level(const struct detailed_timing *descriptor, void *data) +{ + int *res = data; + + if (!is_display_descriptor(descriptor, EDID_DETAIL_MONITOR_RANGE)) + return; + + BUILD_BUG_ON(offsetof(typeof(*descriptor), data.other_data.data.range.flags) != 10); + + switch (descriptor->data.other_data.data.range.flags) { + case DRM_EDID_DEFAULT_GTF_SUPPORT_FLAG: + *res = LEVEL_GTF; + break; + case DRM_EDID_SECONDARY_GTF_SUPPORT_FLAG: + *res = LEVEL_GTF2; + break; + case DRM_EDID_CVT_SUPPORT_FLAG: + *res = LEVEL_CVT; + break; + default: + break; + } +} + /* Get standard timing level (CVT/GTF/DMT). */ static int standard_timing_level(const struct drm_edid *drm_edid) { const struct edid *edid = drm_edid->edid; - if (edid->revision >= 2) { - if (edid->revision >= 4 && (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF)) - return LEVEL_CVT; - if (drm_gtf2_hbreak(drm_edid)) - return LEVEL_GTF2; - if (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF) - return LEVEL_GTF; + if (edid->revision >= 4) { + /* + * If the range descriptor doesn't + * indicate otherwise default to CVT + */ + int ret = LEVEL_CVT; + + drm_for_each_detailed_block(drm_edid, get_timing_level, &ret); + + return ret; + } else if (edid->revision >= 3 && drm_gtf2_hbreak(drm_edid)) { + return LEVEL_GTF2; + } else if (edid->revision >= 2) { + return LEVEL_GTF; + } else { + return LEVEL_DMT; } - return LEVEL_DMT; } /* -- cgit From f72f9529b0ba69d0d00563f54868c5efbf00e88d Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 27 Sep 2022 20:00:04 +0300 Subject: drm/edid: Unconfuse preferred timing stuff a bit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For EDID 1.4 the first detailed timing is always preferred, for older EDIDs there was a feature flag to indicate the same. While correct, the code setting that up is rather confusing. Restate it in a slightly more straightforward manner. Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220927170006.27855-8-ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_edid.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index fdf23dc95131..075ed4e7eae9 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3952,13 +3952,14 @@ static int add_detailed_modes(struct drm_connector *connector, struct detailed_mode_closure closure = { .connector = connector, .drm_edid = drm_edid, - .preferred = true, .quirks = quirks, }; - if (closure.preferred && !version_greater(drm_edid, 1, 3)) + if (version_greater(drm_edid, 1, 3)) + closure.preferred = true; /* first detailed timing is always preferred */ + else closure.preferred = - (drm_edid->edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING); + drm_edid->edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING; drm_for_each_detailed_block(drm_edid, do_detailed_mode, &closure); -- cgit From dd3abfe4e6b679e4258f922540da2277f962eb1f Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 27 Sep 2022 20:00:05 +0300 Subject: drm/edid: Make version checks less convoluted MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Get rid of the confusing version_greater() stuff and simply compare edid->revision directly everwhere. Half the places already did it this way, and since we actually reject any EDID with edid->version!=1 it's a perfectly sane thing to do. Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220927170006.27855-9-ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_edid.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 075ed4e7eae9..73c614efc132 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1572,15 +1572,6 @@ struct drm_edid { const struct edid *edid; }; -static bool version_greater(const struct drm_edid *drm_edid, - u8 version, u8 revision) -{ - const struct edid *edid = drm_edid->edid; - - return edid->version > version || - (edid->version == version && edid->revision > revision); -} - static int edid_hfeeodb_extension_block_count(const struct edid *edid); static int edid_hfeeodb_block_count(const struct edid *edid) @@ -3652,7 +3643,7 @@ do_inferred_modes(const struct detailed_timing *timing, void *c) closure->drm_edid, timing); - if (!version_greater(closure->drm_edid, 1, 1)) + if (closure->drm_edid->edid->revision < 2) return; /* GTF not defined yet */ switch (range->flags) { @@ -3667,7 +3658,7 @@ do_inferred_modes(const struct detailed_timing *timing, void *c) timing); break; case DRM_EDID_CVT_SUPPORT_FLAG: - if (!version_greater(closure->drm_edid, 1, 3)) + if (closure->drm_edid->edid->revision < 4) break; closure->modes += drm_cvt_modes_for_range(closure->connector, @@ -3688,7 +3679,7 @@ static int add_inferred_modes(struct drm_connector *connector, .drm_edid = drm_edid, }; - if (version_greater(drm_edid, 1, 0)) + if (drm_edid->edid->revision >= 1) drm_for_each_detailed_block(drm_edid, do_inferred_modes, &closure); return closure.modes; @@ -3765,7 +3756,7 @@ static int add_established_modes(struct drm_connector *connector, } } - if (version_greater(drm_edid, 1, 0)) + if (edid->revision >= 1) drm_for_each_detailed_block(drm_edid, do_established_modes, &closure); @@ -3820,7 +3811,7 @@ static int add_standard_modes(struct drm_connector *connector, } } - if (version_greater(drm_edid, 1, 0)) + if (drm_edid->edid->revision >= 1) drm_for_each_detailed_block(drm_edid, do_standard_modes, &closure); @@ -3900,7 +3891,7 @@ add_cvt_modes(struct drm_connector *connector, const struct drm_edid *drm_edid) .drm_edid = drm_edid, }; - if (version_greater(drm_edid, 1, 2)) + if (drm_edid->edid->revision >= 3) drm_for_each_detailed_block(drm_edid, do_cvt_mode, &closure); /* XXX should also look for CVT codes in VTB blocks */ @@ -3955,7 +3946,7 @@ static int add_detailed_modes(struct drm_connector *connector, .quirks = quirks, }; - if (version_greater(drm_edid, 1, 3)) + if (drm_edid->edid->revision >= 4) closure.preferred = true; /* first detailed timing is always preferred */ else closure.preferred = @@ -6152,7 +6143,7 @@ static void drm_get_monitor_range(struct drm_connector *connector, { struct drm_display_info *info = &connector->display_info; - if (!version_greater(drm_edid, 1, 3)) + if (drm_edid->edid->revision < 4) return; if (!(drm_edid->edid->features & DRM_EDID_FEATURE_CONTINUOUS_FREQ)) -- cgit From 0add082cebac8555ee3972ba768ae5c01db7a498 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Mon, 3 Oct 2022 13:16:30 +0100 Subject: drm/i915/guc: Fix revocation of non-persistent contexts Patch which added graceful exit for non-persistent contexts missed the fact it is not enough to set the exiting flag on a context and let the backend handle it from there. GuC backend cannot handle it because it runs independently in the firmware and driver might not see the requests ever again. Patch also missed the fact some usages of intel_context_is_banned in the GuC backend needed replacing with newly introduced intel_context_is_schedulable. Fix the first issue by calling into backend revoke when we know this is the last chance to do it. Fix the second issue by replacing intel_context_is_banned with intel_context_is_schedulable, which should always be safe since latter is a superset of the former. v2: * Just call ce->ops->revoke unconditionally. (Andrzej) Signed-off-by: Tvrtko Ursulin Fixes: 45c64ecf97ee ("drm/i915: Improve user experience and driver robustness under SIGINT or similar") Cc: Andrzej Hajda Cc: John Harrison Cc: Daniele Ceraolo Spurio Cc: # v6.0+ Reviewed-by: Andrzej Hajda Acked-by: Daniele Ceraolo Spurio Link: https://patchwork.freedesktop.org/patch/msgid/20221003121630.694249-1-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/gem/i915_gem_context.c | 8 +------ drivers/gpu/drm/i915/gt/intel_context.c | 5 ++--- drivers/gpu/drm/i915/gt/intel_context.h | 3 +-- drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c | 26 +++++++++++------------ 4 files changed, 17 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c index 0bcde53c50c6..1e29b1e6d186 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c @@ -1387,14 +1387,8 @@ kill_engines(struct i915_gem_engines *engines, bool exit, bool persistent) */ for_each_gem_engine(ce, engines, it) { struct intel_engine_cs *engine; - bool skip = false; - if (exit) - skip = intel_context_set_exiting(ce); - else if (!persistent) - skip = intel_context_exit_nonpersistent(ce, NULL); - - if (skip) + if ((exit || !persistent) && intel_context_revoke(ce)) continue; /* Already marked. */ /* diff --git a/drivers/gpu/drm/i915/gt/intel_context.c b/drivers/gpu/drm/i915/gt/intel_context.c index 654a092ed3d6..e94365b08f1e 100644 --- a/drivers/gpu/drm/i915/gt/intel_context.c +++ b/drivers/gpu/drm/i915/gt/intel_context.c @@ -614,13 +614,12 @@ bool intel_context_ban(struct intel_context *ce, struct i915_request *rq) return ret; } -bool intel_context_exit_nonpersistent(struct intel_context *ce, - struct i915_request *rq) +bool intel_context_revoke(struct intel_context *ce) { bool ret = intel_context_set_exiting(ce); if (ce->ops->revoke) - ce->ops->revoke(ce, rq, ce->engine->props.preempt_timeout_ms); + ce->ops->revoke(ce, NULL, ce->engine->props.preempt_timeout_ms); return ret; } diff --git a/drivers/gpu/drm/i915/gt/intel_context.h b/drivers/gpu/drm/i915/gt/intel_context.h index 8e2d70630c49..be09fb2e883a 100644 --- a/drivers/gpu/drm/i915/gt/intel_context.h +++ b/drivers/gpu/drm/i915/gt/intel_context.h @@ -329,8 +329,7 @@ static inline bool intel_context_set_exiting(struct intel_context *ce) return test_and_set_bit(CONTEXT_EXITING, &ce->flags); } -bool intel_context_exit_nonpersistent(struct intel_context *ce, - struct i915_request *rq); +bool intel_context_revoke(struct intel_context *ce); static inline bool intel_context_force_single_submission(const struct intel_context *ce) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index d81f68fef9a8..693b07a97789 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -685,7 +685,7 @@ static int __guc_add_request(struct intel_guc *guc, struct i915_request *rq) * Corner case where requests were sitting in the priority list or a * request resubmitted after the context was banned. */ - if (unlikely(intel_context_is_banned(ce))) { + if (unlikely(!intel_context_is_schedulable(ce))) { i915_request_put(i915_request_mark_eio(rq)); intel_engine_signal_breadcrumbs(ce->engine); return 0; @@ -871,15 +871,15 @@ static int guc_wq_item_append(struct intel_guc *guc, struct i915_request *rq) { struct intel_context *ce = request_to_scheduling_context(rq); - int ret = 0; + int ret; - if (likely(!intel_context_is_banned(ce))) { - ret = __guc_wq_item_append(rq); + if (unlikely(!intel_context_is_schedulable(ce))) + return 0; - if (unlikely(ret == -EBUSY)) { - guc->stalled_request = rq; - guc->submission_stall_reason = STALL_MOVE_LRC_TAIL; - } + ret = __guc_wq_item_append(rq); + if (unlikely(ret == -EBUSY)) { + guc->stalled_request = rq; + guc->submission_stall_reason = STALL_MOVE_LRC_TAIL; } return ret; @@ -898,7 +898,7 @@ static bool multi_lrc_submit(struct i915_request *rq) * submitting all the requests generated in parallel. */ return test_bit(I915_FENCE_FLAG_SUBMIT_PARALLEL, &rq->fence.flags) || - intel_context_is_banned(ce); + !intel_context_is_schedulable(ce); } static int guc_dequeue_one_context(struct intel_guc *guc) @@ -967,7 +967,7 @@ register_context: struct intel_context *ce = request_to_scheduling_context(last); if (unlikely(!ctx_id_mapped(guc, ce->guc_id.id) && - !intel_context_is_banned(ce))) { + intel_context_is_schedulable(ce))) { ret = try_context_registration(ce, false); if (unlikely(ret == -EPIPE)) { goto deadlk; @@ -1577,7 +1577,7 @@ static void guc_reset_state(struct intel_context *ce, u32 head, bool scrub) { struct intel_engine_cs *engine = __context_to_physical_engine(ce); - if (intel_context_is_banned(ce)) + if (!intel_context_is_schedulable(ce)) return; GEM_BUG_ON(!intel_context_is_pinned(ce)); @@ -4518,12 +4518,12 @@ static void guc_handle_context_reset(struct intel_guc *guc, { trace_intel_context_reset(ce); - if (likely(!intel_context_is_banned(ce))) { + if (likely(intel_context_is_schedulable(ce))) { capture_error_state(guc, ce); guc_context_replay(ce); } else { drm_info(&guc_to_gt(guc)->i915->drm, - "Ignoring context reset notification of banned context 0x%04X on %s", + "Ignoring context reset notification of exiting context 0x%04X on %s", ce->guc_id.id, ce->engine->name); } } -- cgit From 3bce981f58421a0a111f04f594ad654afff9f95c Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Tue, 4 Oct 2022 14:19:12 +0100 Subject: drm/i915: remove the TODO in pin_and_fence_fb_obj MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The copy is async (if there even is one), but when later updating the GGTT we always sync against the binding, which will in turn sync against any moves. Signed-off-by: Matthew Auld Cc: Jianshui Yu Cc: Ville Syrjälä Cc: Nirmoy Das Reviewed-by: Nirmoy Das Link: https://patchwork.freedesktop.org/patch/msgid/20221004131916.233474-1-matthew.auld@intel.com --- drivers/gpu/drm/i915/display/intel_fb_pin.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_fb_pin.c b/drivers/gpu/drm/i915/display/intel_fb_pin.c index c86e5d4ee016..0cd9e8cb078b 100644 --- a/drivers/gpu/drm/i915/display/intel_fb_pin.c +++ b/drivers/gpu/drm/i915/display/intel_fb_pin.c @@ -141,7 +141,6 @@ retry: ret = i915_gem_object_attach_phys(obj, alignment); else if (!ret && HAS_LMEM(dev_priv)) ret = i915_gem_object_migrate(obj, &ww, INTEL_REGION_LMEM_0); - /* TODO: Do we need to sync when migration becomes async? */ if (!ret) ret = i915_gem_object_pin_pages(obj); if (ret) -- cgit From 5769f64ff09aab23a9045fa13b464fb5070d3fb2 Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Tue, 4 Oct 2022 14:19:13 +0100 Subject: drm/i915/display: handle migration for dpt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On platforms like DG2, it looks like the dpt path here is missing the migrate-to-lmem step on discrete platforms. v2: - Move the vma_pin() under the for_i915_gem_ww(), otherwise the object can be moved after dropping the lock and then doing the pin. Fixes: 33e7a975103c ("drm/i915/xelpd: First stab at DPT support") Signed-off-by: Matthew Auld Cc: Jianshui Yu Cc: Ville Syrjälä Cc: Nirmoy Das Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221004131916.233474-2-matthew.auld@intel.com --- drivers/gpu/drm/i915/display/intel_fb_pin.c | 51 +++++++++++++++++++---------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fb_pin.c b/drivers/gpu/drm/i915/display/intel_fb_pin.c index 0cd9e8cb078b..e65e70efece7 100644 --- a/drivers/gpu/drm/i915/display/intel_fb_pin.c +++ b/drivers/gpu/drm/i915/display/intel_fb_pin.c @@ -26,10 +26,17 @@ intel_pin_fb_obj_dpt(struct drm_framebuffer *fb, struct drm_device *dev = fb->dev; struct drm_i915_private *dev_priv = to_i915(dev); struct drm_i915_gem_object *obj = intel_fb_obj(fb); + struct i915_gem_ww_ctx ww; struct i915_vma *vma; u32 alignment; int ret; + /* + * We are not syncing against the binding (and potential migrations) + * below, so this vm must never be async. + */ + GEM_WARN_ON(vm->bind_async_flags); + if (WARN_ON(!i915_gem_object_is_framebuffer(obj))) return ERR_PTR(-EINVAL); @@ -37,29 +44,37 @@ intel_pin_fb_obj_dpt(struct drm_framebuffer *fb, atomic_inc(&dev_priv->gpu_error.pending_fb_pin); - ret = i915_gem_object_lock_interruptible(obj, NULL); - if (!ret) { + for_i915_gem_ww(&ww, ret, true) { + ret = i915_gem_object_lock(obj, &ww); + if (ret) + continue; + + if (HAS_LMEM(dev_priv)) { + ret = i915_gem_object_migrate(obj, &ww, INTEL_REGION_LMEM_0); + if (ret) + continue; + } + ret = i915_gem_object_set_cache_level(obj, I915_CACHE_NONE); - i915_gem_object_unlock(obj); - } - if (ret) { - vma = ERR_PTR(ret); - goto err; - } + if (ret) + continue; - vma = i915_vma_instance(obj, vm, view); - if (IS_ERR(vma)) - goto err; + vma = i915_vma_instance(obj, vm, view); + if (IS_ERR(vma)) { + ret = PTR_ERR(vma); + continue; + } - if (i915_vma_misplaced(vma, 0, alignment, 0)) { - ret = i915_vma_unbind_unlocked(vma); - if (ret) { - vma = ERR_PTR(ret); - goto err; + if (i915_vma_misplaced(vma, 0, alignment, 0)) { + ret = i915_vma_unbind(vma); + if (ret) + continue; } - } - ret = i915_vma_pin(vma, 0, alignment, PIN_GLOBAL); + ret = i915_vma_pin_ww(vma, &ww, 0, alignment, PIN_GLOBAL); + if (ret) + continue; + } if (ret) { vma = ERR_PTR(ret); goto err; -- cgit From 999f4562077208b683f0519e5f1aa1e5c2fd2191 Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Tue, 4 Oct 2022 14:19:14 +0100 Subject: drm/i915: allow control over the flags when migrating MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the next patch we want to move the object (if the current resource is not compatible), to the mappable part of lmem for some display buffers. Currently that requires being able to unset the I915_BO_ALLOC_GPU_ONLY hint. Signed-off-by: Matthew Auld Cc: Jianshui Yu Cc: Ville Syrjälä Cc: Nirmoy Das Reviewed-by: Nirmoy Das Link: https://patchwork.freedesktop.org/patch/msgid/20221004131916.233474-3-matthew.auld@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_object.c | 37 +++++++++++++++++++++++- drivers/gpu/drm/i915/gem/i915_gem_object.h | 4 +++ drivers/gpu/drm/i915/gem/i915_gem_object_types.h | 3 +- drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 5 ++-- 4 files changed, 45 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c index 7ff9c7877bec..369006c5317f 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c @@ -652,6 +652,41 @@ bool i915_gem_object_can_migrate(struct drm_i915_gem_object *obj, int i915_gem_object_migrate(struct drm_i915_gem_object *obj, struct i915_gem_ww_ctx *ww, enum intel_region_id id) +{ + return __i915_gem_object_migrate(obj, ww, id, obj->flags); +} + +/** + * __i915_gem_object_migrate - Migrate an object to the desired region id, with + * control of the extra flags + * @obj: The object to migrate. + * @ww: An optional struct i915_gem_ww_ctx. If NULL, the backend may + * not be successful in evicting other objects to make room for this object. + * @id: The region id to migrate to. + * @flags: The object flags. Normally just obj->flags. + * + * Attempt to migrate the object to the desired memory region. The + * object backend must support migration and the object may not be + * pinned, (explicitly pinned pages or pinned vmas). The object must + * be locked. + * On successful completion, the object will have pages pointing to + * memory in the new region, but an async migration task may not have + * completed yet, and to accomplish that, i915_gem_object_wait_migration() + * must be called. + * + * Note: the @ww parameter is not used yet, but included to make sure + * callers put some effort into obtaining a valid ww ctx if one is + * available. + * + * Return: 0 on success. Negative error code on failure. In particular may + * return -ENXIO on lack of region space, -EDEADLK for deadlock avoidance + * if @ww is set, -EINTR or -ERESTARTSYS if signal pending, and + * -EBUSY if the object is pinned. + */ +int __i915_gem_object_migrate(struct drm_i915_gem_object *obj, + struct i915_gem_ww_ctx *ww, + enum intel_region_id id, + unsigned int flags) { struct drm_i915_private *i915 = to_i915(obj->base.dev); struct intel_memory_region *mr; @@ -672,7 +707,7 @@ int i915_gem_object_migrate(struct drm_i915_gem_object *obj, return 0; } - return obj->ops->migrate(obj, mr); + return obj->ops->migrate(obj, mr, flags); } /** diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.h b/drivers/gpu/drm/i915/gem/i915_gem_object.h index a3b7551a57fc..6b9ecff42bb5 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.h @@ -612,6 +612,10 @@ bool i915_gem_object_migratable(struct drm_i915_gem_object *obj); int i915_gem_object_migrate(struct drm_i915_gem_object *obj, struct i915_gem_ww_ctx *ww, enum intel_region_id id); +int __i915_gem_object_migrate(struct drm_i915_gem_object *obj, + struct i915_gem_ww_ctx *ww, + enum intel_region_id id, + unsigned int flags); bool i915_gem_object_can_migrate(struct drm_i915_gem_object *obj, enum intel_region_id id); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h index 40305e2bcd49..d0d6772e6f36 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h @@ -107,7 +107,8 @@ struct drm_i915_gem_object_ops { * pinning or for as long as the object lock is held. */ int (*migrate)(struct drm_i915_gem_object *obj, - struct intel_memory_region *mr); + struct intel_memory_region *mr, + unsigned int flags); void (*release)(struct drm_i915_gem_object *obj); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c index d11cd9c57247..d63f30efd631 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c @@ -893,9 +893,10 @@ static int __i915_ttm_migrate(struct drm_i915_gem_object *obj, } static int i915_ttm_migrate(struct drm_i915_gem_object *obj, - struct intel_memory_region *mr) + struct intel_memory_region *mr, + unsigned int flags) { - return __i915_ttm_migrate(obj, mr, obj->flags); + return __i915_ttm_migrate(obj, mr, flags); } static void i915_ttm_put_pages(struct drm_i915_gem_object *obj, -- cgit From e3afc690188be8e4385d13d1b0e7f0ba01caea40 Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Tue, 4 Oct 2022 14:19:15 +0100 Subject: drm/i915/display: consider DG2_RC_CCS_CC when migrating buffers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For these types of display buffers, we need to able to CPU access some part of the backing memory in prepare_plane_clear_colors(). As a result we need to ensure we always place in the mappable part of lmem, which becomes necessary on small-bar systems. v2(Nirmoy & Ville): - Add some commentary for why we need to CPU access the buffer. - Split out the other changes, so we just consider the display change here. v3: - Handle this in the dpt path. v4(Ville): - Drop the intel_fb_rc_ccs_cc_plane() sanity check in pin_and_fence_fb_obj(), since we can also trigger this on DG1 it seems. Fixes: eb1c535f0d69 ("drm/i915: turn on small BAR support") Reported-by: Jianshui Yu Signed-off-by: Matthew Auld Cc: Ville Syrjälä Cc: Nirmoy Das Reviewed-by: Ville Syrjälä Acked-by: Nirmoy Das Link: https://patchwork.freedesktop.org/patch/msgid/20221004131916.233474-4-matthew.auld@intel.com --- drivers/gpu/drm/i915/display/intel_fb_pin.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_fb_pin.c b/drivers/gpu/drm/i915/display/intel_fb_pin.c index e65e70efece7..6900acbb1381 100644 --- a/drivers/gpu/drm/i915/display/intel_fb_pin.c +++ b/drivers/gpu/drm/i915/display/intel_fb_pin.c @@ -50,7 +50,18 @@ intel_pin_fb_obj_dpt(struct drm_framebuffer *fb, continue; if (HAS_LMEM(dev_priv)) { - ret = i915_gem_object_migrate(obj, &ww, INTEL_REGION_LMEM_0); + unsigned int flags = obj->flags; + + /* + * For this type of buffer we need to able to read from the CPU + * the clear color value found in the buffer, hence we need to + * ensure it is always in the mappable part of lmem, if this is + * a small-bar device. + */ + if (intel_fb_rc_ccs_cc_plane(fb) >= 0) + flags &= ~I915_BO_ALLOC_GPU_ONLY; + ret = __i915_gem_object_migrate(obj, &ww, INTEL_REGION_LMEM_0, + flags); if (ret) continue; } -- cgit From 7024f80efcce8122fe8db3e0b4c096eb199333eb Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Tue, 4 Oct 2022 14:19:16 +0100 Subject: drm/i915: check memory is mappable in read_from_page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On small-bar systems we could be given something non-mappable here, which leads to nasty oops. Make this nicer by checking if the resource is mappable or not, and return an error otherwise. v2: drop GEM_BUG_ON(flags & I915_BO_ALLOC_GPU_ONLY) Signed-off-by: Matthew Auld Cc: Jianshui Yu Cc: Ville Syrjälä Cc: Nirmoy Das Reviewed-by: Nirmoy Das Link: https://patchwork.freedesktop.org/patch/msgid/20221004131916.233474-5-matthew.auld@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_object.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c index 369006c5317f..62495d5d0038 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c @@ -444,6 +444,16 @@ i915_gem_object_read_from_page_iomap(struct drm_i915_gem_object *obj, u64 offset io_mapping_unmap(src_map); } +static bool object_has_mappable_iomem(struct drm_i915_gem_object *obj) +{ + GEM_BUG_ON(!i915_gem_object_has_iomem(obj)); + + if (IS_DGFX(to_i915(obj->base.dev))) + return i915_ttm_resource_mappable(i915_gem_to_ttm(obj)->resource); + + return true; +} + /** * i915_gem_object_read_from_page - read data from the page of a GEM object * @obj: GEM object to read from @@ -466,7 +476,7 @@ int i915_gem_object_read_from_page(struct drm_i915_gem_object *obj, u64 offset, if (i915_gem_object_has_struct_page(obj)) i915_gem_object_read_from_page_kmap(obj, offset, dst, size); - else if (i915_gem_object_has_iomem(obj)) + else if (i915_gem_object_has_iomem(obj) && object_has_mappable_iomem(obj)) i915_gem_object_read_from_page_iomap(obj, offset, dst, size); else return -ENODEV; -- cgit From 7c022f516fbe2d4b1b4abdd1c4b7687ec81a6ed9 Mon Sep 17 00:00:00 2001 From: Christian König Date: Tue, 27 Sep 2022 18:43:03 +0200 Subject: drm/scheduler: fix fence ref counting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We leaked dependency fences when processes were beeing killed. Additional to that grab a reference to the last scheduled fence. Signed-off-by: Christian König Reviewed-by: Andrey Grodzovsky Link: https://patchwork.freedesktop.org/patch/msgid/20220929180151.139751-1-christian.koenig@amd.com --- drivers/gpu/drm/scheduler/sched_entity.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/scheduler/sched_entity.c b/drivers/gpu/drm/scheduler/sched_entity.c index 7060e4ed5a31..dac552f0a75b 100644 --- a/drivers/gpu/drm/scheduler/sched_entity.c +++ b/drivers/gpu/drm/scheduler/sched_entity.c @@ -208,6 +208,7 @@ static void drm_sched_entity_kill_jobs_cb(struct dma_fence *f, struct drm_sched_job *job = container_of(cb, struct drm_sched_job, finish_cb); + dma_fence_put(f); INIT_WORK(&job->work, drm_sched_entity_kill_jobs_work); schedule_work(&job->work); } @@ -235,8 +236,10 @@ static void drm_sched_entity_kill_jobs(struct drm_sched_entity *entity) struct drm_sched_fence *s_fence = job->s_fence; /* Wait for all dependencies to avoid data corruptions */ - while ((f = drm_sched_job_dependency(job, entity))) + while ((f = drm_sched_job_dependency(job, entity))) { dma_fence_wait(f, false); + dma_fence_put(f); + } drm_sched_fence_scheduled(s_fence); dma_fence_set_error(&s_fence->finished, -ESRCH); @@ -251,6 +254,7 @@ static void drm_sched_entity_kill_jobs(struct drm_sched_entity *entity) continue; } + dma_fence_get(entity->last_scheduled); r = dma_fence_add_callback(entity->last_scheduled, &job->finish_cb, drm_sched_entity_kill_jobs_cb); -- cgit From 65b698bf400f00ab452d5f27ecad84ab8c826014 Mon Sep 17 00:00:00 2001 From: Christian König Date: Thu, 29 Sep 2022 19:53:53 +0200 Subject: drm/sched: add missing NULL check in drm_sched_get_cleanup_job v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise we would crash if the job is not resubmitted. v2: fix second usage of s_fence->parent as well. Signed-off-by: Christian König Reviewed-by: Steven Price Link: https://patchwork.freedesktop.org/patch/msgid/20221004132831.134986-1-christian.koenig@amd.com --- drivers/gpu/drm/scheduler/sched_main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index ce86b03e8386..4cc59bae38dd 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -919,7 +919,8 @@ drm_sched_get_cleanup_job(struct drm_gpu_scheduler *sched) job = list_first_entry_or_null(&sched->pending_list, struct drm_sched_job, list); - if (job && dma_fence_is_signaled(job->s_fence->parent)) { + if (job && (!job->s_fence->parent || + dma_fence_is_signaled(job->s_fence->parent))) { /* remove job from pending_list */ list_del_init(&job->list); @@ -929,7 +930,7 @@ drm_sched_get_cleanup_job(struct drm_gpu_scheduler *sched) next = list_first_entry_or_null(&sched->pending_list, typeof(*next), list); - if (next) { + if (next && job->s_fence->parent) { next->s_fence->scheduled.timestamp = job->s_fence->parent->timestamp; /* start TO timer for next job */ -- cgit From 562d2dd8702806c636ba81c43b23394b29c60acc Mon Sep 17 00:00:00 2001 From: Jason Yen Date: Fri, 30 Sep 2022 12:25:06 +0800 Subject: drm/bridge: ps8640: Add software to support aux defer This chip can not handle aux defer if the host directly program its aux registers to access edid/dpcd. So we need let software to handle the aux defer situation. Signed-off-by: Jason Yen Reviewed-by: Douglas Anderson Signed-off-by: Douglas Anderson Link: https://patchwork.freedesktop.org/patch/msgid/20220930042506.2529522-1-jason.yen@paradetech.corp-partner.google.com --- drivers/gpu/drm/bridge/parade-ps8640.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c index d7483c13c569..5be6562c2a19 100644 --- a/drivers/gpu/drm/bridge/parade-ps8640.c +++ b/drivers/gpu/drm/bridge/parade-ps8640.c @@ -286,7 +286,6 @@ static ssize_t ps8640_aux_transfer_msg(struct drm_dp_aux *aux, } switch (data & SWAUX_STATUS_MASK) { - /* Ignore the DEFER cases as they are already handled in hardware */ case SWAUX_STATUS_NACK: case SWAUX_STATUS_I2C_NACK: /* @@ -303,6 +302,14 @@ static ssize_t ps8640_aux_transfer_msg(struct drm_dp_aux *aux, case SWAUX_STATUS_ACKM: len = data & SWAUX_M_MASK; break; + case SWAUX_STATUS_DEFER: + case SWAUX_STATUS_I2C_DEFER: + if (is_native_aux) + msg->reply |= DP_AUX_NATIVE_REPLY_DEFER; + else + msg->reply |= DP_AUX_I2C_REPLY_DEFER; + len = data & SWAUX_M_MASK; + break; case SWAUX_STATUS_INVALID: return -EOPNOTSUPP; case SWAUX_STATUS_TIMEOUT: -- cgit From ce7fcf7003865a63983545fd8f84c04deb1b5dfd Mon Sep 17 00:00:00 2001 From: Jocelyn Falempe Date: Fri, 30 Sep 2022 11:47:54 +0200 Subject: drm/ast: Add Atomic gamma lut support for aspeed The current ast driver only supports legacy gamma interface. This also fixes a Gnome3/Wayland error which incorrectly adds gamma to atomic commit: "Page flip discarded: CRTC property (GAMMA_LUT) not found" I only tested remotely, so I wasn't able to check that it had an effect on the VGA output. But when activating "Night Light" in Gnome, ast_crtc_load_lut() is called. v2: use the same functions as mgag200. handle 16bits color mode. v3: Check gamma_lut size in atomic check. v4: revert 16bits mode, v1 was correct. make sure gamma table are set when primary plane format changes. remove rgb888 format that is not used. Signed-off-by: Jocelyn Falempe Tested-by: Thomas Zimmermann Reviewed-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20220930094754.745626-1-jfalempe@redhat.com --- drivers/gpu/drm/ast/ast_mode.c | 87 +++++++++++++++++++++++++++++++++--------- 1 file changed, 70 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index 1bc0220e6783..8ff998da71ef 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -48,6 +48,8 @@ #include "ast_drv.h" #include "ast_tables.h" +#define AST_LUT_SIZE 256 + static inline void ast_load_palette_index(struct ast_private *ast, u8 index, u8 red, u8 green, u8 blue) @@ -62,20 +64,46 @@ static inline void ast_load_palette_index(struct ast_private *ast, ast_io_read8(ast, AST_IO_SEQ_PORT); } -static void ast_crtc_load_lut(struct ast_private *ast, struct drm_crtc *crtc) +static void ast_crtc_set_gamma_linear(struct ast_private *ast, + const struct drm_format_info *format) { - u16 *r, *g, *b; int i; - if (!crtc->enabled) - return; + switch (format->format) { + case DRM_FORMAT_C8: /* In this case, gamma table is used as color palette */ + case DRM_FORMAT_RGB565: + case DRM_FORMAT_XRGB8888: + for (i = 0; i < AST_LUT_SIZE; i++) + ast_load_palette_index(ast, i, i, i, i); + break; + default: + drm_warn_once(&ast->base, "Unsupported format %p4cc for gamma correction\n", + &format->format); + break; + } +} - r = crtc->gamma_store; - g = r + crtc->gamma_size; - b = g + crtc->gamma_size; +static void ast_crtc_set_gamma(struct ast_private *ast, + const struct drm_format_info *format, + struct drm_color_lut *lut) +{ + int i; - for (i = 0; i < 256; i++) - ast_load_palette_index(ast, i, *r++ >> 8, *g++ >> 8, *b++ >> 8); + switch (format->format) { + case DRM_FORMAT_C8: /* In this case, gamma table is used as color palette */ + case DRM_FORMAT_RGB565: + case DRM_FORMAT_XRGB8888: + for (i = 0; i < AST_LUT_SIZE; i++) + ast_load_palette_index(ast, i, + lut[i].red >> 8, + lut[i].green >> 8, + lut[i].blue >> 8); + break; + default: + drm_warn_once(&ast->base, "Unsupported format %p4cc for gamma correction\n", + &format->format); + break; + } } static bool ast_get_vbios_mode_info(const struct drm_format_info *format, @@ -1026,9 +1054,11 @@ static void ast_crtc_dpms(struct drm_crtc *crtc, int mode) ast_set_color_reg(ast, format); ast_set_vbios_color_reg(ast, format, vbios_mode_info); + if (crtc->state->gamma_lut) + ast_crtc_set_gamma(ast, format, crtc->state->gamma_lut->data); + else + ast_crtc_set_gamma_linear(ast, format); } - - ast_crtc_load_lut(ast, crtc); break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: @@ -1123,6 +1153,8 @@ static int ast_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state) { struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc); + struct ast_crtc_state *old_ast_crtc_state = to_ast_crtc_state(old_crtc_state); struct drm_device *dev = crtc->dev; struct ast_crtc_state *ast_state; const struct drm_format_info *format; @@ -1142,6 +1174,22 @@ static int ast_crtc_helper_atomic_check(struct drm_crtc *crtc, if (drm_WARN_ON_ONCE(dev, !format)) return -EINVAL; /* BUG: We didn't set format in primary check(). */ + /* + * The gamma LUT has to be reloaded after changing the primary + * plane's color format. + */ + if (old_ast_crtc_state->format != format) + crtc_state->color_mgmt_changed = true; + + if (crtc_state->color_mgmt_changed && crtc_state->gamma_lut) { + if (crtc_state->gamma_lut->length != + AST_LUT_SIZE * sizeof(struct drm_color_lut)) { + drm_err(dev, "Wrong size for gamma_lut %zu\n", + crtc_state->gamma_lut->length); + return -EINVAL; + } + } + succ = ast_get_vbios_mode_info(format, &crtc_state->mode, &crtc_state->adjusted_mode, &ast_state->vbios_mode_info); @@ -1172,20 +1220,23 @@ ast_crtc_helper_atomic_flush(struct drm_crtc *crtc, { struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); - struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state, - crtc); struct drm_device *dev = crtc->dev; struct ast_private *ast = to_ast_private(dev); struct ast_crtc_state *ast_crtc_state = to_ast_crtc_state(crtc_state); - struct ast_crtc_state *old_ast_crtc_state = to_ast_crtc_state(old_crtc_state); struct ast_vbios_mode_info *vbios_mode_info = &ast_crtc_state->vbios_mode_info; /* * The gamma LUT has to be reloaded after changing the primary * plane's color format. */ - if (old_ast_crtc_state->format != ast_crtc_state->format) - ast_crtc_load_lut(ast, crtc); + if (crtc_state->enable && crtc_state->color_mgmt_changed) { + if (crtc_state->gamma_lut) + ast_crtc_set_gamma(ast, + ast_crtc_state->format, + crtc_state->gamma_lut->data); + else + ast_crtc_set_gamma_linear(ast, ast_crtc_state->format); + } //Set Aspeed Display-Port if (ast->tx_chip_types & AST_TX_ASTDP_BIT) @@ -1323,7 +1374,9 @@ static int ast_crtc_init(struct drm_device *dev) if (ret) return ret; - drm_mode_crtc_set_gamma_size(crtc, 256); + drm_mode_crtc_set_gamma_size(crtc, AST_LUT_SIZE); + drm_crtc_enable_color_mgmt(crtc, 0, false, AST_LUT_SIZE); + drm_crtc_helper_add(crtc, &ast_crtc_helper_funcs); return 0; -- cgit From fdd0640b639070efb58226c96cea5861150e8dce Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 30 Sep 2022 17:29:44 +0200 Subject: drm/ssd130x: Iterate over damage clips instead of using a merged rect The drm_atomic_helper_damage_merged() helper merges all the damage clips into one rectangle. If there are multiple damage clips that aren't close to each other, the resulting rectangle could be quite big. Instead of using that function helper, iterate over all the damage clips and update them one by one. Suggested-by: Jocelyn Falempe Signed-off-by: Javier Martinez Canillas Acked-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20220930152944.2584356-1-javierm@redhat.com --- drivers/gpu/drm/solomon/ssd130x.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/solomon/ssd130x.c b/drivers/gpu/drm/solomon/ssd130x.c index bc41a5ae810a..f456b233d2e7 100644 --- a/drivers/gpu/drm/solomon/ssd130x.c +++ b/drivers/gpu/drm/solomon/ssd130x.c @@ -578,21 +578,24 @@ static void ssd130x_primary_plane_helper_atomic_update(struct drm_plane *plane, struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); + struct drm_atomic_helper_damage_iter iter; struct drm_device *drm = plane->dev; - struct drm_rect src_clip, dst_clip; + struct drm_rect dst_clip; + struct drm_rect damage; int idx; - if (!drm_atomic_helper_damage_merged(old_plane_state, plane_state, &src_clip)) + if (!drm_dev_enter(drm, &idx)) return; - dst_clip = plane_state->dst; - if (!drm_rect_intersect(&dst_clip, &src_clip)) - return; + drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state); + drm_atomic_for_each_plane_damage(&iter, &damage) { + dst_clip = plane_state->dst; - if (!drm_dev_enter(drm, &idx)) - return; + if (!drm_rect_intersect(&dst_clip, &damage)) + continue; - ssd130x_fb_blit_rect(plane_state->fb, &shadow_plane_state->data[0], &dst_clip); + ssd130x_fb_blit_rect(plane_state->fb, &shadow_plane_state->data[0], &dst_clip); + } drm_dev_exit(idx); } -- cgit From cf867d6a746c942c8ebf4aed0a28cc13ad796caa Mon Sep 17 00:00:00 2001 From: Radhakrishna Sripada Date: Tue, 4 Oct 2022 17:20:13 -0700 Subject: drm/i915/mtl: Add MTP ddc pin configuration Meteorlake PCH reuses Alderlake vbt, DE pin mapping. Extend ADL-P pin mapping for Meteorlake. Bspec: 20124 does not have the mapping for MTP. Based on Bspec:49306, 64051, it is concluded that MTP and ADL-P PCH have the same vbt -> DE pin pair mapping. Reviewed-by: Lucas De Marchi Signed-off-by: Radhakrishna Sripada Link: https://patchwork.freedesktop.org/patch/msgid/20221005002534.2966978-1-radhakrishna.sripada@intel.com --- drivers/gpu/drm/i915/display/intel_bios.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index 4c543e8205ca..c2987f2c2b2e 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -2188,7 +2188,7 @@ static u8 map_ddc_pin(struct drm_i915_private *i915, u8 vbt_pin) const u8 *ddc_pin_map; int n_entries; - if (IS_ALDERLAKE_P(i915)) { + if (HAS_PCH_MTP(i915) || IS_ALDERLAKE_P(i915)) { ddc_pin_map = adlp_ddc_pin_map; n_entries = ARRAY_SIZE(adlp_ddc_pin_map); } else if (IS_ALDERLAKE_S(i915)) { -- cgit From 49d1310a76dd6ae7b4a2cd27732d46fe58aa8177 Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Wed, 5 Oct 2022 16:31:47 +0100 Subject: drm/i915: add back GEN12_BDSM_MASK The mask was added in commit e5f415bfc5c2 ("drm/i915: Add missing mask when reading GEN12_DSMBASE"), but then looks to be dropped in some unrelated code movement in commit dbb2ffbfd708 ("drm/i915/mtl: enable local stolen memory") without explanation. Add it back. Fixes: dbb2ffbfd708 ("drm/i915/mtl: enable local stolen memory") Signed-off-by: Matthew Auld Cc: Aravind Iddamsetty Cc: Lucas De Marchi Cc: Matt Roper Reviewed-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20221005153148.758822-1-matthew.auld@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_stolen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c index 910086974454..2c4922961f33 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c @@ -910,7 +910,7 @@ i915_gem_stolen_lmem_setup(struct drm_i915_private *i915, u16 type, GEM_BUG_ON((dsm_size + SZ_8M) > lmem_size); } else { /* Use DSM base address instead for stolen memory */ - dsm_base = intel_uncore_read64(uncore, GEN12_DSMBASE); + dsm_base = intel_uncore_read64(uncore, GEN12_DSMBASE) & GEN12_BDSM_MASK; if (WARN_ON(lmem_size < dsm_base)) return ERR_PTR(-ENODEV); dsm_size = lmem_size - dsm_base; -- cgit From 0da9493e841b92fc08c2d73612a9b0be285a1be0 Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Wed, 5 Oct 2022 16:31:48 +0100 Subject: drm/i915: restore stolen memory behaviour for DG2 Restore the previous behaviour here where we compare the pci_resource_len() with the actual lmem_size, and not the dsm size, since dsm here is just some subset snipped off the end of the lmem. Otherwise we will incorrectly report an io_size > 0 on small-bar systems. It doesn't looks like MTL is expecting small-bar with its stolen memory, based on: GEM_BUG_ON(pci_resource_len(pdev, GEN12_LMEM_BAR) != SZ_256M) GEM_BUG_ON((dsm_size + SZ_8M) > lmem_size) So just move the HAS_BAR2_SMEM_STOLEN() check first, which then ignores the small bar part, and we can go back to checking lmem_size against the BAR size. Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/7007 Fixes: dbb2ffbfd708 ("drm/i915/mtl: enable local stolen memory") Signed-off-by: Matthew Auld Cc: Aravind Iddamsetty Cc: Lucas De Marchi Cc: Matt Roper Reviewed-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20221005153148.758822-2-matthew.auld@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_stolen.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c index 2c4922961f33..1e00cf4d3ace 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c @@ -917,11 +917,11 @@ i915_gem_stolen_lmem_setup(struct drm_i915_private *i915, u16 type, } io_size = dsm_size; - if (pci_resource_len(pdev, GEN12_LMEM_BAR) < dsm_size) { + if (HAS_BAR2_SMEM_STOLEN(i915)) { + io_start = pci_resource_start(pdev, GEN12_LMEM_BAR) + SZ_8M; + } else if (pci_resource_len(pdev, GEN12_LMEM_BAR) < lmem_size) { io_start = 0; io_size = 0; - } else if (HAS_BAR2_SMEM_STOLEN(i915)) { - io_start = pci_resource_start(pdev, GEN12_LMEM_BAR) + SZ_8M; } else { io_start = pci_resource_start(pdev, GEN12_LMEM_BAR) + dsm_base; } -- cgit From 43d3f3b94efc134317d40ec7c69ae1180ed5ac9c Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Fri, 9 Sep 2022 11:30:00 +0200 Subject: drm/fourcc: add Vivante tile status modifiers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The tile status modifiers can be combined with all of the usual color buffer modifiers. When they are present an additional plane is added to the surfaces to share the tile status buffer. The TS modifiers describe the interpretation of the tag bits in this buffer. Signed-off-by: Lucas Stach Reviewed-by: Christian Gmeiner Reviewed-by: Guido Günther Link: https://patchwork.freedesktop.org/patch/msgid/20220909093000.3458413-1-l.stach@pengutronix.de --- include/uapi/drm/drm_fourcc.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index 868d6909b718..bc056f2d537d 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -744,6 +744,35 @@ extern "C" { */ #define DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED fourcc_mod_code(VIVANTE, 4) +/* + * Vivante TS (tile-status) buffer modifiers. They can be combined with all of + * the color buffer tiling modifiers defined above. When TS is present it's a + * separate buffer containing the clear/compression status of each tile. The + * modifiers are defined as VIVANTE_MOD_TS_c_s, where c is the color buffer + * tile size in bytes covered by one entry in the status buffer and s is the + * number of status bits per entry. + * We reserve the top 8 bits of the Vivante modifier space for tile status + * clear/compression modifiers, as future cores might add some more TS layout + * variations. + */ +#define VIVANTE_MOD_TS_64_4 (1ULL << 48) +#define VIVANTE_MOD_TS_64_2 (2ULL << 48) +#define VIVANTE_MOD_TS_128_4 (3ULL << 48) +#define VIVANTE_MOD_TS_256_4 (4ULL << 48) +#define VIVANTE_MOD_TS_MASK (0xfULL << 48) + +/* + * Vivante compression modifiers. Those depend on a TS modifier being present + * as the TS bits get reinterpreted as compression tags instead of simple + * clear markers when compression is enabled. + */ +#define VIVANTE_MOD_COMP_DEC400 (1ULL << 52) +#define VIVANTE_MOD_COMP_MASK (0xfULL << 52) + +/* Masking out the extension bits will yield the base modifier. */ +#define VIVANTE_MOD_EXT_MASK (VIVANTE_MOD_TS_MASK | \ + VIVANTE_MOD_COMP_MASK) + /* NVIDIA frame buffer modifiers */ /* -- cgit From 59a811faa74f4326fe2d48d2b334c0ee95922628 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 6 Oct 2022 11:53:40 +0200 Subject: drm/udl: Rename struct udl_drm_connector to struct udl_connector Remove the _drm_ infix from struct udl_drm_connector and introduce a macro for upcasting from struct drm_connector. No functional changes. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20221006095355.23579-2-tzimmermann@suse.de --- drivers/gpu/drm/udl/udl_connector.c | 19 +++++-------------- drivers/gpu/drm/udl/udl_connector.h | 10 ++++++++-- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c index fade4c7adbf7..3c8068626384 100644 --- a/drivers/gpu/drm/udl/udl_connector.c +++ b/drivers/gpu/drm/udl/udl_connector.c @@ -46,10 +46,7 @@ static int udl_get_edid_block(void *data, u8 *buf, unsigned int block, static int udl_get_modes(struct drm_connector *connector) { - struct udl_drm_connector *udl_connector = - container_of(connector, - struct udl_drm_connector, - connector); + struct udl_connector *udl_connector = to_udl_connector(connector); drm_connector_update_edid_property(connector, udl_connector->edid); if (udl_connector->edid) @@ -74,10 +71,7 @@ static enum drm_connector_status udl_detect(struct drm_connector *connector, bool force) { struct udl_device *udl = to_udl(connector->dev); - struct udl_drm_connector *udl_connector = - container_of(connector, - struct udl_drm_connector, - connector); + struct udl_connector *udl_connector = to_udl_connector(connector); /* cleanup previous edid */ if (udl_connector->edid != NULL) { @@ -94,10 +88,7 @@ udl_detect(struct drm_connector *connector, bool force) static void udl_connector_destroy(struct drm_connector *connector) { - struct udl_drm_connector *udl_connector = - container_of(connector, - struct udl_drm_connector, - connector); + struct udl_connector *udl_connector = to_udl_connector(connector); drm_connector_cleanup(connector); kfree(udl_connector->edid); @@ -120,10 +111,10 @@ static const struct drm_connector_funcs udl_connector_funcs = { struct drm_connector *udl_connector_init(struct drm_device *dev) { - struct udl_drm_connector *udl_connector; + struct udl_connector *udl_connector; struct drm_connector *connector; - udl_connector = kzalloc(sizeof(struct udl_drm_connector), GFP_KERNEL); + udl_connector = kzalloc(sizeof(*udl_connector), GFP_KERNEL); if (!udl_connector) return ERR_PTR(-ENOMEM); diff --git a/drivers/gpu/drm/udl/udl_connector.h b/drivers/gpu/drm/udl/udl_connector.h index 7f2d392df173..74ad68fd3cc9 100644 --- a/drivers/gpu/drm/udl/udl_connector.h +++ b/drivers/gpu/drm/udl/udl_connector.h @@ -1,15 +1,21 @@ #ifndef __UDL_CONNECTOR_H__ #define __UDL_CONNECTOR_H__ -#include +#include + +#include struct edid; -struct udl_drm_connector { +struct udl_connector { struct drm_connector connector; /* last udl_detect edid */ struct edid *edid; }; +static inline struct udl_connector *to_udl_connector(struct drm_connector *connector) +{ + return container_of(connector, struct udl_connector, connector); +} #endif //__UDL_CONNECTOR_H__ -- cgit From c020f66013b6136a68a3a4ad74cc7af3b3310586 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 6 Oct 2022 11:53:41 +0200 Subject: drm/udl: Test pixel limit in mode-config's mode-valid function The sku_pixel_limit is a per-device property, similar to the amount of available video memory. Move the respective mode-valid test from the connector to the mode-config structure. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20221006095355.23579-3-tzimmermann@suse.de --- drivers/gpu/drm/udl/udl_connector.c | 14 -------------- drivers/gpu/drm/udl/udl_modeset.c | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c index 3c8068626384..e9539829032c 100644 --- a/drivers/gpu/drm/udl/udl_connector.c +++ b/drivers/gpu/drm/udl/udl_connector.c @@ -54,19 +54,6 @@ static int udl_get_modes(struct drm_connector *connector) return 0; } -static enum drm_mode_status udl_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) -{ - struct udl_device *udl = to_udl(connector->dev); - if (!udl->sku_pixel_limit) - return 0; - - if (mode->vdisplay * mode->hdisplay > udl->sku_pixel_limit) - return MODE_VIRTUAL_Y; - - return 0; -} - static enum drm_connector_status udl_detect(struct drm_connector *connector, bool force) { @@ -97,7 +84,6 @@ static void udl_connector_destroy(struct drm_connector *connector) static const struct drm_connector_helper_funcs udl_connector_helper_funcs = { .get_modes = udl_get_modes, - .mode_valid = udl_mode_valid, }; static const struct drm_connector_funcs udl_connector_funcs = { diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c index ec6876f449f3..c7adc29a53a1 100644 --- a/drivers/gpu/drm/udl/udl_modeset.c +++ b/drivers/gpu/drm/udl/udl_modeset.c @@ -407,8 +407,22 @@ static const struct drm_simple_display_pipe_funcs udl_simple_display_pipe_funcs * Modesetting */ +static enum drm_mode_status udl_mode_config_mode_valid(struct drm_device *dev, + const struct drm_display_mode *mode) +{ + struct udl_device *udl = to_udl(dev); + + if (udl->sku_pixel_limit) { + if (mode->vdisplay * mode->hdisplay > udl->sku_pixel_limit) + return MODE_MEM; + } + + return MODE_OK; +} + static const struct drm_mode_config_funcs udl_mode_funcs = { .fb_create = drm_gem_fb_create_with_dirty, + .mode_valid = udl_mode_config_mode_valid, .atomic_check = drm_atomic_helper_check, .atomic_commit = drm_atomic_helper_commit, }; -- cgit From 2c1eafc40e53312864bf2fdccb55052dcbd9e8b2 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 6 Oct 2022 11:53:42 +0200 Subject: drm/udl: Use USB timeout constant when reading EDID Set the USB control-message timeout to the USB default of 5 seconds. Done for consistency with other uses of usb_control_msg() in udl and other drivers. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20221006095355.23579-4-tzimmermann@suse.de --- drivers/gpu/drm/udl/udl_connector.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c index e9539829032c..cb3d6820eaf9 100644 --- a/drivers/gpu/drm/udl/udl_connector.c +++ b/drivers/gpu/drm/udl/udl_connector.c @@ -31,7 +31,7 @@ static int udl_get_edid_block(void *data, u8 *buf, unsigned int block, int bval = (i + block * EDID_LENGTH) << 8; ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x02, (0x80 | (0x02 << 5)), bval, - 0xA1, read_buff, 2, 1000); + 0xA1, read_buff, 2, USB_CTRL_GET_TIMEOUT); if (ret < 1) { DRM_ERROR("Read EDID byte %d failed err %x\n", i, ret); kfree(read_buff); -- cgit From 43858eb41e0dde6e48565c13cdabac95b5d9df90 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 6 Oct 2022 11:53:43 +0200 Subject: drm/udl: Various improvements to the connector Add style fixes, better error handling and reporting, and minor clean-up changes to the connector code before moving the code to the rest of the modesetting pipeline. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20221006095355.23579-5-tzimmermann@suse.de --- drivers/gpu/drm/udl/udl_connector.c | 64 +++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c index cb3d6820eaf9..538b47ffa67f 100644 --- a/drivers/gpu/drm/udl/udl_connector.c +++ b/drivers/gpu/drm/udl/udl_connector.c @@ -15,56 +15,64 @@ #include "udl_connector.h" #include "udl_drv.h" -static int udl_get_edid_block(void *data, u8 *buf, unsigned int block, - size_t len) +static int udl_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len) { - int ret, i; - u8 *read_buff; struct udl_device *udl = data; + struct drm_device *dev = &udl->drm; struct usb_device *udev = udl_to_usb_device(udl); + u8 *read_buff; + int ret; + size_t i; read_buff = kmalloc(2, GFP_KERNEL); if (!read_buff) - return -1; + return -ENOMEM; for (i = 0; i < len; i++) { int bval = (i + block * EDID_LENGTH) << 8; + ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x02, (0x80 | (0x02 << 5)), bval, 0xA1, read_buff, 2, USB_CTRL_GET_TIMEOUT); - if (ret < 1) { - DRM_ERROR("Read EDID byte %d failed err %x\n", i, ret); - kfree(read_buff); - return -1; + if (ret < 0) { + drm_err(dev, "Read EDID byte %zu failed err %x\n", i, ret); + goto err_kfree; + } else if (ret < 1) { + ret = -EIO; + drm_err(dev, "Read EDID byte %zu failed\n", i); + goto err_kfree; } + buf[i] = read_buff[1]; } kfree(read_buff); + return 0; + +err_kfree: + kfree(read_buff); + return ret; } -static int udl_get_modes(struct drm_connector *connector) +static int udl_connector_helper_get_modes(struct drm_connector *connector) { struct udl_connector *udl_connector = to_udl_connector(connector); drm_connector_update_edid_property(connector, udl_connector->edid); if (udl_connector->edid) return drm_add_edid_modes(connector, udl_connector->edid); + return 0; } -static enum drm_connector_status -udl_detect(struct drm_connector *connector, bool force) +static enum drm_connector_status udl_connector_detect(struct drm_connector *connector, bool force) { struct udl_device *udl = to_udl(connector->dev); struct udl_connector *udl_connector = to_udl_connector(connector); - /* cleanup previous edid */ - if (udl_connector->edid != NULL) { - kfree(udl_connector->edid); - udl_connector->edid = NULL; - } + /* cleanup previous EDID */ + kfree(udl_connector->edid); udl_connector->edid = drm_do_get_edid(connector, udl_get_edid_block, udl); if (!udl_connector->edid) @@ -79,38 +87,46 @@ static void udl_connector_destroy(struct drm_connector *connector) drm_connector_cleanup(connector); kfree(udl_connector->edid); - kfree(connector); + kfree(udl_connector); } static const struct drm_connector_helper_funcs udl_connector_helper_funcs = { - .get_modes = udl_get_modes, + .get_modes = udl_connector_helper_get_modes, }; static const struct drm_connector_funcs udl_connector_funcs = { .reset = drm_atomic_helper_connector_reset, - .detect = udl_detect, + .detect = udl_connector_detect, .fill_modes = drm_helper_probe_single_connector_modes, .destroy = udl_connector_destroy, .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; struct drm_connector *udl_connector_init(struct drm_device *dev) { struct udl_connector *udl_connector; struct drm_connector *connector; + int ret; udl_connector = kzalloc(sizeof(*udl_connector), GFP_KERNEL); if (!udl_connector) return ERR_PTR(-ENOMEM); connector = &udl_connector->connector; - drm_connector_init(dev, connector, &udl_connector_funcs, - DRM_MODE_CONNECTOR_VGA); + ret = drm_connector_init(dev, connector, &udl_connector_funcs, DRM_MODE_CONNECTOR_VGA); + if (ret) + goto err_kfree; + drm_connector_helper_add(connector, &udl_connector_helper_funcs); connector->polled = DRM_CONNECTOR_POLL_HPD | - DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; + DRM_CONNECTOR_POLL_CONNECT | + DRM_CONNECTOR_POLL_DISCONNECT; return connector; + +err_kfree: + kfree(udl_connector); + return ERR_PTR(ret); } -- cgit From 0862cfd3e22f3f936927f2f7381c2519ba034c6e Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 6 Oct 2022 11:53:44 +0200 Subject: drm/udl: Move connector to modesetting code Move the connector next to the rest of the modesetting code. No functional changes. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20221006095355.23579-6-tzimmermann@suse.de --- drivers/gpu/drm/udl/Makefile | 2 +- drivers/gpu/drm/udl/udl_connector.c | 132 ------------------------------------ drivers/gpu/drm/udl/udl_connector.h | 21 ------ drivers/gpu/drm/udl/udl_drv.h | 11 +++ drivers/gpu/drm/udl/udl_modeset.c | 122 +++++++++++++++++++++++++++++++++ 5 files changed, 134 insertions(+), 154 deletions(-) delete mode 100644 drivers/gpu/drm/udl/udl_connector.c delete mode 100644 drivers/gpu/drm/udl/udl_connector.h diff --git a/drivers/gpu/drm/udl/Makefile b/drivers/gpu/drm/udl/Makefile index 24d61f61d7db..3f6db179455d 100644 --- a/drivers/gpu/drm/udl/Makefile +++ b/drivers/gpu/drm/udl/Makefile @@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only -udl-y := udl_drv.o udl_modeset.o udl_connector.o udl_main.o udl_transfer.o +udl-y := udl_drv.o udl_modeset.o udl_main.o udl_transfer.o obj-$(CONFIG_DRM_UDL) := udl.o diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c deleted file mode 100644 index 538b47ffa67f..000000000000 --- a/drivers/gpu/drm/udl/udl_connector.c +++ /dev/null @@ -1,132 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2012 Red Hat - * based in parts on udlfb.c: - * Copyright (C) 2009 Roberto De Ioris - * Copyright (C) 2009 Jaya Kumar - * Copyright (C) 2009 Bernie Thompson - */ - -#include -#include -#include -#include - -#include "udl_connector.h" -#include "udl_drv.h" - -static int udl_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len) -{ - struct udl_device *udl = data; - struct drm_device *dev = &udl->drm; - struct usb_device *udev = udl_to_usb_device(udl); - u8 *read_buff; - int ret; - size_t i; - - read_buff = kmalloc(2, GFP_KERNEL); - if (!read_buff) - return -ENOMEM; - - for (i = 0; i < len; i++) { - int bval = (i + block * EDID_LENGTH) << 8; - - ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), - 0x02, (0x80 | (0x02 << 5)), bval, - 0xA1, read_buff, 2, USB_CTRL_GET_TIMEOUT); - if (ret < 0) { - drm_err(dev, "Read EDID byte %zu failed err %x\n", i, ret); - goto err_kfree; - } else if (ret < 1) { - ret = -EIO; - drm_err(dev, "Read EDID byte %zu failed\n", i); - goto err_kfree; - } - - buf[i] = read_buff[1]; - } - - kfree(read_buff); - - return 0; - -err_kfree: - kfree(read_buff); - return ret; -} - -static int udl_connector_helper_get_modes(struct drm_connector *connector) -{ - struct udl_connector *udl_connector = to_udl_connector(connector); - - drm_connector_update_edid_property(connector, udl_connector->edid); - if (udl_connector->edid) - return drm_add_edid_modes(connector, udl_connector->edid); - - return 0; -} - -static enum drm_connector_status udl_connector_detect(struct drm_connector *connector, bool force) -{ - struct udl_device *udl = to_udl(connector->dev); - struct udl_connector *udl_connector = to_udl_connector(connector); - - /* cleanup previous EDID */ - kfree(udl_connector->edid); - - udl_connector->edid = drm_do_get_edid(connector, udl_get_edid_block, udl); - if (!udl_connector->edid) - return connector_status_disconnected; - - return connector_status_connected; -} - -static void udl_connector_destroy(struct drm_connector *connector) -{ - struct udl_connector *udl_connector = to_udl_connector(connector); - - drm_connector_cleanup(connector); - kfree(udl_connector->edid); - kfree(udl_connector); -} - -static const struct drm_connector_helper_funcs udl_connector_helper_funcs = { - .get_modes = udl_connector_helper_get_modes, -}; - -static const struct drm_connector_funcs udl_connector_funcs = { - .reset = drm_atomic_helper_connector_reset, - .detect = udl_connector_detect, - .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = udl_connector_destroy, - .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -}; - -struct drm_connector *udl_connector_init(struct drm_device *dev) -{ - struct udl_connector *udl_connector; - struct drm_connector *connector; - int ret; - - udl_connector = kzalloc(sizeof(*udl_connector), GFP_KERNEL); - if (!udl_connector) - return ERR_PTR(-ENOMEM); - - connector = &udl_connector->connector; - ret = drm_connector_init(dev, connector, &udl_connector_funcs, DRM_MODE_CONNECTOR_VGA); - if (ret) - goto err_kfree; - - drm_connector_helper_add(connector, &udl_connector_helper_funcs); - - connector->polled = DRM_CONNECTOR_POLL_HPD | - DRM_CONNECTOR_POLL_CONNECT | - DRM_CONNECTOR_POLL_DISCONNECT; - - return connector; - -err_kfree: - kfree(udl_connector); - return ERR_PTR(ret); -} diff --git a/drivers/gpu/drm/udl/udl_connector.h b/drivers/gpu/drm/udl/udl_connector.h deleted file mode 100644 index 74ad68fd3cc9..000000000000 --- a/drivers/gpu/drm/udl/udl_connector.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef __UDL_CONNECTOR_H__ -#define __UDL_CONNECTOR_H__ - -#include - -#include - -struct edid; - -struct udl_connector { - struct drm_connector connector; - /* last udl_detect edid */ - struct edid *edid; -}; - -static inline struct udl_connector *to_udl_connector(struct drm_connector *connector) -{ - return container_of(connector, struct udl_connector, connector); -} - -#endif //__UDL_CONNECTOR_H__ diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h index b4cc7cc568c7..d7a3d495f2e7 100644 --- a/drivers/gpu/drm/udl/udl_drv.h +++ b/drivers/gpu/drm/udl/udl_drv.h @@ -46,6 +46,17 @@ struct urb_list { size_t size; }; +struct udl_connector { + struct drm_connector connector; + /* last udl_detect edid */ + struct edid *edid; +}; + +static inline struct udl_connector *to_udl_connector(struct drm_connector *connector) +{ + return container_of(connector, struct udl_connector, connector); +} + struct udl_device { struct drm_device drm; struct device *dev; diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c index c7adc29a53a1..93e7554e83fa 100644 --- a/drivers/gpu/drm/udl/udl_modeset.c +++ b/drivers/gpu/drm/udl/udl_modeset.c @@ -11,11 +11,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include "udl_drv.h" @@ -403,6 +405,126 @@ static const struct drm_simple_display_pipe_funcs udl_simple_display_pipe_funcs DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS, }; +/* + * Connector + */ + +static int udl_connector_helper_get_modes(struct drm_connector *connector) +{ + struct udl_connector *udl_connector = to_udl_connector(connector); + + drm_connector_update_edid_property(connector, udl_connector->edid); + if (udl_connector->edid) + return drm_add_edid_modes(connector, udl_connector->edid); + + return 0; +} + +static const struct drm_connector_helper_funcs udl_connector_helper_funcs = { + .get_modes = udl_connector_helper_get_modes, +}; + +static int udl_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len) +{ + struct udl_device *udl = data; + struct drm_device *dev = &udl->drm; + struct usb_device *udev = udl_to_usb_device(udl); + u8 *read_buff; + int ret; + size_t i; + + read_buff = kmalloc(2, GFP_KERNEL); + if (!read_buff) + return -ENOMEM; + + for (i = 0; i < len; i++) { + int bval = (i + block * EDID_LENGTH) << 8; + + ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + 0x02, (0x80 | (0x02 << 5)), bval, + 0xA1, read_buff, 2, USB_CTRL_GET_TIMEOUT); + if (ret < 0) { + drm_err(dev, "Read EDID byte %zu failed err %x\n", i, ret); + goto err_kfree; + } else if (ret < 1) { + ret = -EIO; + drm_err(dev, "Read EDID byte %zu failed\n", i); + goto err_kfree; + } + + buf[i] = read_buff[1]; + } + + kfree(read_buff); + + return 0; + +err_kfree: + kfree(read_buff); + return ret; +} + +static enum drm_connector_status udl_connector_detect(struct drm_connector *connector, bool force) +{ + struct udl_device *udl = to_udl(connector->dev); + struct udl_connector *udl_connector = to_udl_connector(connector); + + /* cleanup previous EDID */ + kfree(udl_connector->edid); + + udl_connector->edid = drm_do_get_edid(connector, udl_get_edid_block, udl); + if (!udl_connector->edid) + return connector_status_disconnected; + + return connector_status_connected; +} + +static void udl_connector_destroy(struct drm_connector *connector) +{ + struct udl_connector *udl_connector = to_udl_connector(connector); + + drm_connector_cleanup(connector); + kfree(udl_connector->edid); + kfree(udl_connector); +} + +static const struct drm_connector_funcs udl_connector_funcs = { + .reset = drm_atomic_helper_connector_reset, + .detect = udl_connector_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = udl_connector_destroy, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +struct drm_connector *udl_connector_init(struct drm_device *dev) +{ + struct udl_connector *udl_connector; + struct drm_connector *connector; + int ret; + + udl_connector = kzalloc(sizeof(*udl_connector), GFP_KERNEL); + if (!udl_connector) + return ERR_PTR(-ENOMEM); + + connector = &udl_connector->connector; + ret = drm_connector_init(dev, connector, &udl_connector_funcs, DRM_MODE_CONNECTOR_VGA); + if (ret) + goto err_kfree; + + drm_connector_helper_add(connector, &udl_connector_helper_funcs); + + connector->polled = DRM_CONNECTOR_POLL_HPD | + DRM_CONNECTOR_POLL_CONNECT | + DRM_CONNECTOR_POLL_DISCONNECT; + + return connector; + +err_kfree: + kfree(udl_connector); + return ERR_PTR(ret); +} + /* * Modesetting */ -- cgit From efaa418fd75ebe8dbca57fd10a003910e46fc5a3 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 6 Oct 2022 11:53:45 +0200 Subject: drm/udl: Remove udl_simple_display_pipe_mode_valid() Remove the empty function udl_simple_display_pipe_mode_valid() and let simple-KMS helpers accept the modes. No functional changes. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20221006095355.23579-7-tzimmermann@suse.de --- drivers/gpu/drm/udl/udl_modeset.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c index 93e7554e83fa..7f8bde89396d 100644 --- a/drivers/gpu/drm/udl/udl_modeset.c +++ b/drivers/gpu/drm/udl/udl_modeset.c @@ -310,13 +310,6 @@ static const uint32_t udl_simple_display_pipe_formats[] = { DRM_FORMAT_XRGB8888, }; -static enum drm_mode_status -udl_simple_display_pipe_mode_valid(struct drm_simple_display_pipe *pipe, - const struct drm_display_mode *mode) -{ - return MODE_OK; -} - static void udl_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe, struct drm_crtc_state *crtc_state, @@ -398,7 +391,6 @@ udl_simple_display_pipe_update(struct drm_simple_display_pipe *pipe, } static const struct drm_simple_display_pipe_funcs udl_simple_display_pipe_funcs = { - .mode_valid = udl_simple_display_pipe_mode_valid, .enable = udl_simple_display_pipe_enable, .disable = udl_simple_display_pipe_disable, .update = udl_simple_display_pipe_update, -- cgit From 72d73dd3a95c7e879c18a0eae8fd2af89b5b3347 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 6 Oct 2022 11:53:46 +0200 Subject: drm/udl: Convert to atomic-modesetting helpers Replace simple-KMS helpers with regular atomic-modesetting helpers. The simple-KMS helpers introduce a mid-layer abstraction without added functionality. Using regular atomic helpers makes the driver's implementation more discoverable and simplifies code sharing. The conversion effectively open-codes the simple-KMS functions and data structure within udl. No functional changes. v2: * don't use the atomic_disable plane helper Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20221006095355.23579-8-tzimmermann@suse.de --- drivers/gpu/drm/udl/udl_drv.h | 9 ++- drivers/gpu/drm/udl/udl_modeset.c | 157 +++++++++++++++++++++++++------------- 2 files changed, 112 insertions(+), 54 deletions(-) diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h index d7a3d495f2e7..e96166ce2919 100644 --- a/drivers/gpu/drm/udl/udl_drv.h +++ b/drivers/gpu/drm/udl/udl_drv.h @@ -14,10 +14,13 @@ #include #include +#include +#include #include +#include #include #include -#include +#include struct drm_mode_create_dumb; @@ -62,7 +65,9 @@ struct udl_device { struct device *dev; struct device *dmadev; - struct drm_simple_display_pipe display_pipe; + struct drm_plane primary_plane; + struct drm_crtc crtc; + struct drm_encoder encoder; struct mutex gem_lock; diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c index 7f8bde89396d..62c07289680e 100644 --- a/drivers/gpu/drm/udl/udl_modeset.c +++ b/drivers/gpu/drm/udl/udl_modeset.c @@ -8,6 +8,7 @@ * Copyright (C) 2009 Bernie Thompson */ +#include #include #include #include @@ -17,6 +18,7 @@ #include #include #include +#include #include #include @@ -302,61 +304,96 @@ out_drm_gem_fb_end_cpu_access: } /* - * Simple display pipeline + * Primary plane */ -static const uint32_t udl_simple_display_pipe_formats[] = { +static const uint32_t udl_primary_plane_formats[] = { DRM_FORMAT_RGB565, DRM_FORMAT_XRGB8888, }; -static void -udl_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe, - struct drm_crtc_state *crtc_state, - struct drm_plane_state *plane_state) +static const uint64_t udl_primary_plane_fmtmods[] = { + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID +}; + +static void udl_primary_plane_helper_atomic_update(struct drm_plane *plane, + struct drm_atomic_state *state) { - struct drm_crtc *crtc = &pipe->crtc; - struct drm_device *dev = crtc->dev; + struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); + struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); struct drm_framebuffer *fb = plane_state->fb; + struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); + struct drm_rect rect; + + if (!fb) + return; /* no framebuffer; plane is disabled */ + + if (drm_atomic_helper_damage_merged(old_plane_state, plane_state, &rect)) + udl_handle_damage(fb, &shadow_plane_state->data[0], &rect); +} + +static const struct drm_plane_helper_funcs udl_primary_plane_helper_funcs = { + DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, + .atomic_check = drm_plane_helper_atomic_check, + .atomic_update = udl_primary_plane_helper_atomic_update, +}; + +static const struct drm_plane_funcs udl_primary_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = drm_plane_cleanup, + DRM_GEM_SHADOW_PLANE_FUNCS, +}; + +/* + * CRTC + */ + +static int udl_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state) +{ + struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + + return drm_atomic_helper_check_crtc_state(new_crtc_state, false); +} + +static void udl_crtc_helper_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state) +{ + struct drm_device *dev = crtc->dev; struct udl_device *udl = to_udl(dev); + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); struct drm_display_mode *mode = &crtc_state->mode; - struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); - struct drm_rect clip = DRM_RECT_INIT(0, 0, fb->width, fb->height); char *buf; char *wrptr; int color_depth = UDL_COLOR_DEPTH_16BPP; buf = (char *)udl->mode_buf; - /* This first section has to do with setting the base address on the - * controller associated with the display. There are 2 base - * pointers, currently, we only use the 16 bpp segment. + /* + * This first section has to do with setting the base address on + * the controller associated with the display. There are 2 base + * pointers. Currently, we only use the 16 bpp segment. */ + wrptr = udl_vidreg_lock(buf); wrptr = udl_set_color_depth(wrptr, color_depth); /* set base for 16bpp segment to 0 */ wrptr = udl_set_base16bpp(wrptr, 0); /* set base for 8bpp segment to end of fb */ wrptr = udl_set_base8bpp(wrptr, 2 * mode->vdisplay * mode->hdisplay); - wrptr = udl_set_vid_cmds(wrptr, mode); wrptr = udl_set_blank_mode(wrptr, UDL_BLANK_MODE_ON); wrptr = udl_vidreg_unlock(wrptr); - wrptr = udl_dummy_render(wrptr); udl->mode_buf_len = wrptr - buf; - udl_handle_damage(fb, &shadow_plane_state->data[0], &clip); - /* enable display */ udl_crtc_write_mode_to_hw(crtc); } -static void -udl_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe) +static void udl_crtc_helper_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *state) { - struct drm_crtc *crtc = &pipe->crtc; struct drm_device *dev = crtc->dev; struct urb *urb; char *buf; @@ -374,27 +411,27 @@ udl_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe) udl_submit_urb(dev, urb, buf - (char *)urb->transfer_buffer); } -static void -udl_simple_display_pipe_update(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *old_plane_state) -{ - struct drm_plane_state *state = pipe->plane.state; - struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(state); - struct drm_framebuffer *fb = state->fb; - struct drm_rect rect; +static const struct drm_crtc_helper_funcs udl_crtc_helper_funcs = { + .atomic_check = udl_crtc_helper_atomic_check, + .atomic_enable = udl_crtc_helper_atomic_enable, + .atomic_disable = udl_crtc_helper_atomic_disable, +}; - if (!fb) - return; +static const struct drm_crtc_funcs udl_crtc_funcs = { + .reset = drm_atomic_helper_crtc_reset, + .destroy = drm_crtc_cleanup, + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, +}; - if (drm_atomic_helper_damage_merged(old_plane_state, state, &rect)) - udl_handle_damage(fb, &shadow_plane_state->data[0], &rect); -} +/* + * Encoder + */ -static const struct drm_simple_display_pipe_funcs udl_simple_display_pipe_funcs = { - .enable = udl_simple_display_pipe_enable, - .disable = udl_simple_display_pipe_disable, - .update = udl_simple_display_pipe_update, - DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS, +static const struct drm_encoder_funcs udl_encoder_funcs = { + .destroy = drm_encoder_cleanup, }; /* @@ -534,7 +571,7 @@ static enum drm_mode_status udl_mode_config_mode_valid(struct drm_device *dev, return MODE_OK; } -static const struct drm_mode_config_funcs udl_mode_funcs = { +static const struct drm_mode_config_funcs udl_mode_config_funcs = { .fb_create = drm_gem_fb_create_with_dirty, .mode_valid = udl_mode_config_mode_valid, .atomic_check = drm_atomic_helper_check, @@ -543,8 +580,10 @@ static const struct drm_mode_config_funcs udl_mode_funcs = { int udl_modeset_init(struct drm_device *dev) { - size_t format_count = ARRAY_SIZE(udl_simple_display_pipe_formats); struct udl_device *udl = to_udl(dev); + struct drm_plane *primary_plane; + struct drm_crtc *crtc; + struct drm_encoder *encoder; struct drm_connector *connector; int ret; @@ -554,28 +593,42 @@ int udl_modeset_init(struct drm_device *dev) dev->mode_config.min_width = 640; dev->mode_config.min_height = 480; - dev->mode_config.max_width = 2048; dev->mode_config.max_height = 2048; - - dev->mode_config.prefer_shadow = 0; dev->mode_config.preferred_depth = 16; + dev->mode_config.funcs = &udl_mode_config_funcs; + + primary_plane = &udl->primary_plane; + ret = drm_universal_plane_init(dev, primary_plane, 0, + &udl_primary_plane_funcs, + udl_primary_plane_formats, + ARRAY_SIZE(udl_primary_plane_formats), + udl_primary_plane_fmtmods, + DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) + return ret; + drm_plane_helper_add(primary_plane, &udl_primary_plane_helper_funcs); + drm_plane_enable_fb_damage_clips(primary_plane); + + crtc = &udl->crtc; + ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL, + &udl_crtc_funcs, NULL); + if (ret) + return ret; + drm_crtc_helper_add(crtc, &udl_crtc_helper_funcs); - dev->mode_config.funcs = &udl_mode_funcs; + encoder = &udl->encoder; + ret = drm_encoder_init(dev, encoder, &udl_encoder_funcs, DRM_MODE_ENCODER_DAC, NULL); + if (ret) + return ret; + encoder->possible_crtcs = drm_crtc_mask(crtc); connector = udl_connector_init(dev); if (IS_ERR(connector)) return PTR_ERR(connector); - - format_count = ARRAY_SIZE(udl_simple_display_pipe_formats); - - ret = drm_simple_display_pipe_init(dev, &udl->display_pipe, - &udl_simple_display_pipe_funcs, - udl_simple_display_pipe_formats, - format_count, NULL, connector); + ret = drm_connector_attach_encoder(connector, encoder); if (ret) return ret; - drm_plane_enable_fb_damage_clips(&udl->display_pipe.plane); drm_mode_config_reset(dev); -- cgit From 890e4de83898c9f34623f67b2129edfc37277ca3 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 6 Oct 2022 11:53:47 +0200 Subject: drm/udl: Simplify modesetting in CRTC's enable function Inline a modesetting helper in the CRTC's enable function. Build the command set directly in the USB URB's buffer and drop an intermediate buffer. No functional changes. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20221006095355.23579-9-tzimmermann@suse.de --- drivers/gpu/drm/udl/udl_drv.h | 3 -- drivers/gpu/drm/udl/udl_modeset.c | 61 +++++++++------------------------------ 2 files changed, 14 insertions(+), 50 deletions(-) diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h index e96166ce2919..b090b6cebdc4 100644 --- a/drivers/gpu/drm/udl/udl_drv.h +++ b/drivers/gpu/drm/udl/udl_drv.h @@ -74,9 +74,6 @@ struct udl_device { int sku_pixel_limit; struct urb_list urbs; - - char mode_buf[1024]; - uint32_t mode_buf_len; }; #define to_udl(x) container_of(x, struct udl_device, drm) diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c index 62c07289680e..a1334f4718e0 100644 --- a/drivers/gpu/drm/udl/udl_modeset.c +++ b/drivers/gpu/drm/udl/udl_modeset.c @@ -214,31 +214,6 @@ static char *udl_dummy_render(char *wrptr) return wrptr; } -static int udl_crtc_write_mode_to_hw(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct udl_device *udl = to_udl(dev); - struct urb *urb; - char *buf; - int retval; - - if (udl->mode_buf_len == 0) { - DRM_ERROR("No mode set\n"); - return -EINVAL; - } - - urb = udl_get_urb(dev); - if (!urb) - return -ENOMEM; - - buf = (char *)urb->transfer_buffer; - - memcpy(buf, udl->mode_buf, udl->mode_buf_len); - retval = udl_submit_urb(dev, urb, udl->mode_buf_len); - DRM_DEBUG("write mode info %d\n", udl->mode_buf_len); - return retval; -} - static long udl_log_cpp(unsigned int cpp) { if (WARN_ON(!is_power_of_2(cpp))) @@ -360,36 +335,28 @@ static int udl_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic static void udl_crtc_helper_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state) { struct drm_device *dev = crtc->dev; - struct udl_device *udl = to_udl(dev); struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); struct drm_display_mode *mode = &crtc_state->mode; + struct urb *urb; char *buf; - char *wrptr; - int color_depth = UDL_COLOR_DEPTH_16BPP; - buf = (char *)udl->mode_buf; - - /* - * This first section has to do with setting the base address on - * the controller associated with the display. There are 2 base - * pointers. Currently, we only use the 16 bpp segment. - */ + urb = udl_get_urb(dev); + if (!urb) + return; - wrptr = udl_vidreg_lock(buf); - wrptr = udl_set_color_depth(wrptr, color_depth); + buf = (char *)urb->transfer_buffer; + buf = udl_vidreg_lock(buf); + buf = udl_set_color_depth(buf, UDL_COLOR_DEPTH_16BPP); /* set base for 16bpp segment to 0 */ - wrptr = udl_set_base16bpp(wrptr, 0); + buf = udl_set_base16bpp(buf, 0); /* set base for 8bpp segment to end of fb */ - wrptr = udl_set_base8bpp(wrptr, 2 * mode->vdisplay * mode->hdisplay); - wrptr = udl_set_vid_cmds(wrptr, mode); - wrptr = udl_set_blank_mode(wrptr, UDL_BLANK_MODE_ON); - wrptr = udl_vidreg_unlock(wrptr); - wrptr = udl_dummy_render(wrptr); - - udl->mode_buf_len = wrptr - buf; + buf = udl_set_base8bpp(buf, 2 * mode->vdisplay * mode->hdisplay); + buf = udl_set_vid_cmds(buf, mode); + buf = udl_set_blank_mode(buf, UDL_BLANK_MODE_ON); + buf = udl_vidreg_unlock(buf); + buf = udl_dummy_render(buf); - /* enable display */ - udl_crtc_write_mode_to_hw(crtc); + udl_submit_urb(dev, urb, buf - (char *)urb->transfer_buffer); } static void udl_crtc_helper_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *state) -- cgit From ca2bd373eb6632d5c37323755030fea6364937d0 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 6 Oct 2022 11:53:48 +0200 Subject: drm/udl: Support DRM hot-unplugging Add drm_dev_enter() and drm_dev_exit() to the various modesetting functions that interact with the device. After hot-unplugging the device, these functions will return early. So far, the udl driver relied on USB interfaces to handle unplugging of the device. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20221006095355.23579-10-tzimmermann@suse.de --- drivers/gpu/drm/udl/udl_modeset.c | 43 +++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c index a1334f4718e0..34c7fb6ecfe9 100644 --- a/drivers/gpu/drm/udl/udl_modeset.c +++ b/drivers/gpu/drm/udl/udl_modeset.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -295,17 +296,24 @@ static const uint64_t udl_primary_plane_fmtmods[] = { static void udl_primary_plane_helper_atomic_update(struct drm_plane *plane, struct drm_atomic_state *state) { + struct drm_device *dev = plane->dev; struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); struct drm_framebuffer *fb = plane_state->fb; struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); struct drm_rect rect; + int idx; + + if (!drm_dev_enter(dev, &idx)) + return; if (!fb) return; /* no framebuffer; plane is disabled */ if (drm_atomic_helper_damage_merged(old_plane_state, plane_state, &rect)) udl_handle_damage(fb, &shadow_plane_state->data[0], &rect); + + drm_dev_exit(idx); } static const struct drm_plane_helper_funcs udl_primary_plane_helper_funcs = { @@ -339,10 +347,14 @@ static void udl_crtc_helper_atomic_enable(struct drm_crtc *crtc, struct drm_atom struct drm_display_mode *mode = &crtc_state->mode; struct urb *urb; char *buf; + int idx; + + if (!drm_dev_enter(dev, &idx)) + return; urb = udl_get_urb(dev); if (!urb) - return; + goto out; buf = (char *)urb->transfer_buffer; buf = udl_vidreg_lock(buf); @@ -357,6 +369,9 @@ static void udl_crtc_helper_atomic_enable(struct drm_crtc *crtc, struct drm_atom buf = udl_dummy_render(buf); udl_submit_urb(dev, urb, buf - (char *)urb->transfer_buffer); + +out: + drm_dev_exit(idx); } static void udl_crtc_helper_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *state) @@ -364,10 +379,14 @@ static void udl_crtc_helper_atomic_disable(struct drm_crtc *crtc, struct drm_ato struct drm_device *dev = crtc->dev; struct urb *urb; char *buf; + int idx; + + if (!drm_dev_enter(dev, &idx)) + return; urb = udl_get_urb(dev); if (!urb) - return; + goto out; buf = (char *)urb->transfer_buffer; buf = udl_vidreg_lock(buf); @@ -376,6 +395,9 @@ static void udl_crtc_helper_atomic_disable(struct drm_crtc *crtc, struct drm_ato buf = udl_dummy_render(buf); udl_submit_urb(dev, urb, buf - (char *)urb->transfer_buffer); + +out: + drm_dev_exit(idx); } static const struct drm_crtc_helper_funcs udl_crtc_helper_funcs = { @@ -462,17 +484,26 @@ err_kfree: static enum drm_connector_status udl_connector_detect(struct drm_connector *connector, bool force) { - struct udl_device *udl = to_udl(connector->dev); + struct drm_device *dev = connector->dev; + struct udl_device *udl = to_udl(dev); struct udl_connector *udl_connector = to_udl_connector(connector); + enum drm_connector_status status = connector_status_disconnected; + int idx; /* cleanup previous EDID */ kfree(udl_connector->edid); + udl_connector->edid = NULL; - udl_connector->edid = drm_do_get_edid(connector, udl_get_edid_block, udl); - if (!udl_connector->edid) + if (!drm_dev_enter(dev, &idx)) return connector_status_disconnected; - return connector_status_connected; + udl_connector->edid = drm_do_get_edid(connector, udl_get_edid_block, udl); + if (udl_connector->edid) + status = connector_status_connected; + + drm_dev_exit(idx); + + return status; } static void udl_connector_destroy(struct drm_connector *connector) -- cgit From fcc21447c79816b40feddfc707006e9c72f3445e Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 6 Oct 2022 11:53:49 +0200 Subject: drm/udl: Use damage iterator Use a damage iterator to process damage areas individually. Merging damage areas can result in large updates of unchanged framebuffer regions. As USB is rather slow, it's better to process damage areas individually and hence minimize USB-transfered data. As part of the change, move drm_gem_fb_{begin,end}_cpu_access() into the plane's atomic_update helper. To avoid overhead and intermediate writers, we want to synchronize buffers and reserve access only once before copying damage areas of the framebuffer. v2: * clarify commit message (Javier) Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20221006095355.23579-11-tzimmermann@suse.de --- drivers/gpu/drm/udl/udl_modeset.c | 42 +++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c index 34c7fb6ecfe9..aee4fe2b5b08 100644 --- a/drivers/gpu/drm/udl/udl_modeset.c +++ b/drivers/gpu/drm/udl/udl_modeset.c @@ -238,15 +238,9 @@ static int udl_handle_damage(struct drm_framebuffer *fb, return ret; log_bpp = ret; - ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE); - if (ret) - return ret; - urb = udl_get_urb(dev); - if (!urb) { - ret = -ENOMEM; - goto out_drm_gem_fb_end_cpu_access; - } + if (!urb) + return -ENOMEM; cmd = urb->transfer_buffer; for (i = clip->y1; i < clip->y2; i++) { @@ -258,7 +252,7 @@ static int udl_handle_damage(struct drm_framebuffer *fb, &cmd, byte_offset, dev_byte_offset, byte_width); if (ret) - goto out_drm_gem_fb_end_cpu_access; + return ret; } if (cmd > (char *)urb->transfer_buffer) { @@ -272,11 +266,7 @@ static int udl_handle_damage(struct drm_framebuffer *fb, udl_urb_completion(urb); } - ret = 0; - -out_drm_gem_fb_end_cpu_access: - drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE); - return ret; + return 0; } /* @@ -301,19 +291,29 @@ static void udl_primary_plane_helper_atomic_update(struct drm_plane *plane, struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); struct drm_framebuffer *fb = plane_state->fb; struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); - struct drm_rect rect; - int idx; - - if (!drm_dev_enter(dev, &idx)) - return; + struct drm_atomic_helper_damage_iter iter; + struct drm_rect damage; + int ret, idx; if (!fb) return; /* no framebuffer; plane is disabled */ - if (drm_atomic_helper_damage_merged(old_plane_state, plane_state, &rect)) - udl_handle_damage(fb, &shadow_plane_state->data[0], &rect); + ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE); + if (ret) + return; + + if (!drm_dev_enter(dev, &idx)) + goto out_drm_gem_fb_end_cpu_access; + + drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state); + drm_atomic_for_each_plane_damage(&iter, &damage) { + udl_handle_damage(fb, &shadow_plane_state->data[0], &damage); + } drm_dev_exit(idx); + +out_drm_gem_fb_end_cpu_access: + drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE); } static const struct drm_plane_helper_funcs udl_primary_plane_helper_funcs = { -- cgit From ff76e82c05a5d35994c2452ac4dcbd2bdd467204 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 6 Oct 2022 11:53:50 +0200 Subject: drm/udl: Move register constants to udl_proto.h Move the existing register constants to a new file in preparation of adding more of them. Renaming is intentional. No functional changes. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20221006095355.23579-12-tzimmermann@suse.de --- drivers/gpu/drm/udl/udl_drv.h | 9 --------- drivers/gpu/drm/udl/udl_modeset.c | 11 +++++------ drivers/gpu/drm/udl/udl_proto.h | 16 ++++++++++++++++ 3 files changed, 21 insertions(+), 15 deletions(-) create mode 100644 drivers/gpu/drm/udl/udl_proto.h diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h index b090b6cebdc4..580989087c54 100644 --- a/drivers/gpu/drm/udl/udl_drv.h +++ b/drivers/gpu/drm/udl/udl_drv.h @@ -112,13 +112,4 @@ int udl_select_std_channel(struct udl_device *udl); #define CMD_WRITE_COPY16 "\xAF\x6A" /**< 16 bit copy command. */ #define CMD_WRITE_RLX16 "\xAF\x6B" /**< 16 bit extended run length command. */ -/* On/Off for driving the DisplayLink framebuffer to the display */ -#define UDL_REG_BLANK_MODE 0x1f - -#define UDL_BLANK_MODE_ON 0x00 /* hsync and vsync on, visible */ -#define UDL_BLANK_MODE_BLANKED 0x01 /* hsync and vsync on, blanked */ -#define UDL_BLANK_MODE_VSYNC_OFF 0x03 /* vsync off, blanked */ -#define UDL_BLANK_MODE_HSYNC_OFF 0x05 /* hsync off, blanked */ -#define UDL_BLANK_MODE_POWERDOWN 0x07 /* powered off; requires modeset */ - #endif diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c index aee4fe2b5b08..702731bcd322 100644 --- a/drivers/gpu/drm/udl/udl_modeset.c +++ b/drivers/gpu/drm/udl/udl_modeset.c @@ -24,8 +24,7 @@ #include #include "udl_drv.h" - -#define UDL_COLOR_DEPTH_16BPP 0 +#include "udl_proto.h" /* * All DisplayLink bulk operations start with 0xAF, followed by specific code @@ -52,7 +51,7 @@ static char *udl_vidreg_unlock(char *buf) static char *udl_set_blank_mode(char *buf, u8 mode) { - return udl_set_register(buf, UDL_REG_BLANK_MODE, mode); + return udl_set_register(buf, UDL_REG_BLANKMODE, mode); } static char *udl_set_color_depth(char *buf, u8 selection) @@ -358,13 +357,13 @@ static void udl_crtc_helper_atomic_enable(struct drm_crtc *crtc, struct drm_atom buf = (char *)urb->transfer_buffer; buf = udl_vidreg_lock(buf); - buf = udl_set_color_depth(buf, UDL_COLOR_DEPTH_16BPP); + buf = udl_set_color_depth(buf, UDL_COLORDEPTH_16BPP); /* set base for 16bpp segment to 0 */ buf = udl_set_base16bpp(buf, 0); /* set base for 8bpp segment to end of fb */ buf = udl_set_base8bpp(buf, 2 * mode->vdisplay * mode->hdisplay); buf = udl_set_vid_cmds(buf, mode); - buf = udl_set_blank_mode(buf, UDL_BLANK_MODE_ON); + buf = udl_set_blank_mode(buf, UDL_BLANKMODE_ON); buf = udl_vidreg_unlock(buf); buf = udl_dummy_render(buf); @@ -390,7 +389,7 @@ static void udl_crtc_helper_atomic_disable(struct drm_crtc *crtc, struct drm_ato buf = (char *)urb->transfer_buffer; buf = udl_vidreg_lock(buf); - buf = udl_set_blank_mode(buf, UDL_BLANK_MODE_POWERDOWN); + buf = udl_set_blank_mode(buf, UDL_BLANKMODE_POWERDOWN); buf = udl_vidreg_unlock(buf); buf = udl_dummy_render(buf); diff --git a/drivers/gpu/drm/udl/udl_proto.h b/drivers/gpu/drm/udl/udl_proto.h new file mode 100644 index 000000000000..3f5b8e832b99 --- /dev/null +++ b/drivers/gpu/drm/udl/udl_proto.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef UDL_PROTO_H +#define UDL_PROTO_H + +#define UDL_COLORDEPTH_16BPP 0 + +/* On/Off for driving the DisplayLink framebuffer to the display */ +#define UDL_REG_BLANKMODE 0x1f +#define UDL_BLANKMODE_ON 0x00 /* hsync and vsync on, visible */ +#define UDL_BLANKMODE_BLANKED 0x01 /* hsync and vsync on, blanked */ +#define UDL_BLANKMODE_VSYNC_OFF 0x03 /* vsync off, blanked */ +#define UDL_BLANKMODE_HSYNC_OFF 0x05 /* hsync off, blanked */ +#define UDL_BLANKMODE_POWERDOWN 0x07 /* powered off; requires modeset */ + +#endif -- cgit From 9869e40df1a72eede80b4816d6e522e57a6fd97b Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 6 Oct 2022 11:53:51 +0200 Subject: drm/udl: Add constants for display-mode registers Add constants for the registers the contain various display-mode parameters and update the mode-setting function. No functional changes. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20221006095355.23579-13-tzimmermann@suse.de --- drivers/gpu/drm/udl/udl_modeset.c | 102 ++++++++++++-------------------------- drivers/gpu/drm/udl/udl_proto.h | 15 ++++++ 2 files changed, 47 insertions(+), 70 deletions(-) diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c index 702731bcd322..12385bcc71eb 100644 --- a/drivers/gpu/drm/udl/udl_modeset.c +++ b/drivers/gpu/drm/udl/udl_modeset.c @@ -126,78 +126,40 @@ static char *udl_set_register_lfsr16(char *wrptr, u8 reg, u16 value) } /* - * This takes a standard fbdev screeninfo struct and all of its monitor mode - * details and converts them into the DisplayLink equivalent register commands. - ERR(vreg(dev, 0x00, (color_depth == 16) ? 0 : 1)); - ERR(vreg_lfsr16(dev, 0x01, xDisplayStart)); - ERR(vreg_lfsr16(dev, 0x03, xDisplayEnd)); - ERR(vreg_lfsr16(dev, 0x05, yDisplayStart)); - ERR(vreg_lfsr16(dev, 0x07, yDisplayEnd)); - ERR(vreg_lfsr16(dev, 0x09, xEndCount)); - ERR(vreg_lfsr16(dev, 0x0B, hSyncStart)); - ERR(vreg_lfsr16(dev, 0x0D, hSyncEnd)); - ERR(vreg_big_endian(dev, 0x0F, hPixels)); - ERR(vreg_lfsr16(dev, 0x11, yEndCount)); - ERR(vreg_lfsr16(dev, 0x13, vSyncStart)); - ERR(vreg_lfsr16(dev, 0x15, vSyncEnd)); - ERR(vreg_big_endian(dev, 0x17, vPixels)); - ERR(vreg_little_endian(dev, 0x1B, pixelClock5KHz)); - - ERR(vreg(dev, 0x1F, 0)); - - ERR(vbuf(dev, WRITE_VIDREG_UNLOCK, DSIZEOF(WRITE_VIDREG_UNLOCK))); + * Takes a DRM display mode and converts it into the DisplayLink + * equivalent register commands. */ -static char *udl_set_vid_cmds(char *wrptr, struct drm_display_mode *mode) +static char *udl_set_display_mode(char *buf, struct drm_display_mode *mode) { - u16 xds, yds; - u16 xde, yde; - u16 yec; + u16 reg01 = mode->crtc_htotal - mode->crtc_hsync_start; + u16 reg03 = reg01 + mode->crtc_hdisplay; + u16 reg05 = mode->crtc_vtotal - mode->crtc_vsync_start; + u16 reg07 = reg05 + mode->crtc_vdisplay; + u16 reg09 = mode->crtc_htotal - 1; + u16 reg0b = 1; /* libdlo hardcodes hsync start to 1 */ + u16 reg0d = mode->crtc_hsync_end - mode->crtc_hsync_start + 1; + u16 reg0f = mode->hdisplay; + u16 reg11 = mode->crtc_vtotal; + u16 reg13 = 0; /* libdlo hardcodes vsync start to 0 */ + u16 reg15 = mode->crtc_vsync_end - mode->crtc_vsync_start; + u16 reg17 = mode->crtc_vdisplay; + u16 reg1b = mode->clock / 5; + + buf = udl_set_register_lfsr16(buf, UDL_REG_XDISPLAYSTART, reg01); + buf = udl_set_register_lfsr16(buf, UDL_REG_XDISPLAYEND, reg03); + buf = udl_set_register_lfsr16(buf, UDL_REG_YDISPLAYSTART, reg05); + buf = udl_set_register_lfsr16(buf, UDL_REG_YDISPLAYEND, reg07); + buf = udl_set_register_lfsr16(buf, UDL_REG_XENDCOUNT, reg09); + buf = udl_set_register_lfsr16(buf, UDL_REG_HSYNCSTART, reg0b); + buf = udl_set_register_lfsr16(buf, UDL_REG_HSYNCEND, reg0d); + buf = udl_set_register_16(buf, UDL_REG_HPIXELS, reg0f); + buf = udl_set_register_lfsr16(buf, UDL_REG_YENDCOUNT, reg11); + buf = udl_set_register_lfsr16(buf, UDL_REG_VSYNCSTART, reg13); + buf = udl_set_register_lfsr16(buf, UDL_REG_VSYNCEND, reg15); + buf = udl_set_register_16(buf, UDL_REG_VPIXELS, reg17); + buf = udl_set_register_16be(buf, UDL_REG_PIXELCLOCK5KHZ, reg1b); - /* x display start */ - xds = mode->crtc_htotal - mode->crtc_hsync_start; - wrptr = udl_set_register_lfsr16(wrptr, 0x01, xds); - /* x display end */ - xde = xds + mode->crtc_hdisplay; - wrptr = udl_set_register_lfsr16(wrptr, 0x03, xde); - - /* y display start */ - yds = mode->crtc_vtotal - mode->crtc_vsync_start; - wrptr = udl_set_register_lfsr16(wrptr, 0x05, yds); - /* y display end */ - yde = yds + mode->crtc_vdisplay; - wrptr = udl_set_register_lfsr16(wrptr, 0x07, yde); - - /* x end count is active + blanking - 1 */ - wrptr = udl_set_register_lfsr16(wrptr, 0x09, - mode->crtc_htotal - 1); - - /* libdlo hardcodes hsync start to 1 */ - wrptr = udl_set_register_lfsr16(wrptr, 0x0B, 1); - - /* hsync end is width of sync pulse + 1 */ - wrptr = udl_set_register_lfsr16(wrptr, 0x0D, - mode->crtc_hsync_end - mode->crtc_hsync_start + 1); - - /* hpixels is active pixels */ - wrptr = udl_set_register_16(wrptr, 0x0F, mode->hdisplay); - - /* yendcount is vertical active + vertical blanking */ - yec = mode->crtc_vtotal; - wrptr = udl_set_register_lfsr16(wrptr, 0x11, yec); - - /* libdlo hardcodes vsync start to 0 */ - wrptr = udl_set_register_lfsr16(wrptr, 0x13, 0); - - /* vsync end is width of vsync pulse */ - wrptr = udl_set_register_lfsr16(wrptr, 0x15, mode->crtc_vsync_end - mode->crtc_vsync_start); - - /* vpixels is active pixels */ - wrptr = udl_set_register_16(wrptr, 0x17, mode->crtc_vdisplay); - - wrptr = udl_set_register_16be(wrptr, 0x1B, - mode->clock / 5); - - return wrptr; + return buf; } static char *udl_dummy_render(char *wrptr) @@ -362,7 +324,7 @@ static void udl_crtc_helper_atomic_enable(struct drm_crtc *crtc, struct drm_atom buf = udl_set_base16bpp(buf, 0); /* set base for 8bpp segment to end of fb */ buf = udl_set_base8bpp(buf, 2 * mode->vdisplay * mode->hdisplay); - buf = udl_set_vid_cmds(buf, mode); + buf = udl_set_display_mode(buf, mode); buf = udl_set_blank_mode(buf, UDL_BLANKMODE_ON); buf = udl_vidreg_unlock(buf); buf = udl_dummy_render(buf); diff --git a/drivers/gpu/drm/udl/udl_proto.h b/drivers/gpu/drm/udl/udl_proto.h index 3f5b8e832b99..5a6c960bd10d 100644 --- a/drivers/gpu/drm/udl/udl_proto.h +++ b/drivers/gpu/drm/udl/udl_proto.h @@ -5,6 +5,21 @@ #define UDL_COLORDEPTH_16BPP 0 +/* Display-mode settings */ +#define UDL_REG_XDISPLAYSTART 0x01 +#define UDL_REG_XDISPLAYEND 0x03 +#define UDL_REG_YDISPLAYSTART 0x05 +#define UDL_REG_YDISPLAYEND 0x07 +#define UDL_REG_XENDCOUNT 0x09 +#define UDL_REG_HSYNCSTART 0x0b +#define UDL_REG_HSYNCEND 0x0d +#define UDL_REG_HPIXELS 0x0f +#define UDL_REG_YENDCOUNT 0x11 +#define UDL_REG_VSYNCSTART 0x13 +#define UDL_REG_VSYNCEND 0x15 +#define UDL_REG_VPIXELS 0x17 +#define UDL_REG_PIXELCLOCK5KHZ 0x1b + /* On/Off for driving the DisplayLink framebuffer to the display */ #define UDL_REG_BLANKMODE 0x1f #define UDL_BLANKMODE_ON 0x00 /* hsync and vsync on, visible */ -- cgit From ed24ed48be13fb8a866862f371614d546172cf6f Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 6 Oct 2022 11:53:52 +0200 Subject: drm/udl: Add register constants for color depth Add the register constants for setting the color depth. The driver only uses 16bpp. No functional changes. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20221006095355.23579-14-tzimmermann@suse.de --- drivers/gpu/drm/udl/udl_modeset.c | 2 +- drivers/gpu/drm/udl/udl_proto.h | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c index 12385bcc71eb..f8562d46b707 100644 --- a/drivers/gpu/drm/udl/udl_modeset.c +++ b/drivers/gpu/drm/udl/udl_modeset.c @@ -56,7 +56,7 @@ static char *udl_set_blank_mode(char *buf, u8 mode) static char *udl_set_color_depth(char *buf, u8 selection) { - return udl_set_register(buf, 0x00, selection); + return udl_set_register(buf, UDL_REG_COLORDEPTH, selection); } static char *udl_set_base16bpp(char *wrptr, u32 base) diff --git a/drivers/gpu/drm/udl/udl_proto.h b/drivers/gpu/drm/udl/udl_proto.h index 5a6c960bd10d..22bc1ae8420c 100644 --- a/drivers/gpu/drm/udl/udl_proto.h +++ b/drivers/gpu/drm/udl/udl_proto.h @@ -3,7 +3,10 @@ #ifndef UDL_PROTO_H #define UDL_PROTO_H +/* Color depth */ +#define UDL_REG_COLORDEPTH 0x00 #define UDL_COLORDEPTH_16BPP 0 +#define UDL_COLORDEPTH_24BPP 1 /* Display-mode settings */ #define UDL_REG_XDISPLAYSTART 0x01 -- cgit From cb7b995dcb20d1ab16f41498c65d8f395f095896 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 6 Oct 2022 11:53:53 +0200 Subject: drm/udl: Add register constants for video locks Add register constants for the video lock. No functional changes. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20221006095355.23579-15-tzimmermann@suse.de --- drivers/gpu/drm/udl/udl_modeset.c | 4 ++-- drivers/gpu/drm/udl/udl_proto.h | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c index f8562d46b707..ea0388ccbd7e 100644 --- a/drivers/gpu/drm/udl/udl_modeset.c +++ b/drivers/gpu/drm/udl/udl_modeset.c @@ -41,12 +41,12 @@ static char *udl_set_register(char *buf, u8 reg, u8 val) static char *udl_vidreg_lock(char *buf) { - return udl_set_register(buf, 0xFF, 0x00); + return udl_set_register(buf, UDL_REG_VIDREG, UDL_VIDREG_LOCK); } static char *udl_vidreg_unlock(char *buf) { - return udl_set_register(buf, 0xFF, 0xFF); + return udl_set_register(buf, UDL_REG_VIDREG, UDL_VIDREG_UNLOCK); } static char *udl_set_blank_mode(char *buf, u8 mode) diff --git a/drivers/gpu/drm/udl/udl_proto.h b/drivers/gpu/drm/udl/udl_proto.h index 22bc1ae8420c..8e7d1a090644 100644 --- a/drivers/gpu/drm/udl/udl_proto.h +++ b/drivers/gpu/drm/udl/udl_proto.h @@ -31,4 +31,9 @@ #define UDL_BLANKMODE_HSYNC_OFF 0x05 /* hsync off, blanked */ #define UDL_BLANKMODE_POWERDOWN 0x07 /* powered off; requires modeset */ +/* Lock/unlock video registers */ +#define UDL_REG_VIDREG 0xff +#define UDL_VIDREG_LOCK 0x00 +#define UDL_VIDREG_UNLOCK 0xff + #endif -- cgit From 44f29ad9a4d3131afbc616ad15e4bdf4586cf9a0 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 6 Oct 2022 11:53:54 +0200 Subject: drm/udl: Add register constants for framebuffer scanout addresses Add register constants for the framebuffer scanout addresses and update the related helper functions. No functional changes. v2: * extract address bytes with helper macros (Javier) * fix comments Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20221006095355.23579-16-tzimmermann@suse.de --- drivers/gpu/drm/udl/udl_modeset.c | 33 ++++++++++++++++++++++++--------- drivers/gpu/drm/udl/udl_proto.h | 14 ++++++++++++++ 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c index ea0388ccbd7e..4462653e6736 100644 --- a/drivers/gpu/drm/udl/udl_modeset.c +++ b/drivers/gpu/drm/udl/udl_modeset.c @@ -8,6 +8,8 @@ * Copyright (C) 2009 Bernie Thompson */ +#include + #include #include #include @@ -59,23 +61,36 @@ static char *udl_set_color_depth(char *buf, u8 selection) return udl_set_register(buf, UDL_REG_COLORDEPTH, selection); } -static char *udl_set_base16bpp(char *wrptr, u32 base) +static char *udl_set_base16bpp(char *buf, u32 base) { - /* the base pointer is 16 bits wide, 0x20 is hi byte. */ - wrptr = udl_set_register(wrptr, 0x20, base >> 16); - wrptr = udl_set_register(wrptr, 0x21, base >> 8); - return udl_set_register(wrptr, 0x22, base); + /* the base pointer is 24 bits wide, 0x20 is hi byte. */ + u8 reg20 = FIELD_GET(UDL_BASE_ADDR2_MASK, base); + u8 reg21 = FIELD_GET(UDL_BASE_ADDR1_MASK, base); + u8 reg22 = FIELD_GET(UDL_BASE_ADDR0_MASK, base); + + buf = udl_set_register(buf, UDL_REG_BASE16BPP_ADDR2, reg20); + buf = udl_set_register(buf, UDL_REG_BASE16BPP_ADDR1, reg21); + buf = udl_set_register(buf, UDL_REG_BASE16BPP_ADDR0, reg22); + + return buf; } /* * DisplayLink HW has separate 16bpp and 8bpp framebuffers. * In 24bpp modes, the low 323 RGB bits go in the 8bpp framebuffer */ -static char *udl_set_base8bpp(char *wrptr, u32 base) +static char *udl_set_base8bpp(char *buf, u32 base) { - wrptr = udl_set_register(wrptr, 0x26, base >> 16); - wrptr = udl_set_register(wrptr, 0x27, base >> 8); - return udl_set_register(wrptr, 0x28, base); + /* the base pointer is 24 bits wide, 0x26 is hi byte. */ + u8 reg26 = FIELD_GET(UDL_BASE_ADDR2_MASK, base); + u8 reg27 = FIELD_GET(UDL_BASE_ADDR1_MASK, base); + u8 reg28 = FIELD_GET(UDL_BASE_ADDR0_MASK, base); + + buf = udl_set_register(buf, UDL_REG_BASE8BPP_ADDR2, reg26); + buf = udl_set_register(buf, UDL_REG_BASE8BPP_ADDR1, reg27); + buf = udl_set_register(buf, UDL_REG_BASE8BPP_ADDR0, reg28); + + return buf; } static char *udl_set_register_16(char *wrptr, u8 reg, u16 value) diff --git a/drivers/gpu/drm/udl/udl_proto.h b/drivers/gpu/drm/udl/udl_proto.h index 8e7d1a090644..8f143e75e797 100644 --- a/drivers/gpu/drm/udl/udl_proto.h +++ b/drivers/gpu/drm/udl/udl_proto.h @@ -3,6 +3,8 @@ #ifndef UDL_PROTO_H #define UDL_PROTO_H +#include + /* Color depth */ #define UDL_REG_COLORDEPTH 0x00 #define UDL_COLORDEPTH_16BPP 0 @@ -31,6 +33,18 @@ #define UDL_BLANKMODE_HSYNC_OFF 0x05 /* hsync off, blanked */ #define UDL_BLANKMODE_POWERDOWN 0x07 /* powered off; requires modeset */ +/* Framebuffer address */ +#define UDL_REG_BASE16BPP_ADDR2 0x20 +#define UDL_REG_BASE16BPP_ADDR1 0x21 +#define UDL_REG_BASE16BPP_ADDR0 0x22 +#define UDL_REG_BASE8BPP_ADDR2 0x26 +#define UDL_REG_BASE8BPP_ADDR1 0x27 +#define UDL_REG_BASE8BPP_ADDR0 0x28 + +#define UDL_BASE_ADDR0_MASK GENMASK(7, 0) +#define UDL_BASE_ADDR1_MASK GENMASK(15, 8) +#define UDL_BASE_ADDR2_MASK GENMASK(23, 16) + /* Lock/unlock video registers */ #define UDL_REG_VIDREG 0xff #define UDL_VIDREG_LOCK 0x00 -- cgit From 1b8db07f233a2acc0053a18960a742f354b78436 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 6 Oct 2022 11:53:55 +0200 Subject: drm/udl: Add constants for commands Add constants for the various commands that the driver can send to the device and update the respective helper functions. No functional changes. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20221006095355.23579-17-tzimmermann@suse.de --- drivers/gpu/drm/udl/udl_drv.h | 10 ---------- drivers/gpu/drm/udl/udl_modeset.c | 16 +++++++++------- drivers/gpu/drm/udl/udl_proto.h | 15 +++++++++++++++ drivers/gpu/drm/udl/udl_transfer.c | 7 ++++--- 4 files changed, 28 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h index 580989087c54..282ebd6c02fd 100644 --- a/drivers/gpu/drm/udl/udl_drv.h +++ b/drivers/gpu/drm/udl/udl_drv.h @@ -102,14 +102,4 @@ int udl_render_hline(struct drm_device *dev, int log_bpp, struct urb **urb_ptr, int udl_drop_usb(struct drm_device *dev); int udl_select_std_channel(struct udl_device *udl); -#define CMD_WRITE_RAW8 "\xAF\x60" /**< 8 bit raw write command. */ -#define CMD_WRITE_RL8 "\xAF\x61" /**< 8 bit run length command. */ -#define CMD_WRITE_COPY8 "\xAF\x62" /**< 8 bit copy command. */ -#define CMD_WRITE_RLX8 "\xAF\x63" /**< 8 bit extended run length command. */ - -#define CMD_WRITE_RAW16 "\xAF\x68" /**< 16 bit raw write command. */ -#define CMD_WRITE_RL16 "\xAF\x69" /**< 16 bit run length command. */ -#define CMD_WRITE_COPY16 "\xAF\x6A" /**< 16 bit copy command. */ -#define CMD_WRITE_RLX16 "\xAF\x6B" /**< 16 bit extended run length command. */ - #endif diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c index 4462653e6736..3a25f3fc2b22 100644 --- a/drivers/gpu/drm/udl/udl_modeset.c +++ b/drivers/gpu/drm/udl/udl_modeset.c @@ -29,15 +29,17 @@ #include "udl_proto.h" /* - * All DisplayLink bulk operations start with 0xAF, followed by specific code - * All operations are written to buffers which then later get sent to device + * All DisplayLink bulk operations start with 0xaf (UDL_MSG_BULK), followed by + * a specific command code. All operations are written to a command buffer, which + * the driver sends to the device. */ static char *udl_set_register(char *buf, u8 reg, u8 val) { - *buf++ = 0xAF; - *buf++ = 0x20; + *buf++ = UDL_MSG_BULK; + *buf++ = UDL_CMD_WRITEREG; *buf++ = reg; *buf++ = val; + return buf; } @@ -179,8 +181,8 @@ static char *udl_set_display_mode(char *buf, struct drm_display_mode *mode) static char *udl_dummy_render(char *wrptr) { - *wrptr++ = 0xAF; - *wrptr++ = 0x6A; /* copy */ + *wrptr++ = UDL_MSG_BULK; + *wrptr++ = UDL_CMD_WRITECOPY16; *wrptr++ = 0x00; /* from addr */ *wrptr++ = 0x00; *wrptr++ = 0x00; @@ -235,7 +237,7 @@ static int udl_handle_damage(struct drm_framebuffer *fb, /* Send partial buffer remaining before exiting */ int len; if (cmd < (char *)urb->transfer_buffer + urb->transfer_buffer_length) - *cmd++ = 0xAF; + *cmd++ = UDL_MSG_BULK; len = cmd - (char *)urb->transfer_buffer; ret = udl_submit_urb(dev, urb, len); } else { diff --git a/drivers/gpu/drm/udl/udl_proto.h b/drivers/gpu/drm/udl/udl_proto.h index 8f143e75e797..c92d2109584c 100644 --- a/drivers/gpu/drm/udl/udl_proto.h +++ b/drivers/gpu/drm/udl/udl_proto.h @@ -5,6 +5,21 @@ #include +#define UDL_MSG_BULK 0xaf + +/* Register access */ +#define UDL_CMD_WRITEREG 0x20 /* See register constants below */ + +/* Framebuffer access */ +#define UDL_CMD_WRITERAW8 0x60 /* 8 bit raw write command. */ +#define UDL_CMD_WRITERL8 0x61 /* 8 bit run length command. */ +#define UDL_CMD_WRITECOPY8 0x62 /* 8 bit copy command. */ +#define UDL_CMD_WRITERLX8 0x63 /* 8 bit extended run length command. */ +#define UDL_CMD_WRITERAW16 0x68 /* 16 bit raw write command. */ +#define UDL_CMD_WRITERL16 0x69 /* 16 bit run length command. */ +#define UDL_CMD_WRITECOPY16 0x6a /* 16 bit copy command. */ +#define UDL_CMD_WRITERLX16 0x6b /* 16 bit extended run length command. */ + /* Color depth */ #define UDL_REG_COLORDEPTH 0x00 #define UDL_COLORDEPTH_16BPP 0 diff --git a/drivers/gpu/drm/udl/udl_transfer.c b/drivers/gpu/drm/udl/udl_transfer.c index b57844632dbd..5ff1037a3453 100644 --- a/drivers/gpu/drm/udl/udl_transfer.c +++ b/drivers/gpu/drm/udl/udl_transfer.c @@ -10,6 +10,7 @@ #include #include "udl_drv.h" +#include "udl_proto.h" #define MAX_CMD_PIXELS 255 @@ -89,8 +90,8 @@ static void udl_compress_hline16( const u8 *cmd_pixel_start, *cmd_pixel_end = NULL; uint16_t pixel_val16; - *cmd++ = 0xaf; - *cmd++ = 0x6b; + *cmd++ = UDL_MSG_BULK; + *cmd++ = UDL_CMD_WRITERLX16; *cmd++ = (uint8_t) ((dev_addr >> 16) & 0xFF); *cmd++ = (uint8_t) ((dev_addr >> 8) & 0xFF); *cmd++ = (uint8_t) ((dev_addr) & 0xFF); @@ -152,7 +153,7 @@ static void udl_compress_hline16( if (cmd_buffer_end <= MIN_RLX_CMD_BYTES + cmd) { /* Fill leftover bytes with no-ops */ if (cmd_buffer_end > cmd) - memset(cmd, 0xAF, cmd_buffer_end - cmd); + memset(cmd, UDL_MSG_BULK, cmd_buffer_end - cmd); cmd = (uint8_t *) cmd_buffer_end; } -- cgit From a2b1d9ecaa755c4795a84a046b075bbf351cd6af Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 4 Oct 2022 18:09:29 +0300 Subject: drm/i915: Clean up some namespacing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename a few functions from intel_crtc_foo_init() to intel_foo_crtc_init() so that the namespaec clearly indicates what feature/file we're talking about. I left out intel_crtc_crc_init() because the whole crc stuff uses intel_crtc_ as its namespace currently. Suggested-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221004150929.23910-1-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_color.c | 2 +- drivers/gpu/drm/i915/display/intel_color.h | 2 +- drivers/gpu/drm/i915/display/intel_crtc.c | 4 ++-- drivers/gpu/drm/i915/display/intel_drrs.c | 4 ++-- drivers/gpu/drm/i915/display/intel_drrs.h | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index 0c73b2ba1283..fc23d5d8f7fd 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -2209,7 +2209,7 @@ static const struct intel_color_funcs ilk_color_funcs = { .read_luts = ilk_read_luts, }; -void intel_crtc_color_init(struct intel_crtc *crtc) +void intel_color_crtc_init(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); bool has_ctm = INTEL_INFO(dev_priv)->display.color.degamma_lut_size != 0; diff --git a/drivers/gpu/drm/i915/display/intel_color.h b/drivers/gpu/drm/i915/display/intel_color.h index 67702451e2fd..04984e6000b6 100644 --- a/drivers/gpu/drm/i915/display/intel_color.h +++ b/drivers/gpu/drm/i915/display/intel_color.h @@ -14,7 +14,7 @@ struct drm_i915_private; struct drm_property_blob; void intel_color_init_hooks(struct drm_i915_private *i915); -void intel_crtc_color_init(struct intel_crtc *crtc); +void intel_color_crtc_init(struct intel_crtc *crtc); int intel_color_check(struct intel_crtc_state *crtc_state); void intel_color_commit_noarm(const struct intel_crtc_state *crtc_state); void intel_color_commit_arm(const struct intel_crtc_state *crtc_state); diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c index 2d9fc7383bfc..6be1fe34c83b 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc.c +++ b/drivers/gpu/drm/i915/display/intel_crtc.c @@ -365,8 +365,8 @@ int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe) BIT(DRM_SCALING_FILTER_DEFAULT) | BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR)); - intel_crtc_color_init(crtc); - intel_crtc_drrs_init(crtc); + intel_color_crtc_init(crtc); + intel_drrs_crtc_init(crtc); intel_crtc_crc_init(crtc); cpu_latency_qos_add_request(&crtc->vblank_pm_qos, PM_QOS_DEFAULT_VALUE); diff --git a/drivers/gpu/drm/i915/display/intel_drrs.c b/drivers/gpu/drm/i915/display/intel_drrs.c index 2b94a62ef65a..e27408efaae2 100644 --- a/drivers/gpu/drm/i915/display/intel_drrs.c +++ b/drivers/gpu/drm/i915/display/intel_drrs.c @@ -284,14 +284,14 @@ void intel_drrs_flush(struct drm_i915_private *dev_priv, } /** - * intel_crtc_drrs_init - Init DRRS for CRTC + * intel_drrs_crtc_init - Init DRRS for CRTC * @crtc: crtc * * This function is called only once at driver load to initialize basic * DRRS stuff. * */ -void intel_crtc_drrs_init(struct intel_crtc *crtc) +void intel_drrs_crtc_init(struct intel_crtc *crtc) { INIT_DELAYED_WORK(&crtc->drrs.work, intel_drrs_downclock_work); mutex_init(&crtc->drrs.mutex); diff --git a/drivers/gpu/drm/i915/display/intel_drrs.h b/drivers/gpu/drm/i915/display/intel_drrs.h index 041248bf5d67..8ef5f93a80ff 100644 --- a/drivers/gpu/drm/i915/display/intel_drrs.h +++ b/drivers/gpu/drm/i915/display/intel_drrs.h @@ -23,7 +23,7 @@ void intel_drrs_invalidate(struct drm_i915_private *dev_priv, unsigned int frontbuffer_bits); void intel_drrs_flush(struct drm_i915_private *dev_priv, unsigned int frontbuffer_bits); -void intel_crtc_drrs_init(struct intel_crtc *crtc); +void intel_drrs_crtc_init(struct intel_crtc *crtc); void intel_drrs_crtc_debugfs_add(struct intel_crtc *crtc); void intel_drrs_connector_debugfs_add(struct intel_connector *connector); -- cgit From 8c45f31c320d0a49e5cd8621db07e4b3701c52a7 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 22 Jun 2022 18:54:49 +0300 Subject: drm/i915: Fix g4x/vlv/chv CxSR vs. format/tiling/rotation changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On g4x/vlv/chv the hardware seems incapable of changing the pixel format, rotation, or YUV->RGB CSC matrix while in CxSR. Additionally on VLV/CHV the sprites seem incapable of tiling changes while in CxSR. On g4x CxSR is not even possible with the sprite enabled. Curiously the primary plane seems perfectly happy when changing tiling during CxSR. Pimp up the code to account for these when determining whether CxSR needs to be disabled. Since it looks like most of the plane control register bits are affected let's just compare that. But in the name of efficiency we'll make an exception for the primary plane tiling changes (avoids some extra vblank waits). v2: Just use the pre-computed plane control register values Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220622155452.32587-7-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy --- drivers/gpu/drm/i915/display/intel_atomic_plane.c | 53 +++++++++++++++++++---- 1 file changed, 45 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_atomic_plane.c b/drivers/gpu/drm/i915/display/intel_atomic_plane.c index ecb8d71d36c0..bcf0239b9533 100644 --- a/drivers/gpu/drm/i915/display/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/display/intel_atomic_plane.c @@ -425,6 +425,47 @@ static bool intel_plane_do_async_flip(struct intel_plane *plane, return DISPLAY_VER(i915) < 13 || old_crtc_state->uapi.async_flip; } +static bool i9xx_must_disable_cxsr(const struct intel_crtc_state *new_crtc_state, + const struct intel_plane_state *old_plane_state, + const struct intel_plane_state *new_plane_state) +{ + struct intel_plane *plane = to_intel_plane(new_plane_state->uapi.plane); + bool old_visible = old_plane_state->uapi.visible; + bool new_visible = new_plane_state->uapi.visible; + u32 old_ctl = old_plane_state->ctl; + u32 new_ctl = new_plane_state->ctl; + bool modeset, turn_on, turn_off; + + if (plane->id == PLANE_CURSOR) + return false; + + modeset = intel_crtc_needs_modeset(new_crtc_state); + turn_off = old_visible && (!new_visible || modeset); + turn_on = new_visible && (!old_visible || modeset); + + /* Must disable CxSR around plane enable/disable */ + if (turn_on || turn_off) + return true; + + if (!old_visible || !new_visible) + return false; + + /* + * Most plane control register updates are blocked while in CxSR. + * + * Tiling mode is one exception where the primary plane can + * apparently handle it, whereas the sprites can not (the + * sprite issue being only relevant on VLV/CHV where CxSR + * is actually possible with a sprite enabled). + */ + if (plane->id == PLANE_PRIMARY) { + old_ctl &= ~DISP_TILED; + new_ctl &= ~DISP_TILED; + } + + return old_ctl != new_ctl; +} + static int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_state, struct intel_crtc_state *new_crtc_state, const struct intel_plane_state *old_plane_state, @@ -482,17 +523,9 @@ static int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_cr if (turn_on) { if (DISPLAY_VER(dev_priv) < 5 && !IS_G4X(dev_priv)) new_crtc_state->update_wm_pre = true; - - /* must disable cxsr around plane enable/disable */ - if (plane->id != PLANE_CURSOR) - new_crtc_state->disable_cxsr = true; } else if (turn_off) { if (DISPLAY_VER(dev_priv) < 5 && !IS_G4X(dev_priv)) new_crtc_state->update_wm_post = true; - - /* must disable cxsr around plane enable/disable */ - if (plane->id != PLANE_CURSOR) - new_crtc_state->disable_cxsr = true; } else if (intel_wm_need_update(old_plane_state, new_plane_state)) { if (DISPLAY_VER(dev_priv) < 5 && !IS_G4X(dev_priv)) { /* FIXME bollocks */ @@ -504,6 +537,10 @@ static int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_cr if (visible || was_visible) new_crtc_state->fb_bits |= plane->frontbuffer_bit; + if (HAS_GMCH(dev_priv) && + i9xx_must_disable_cxsr(new_crtc_state, old_plane_state, new_plane_state)) + new_crtc_state->disable_cxsr = true; + /* * ILK/SNB DVSACNTR/Sprite Enable * IVB SPR_CTL/Sprite Enable -- cgit From eadbd867177e1d72b2ff71b7ba0dffcae4dabc64 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 22 Jun 2022 18:54:50 +0300 Subject: drm/i915: Fix pipe gamma enable/disable vs. CxSR on gmch platforms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Like most other plane control register bits, the pipe gamma enable bit is also blocked by CxSR. So make sure we kick the machine out of CxSR before trying to change that bit. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220622155452.32587-8-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy --- drivers/gpu/drm/i915/display/intel_color.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index fc23d5d8f7fd..123c57ceeb73 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -1287,6 +1287,10 @@ intel_color_add_affected_planes(struct intel_crtc_state *new_crtc_state) return PTR_ERR(plane_state); new_crtc_state->update_planes |= BIT(plane->id); + + /* plane control register changes blocked by CxSR */ + if (HAS_GMCH(dev_priv)) + new_crtc_state->disable_cxsr = true; } return 0; -- cgit From 599cc77efae7e4dc5700be2f422dac331e7b4d06 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 22 Jun 2022 18:54:51 +0300 Subject: drm/i915: Write watermarks for disabled pipes on gmch platforms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We've excluded gmch platforms from writing the final watermarks for any disabled pipe. IIRC the reason was perhaps some lingering issue with the watermark merging across the pipes. But I can't really see any reason for this anymore, so let's unify this behaviour. The main benefit being more consistency in register dumps when we don't have stale watermarks hanging around in the registers. Functionally there should be no difference as the hardware just ignore all of it when the pipe is disabled. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220622155452.32587-9-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy --- drivers/gpu/drm/i915/display/intel_display.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 237262a0bab4..ff8ca79432a2 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -7166,9 +7166,7 @@ static void intel_old_crtc_state_disables(struct intel_atomic_state *state, intel_fbc_disable(crtc); intel_disable_shared_dpll(old_crtc_state); - /* FIXME unify this for all platforms */ - if (!new_crtc_state->hw.active && - !HAS_GMCH(dev_priv)) + if (!new_crtc_state->hw.active) intel_initial_watermarks(state, crtc); } -- cgit From dbbf933d365da1a76a540211bee3d57bde520194 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 7 Oct 2022 14:43:37 +0200 Subject: drm/atomic-helper: Don't allocate new plane state in CRTC check In drm_atomic_helper_check_crtc_state(), do not add a new plane state to the global state if it does not exist already. Adding a new plane state will result in overhead for the plane during the atomic-commit step. For the test in drm_atomic_helper_check_crtc_state() to succeed, it is important that the CRTC has an enabled primary plane after the commit. Simply testing the CRTC state's plane_mask for a primary plane is sufficient. Note that the helper still only tests for an attached primary plane. Drivers have to ensure that the plane contains valid pixel information. v5: * fix commit description (Javier) v3: * test for a primary plane in plane_mask (Ville) v2: * remove unnecessary test for plane->crtc (Ville) * inline drm_atomic_get_next_plane_state() (Ville) * acquire plane lock before accessing plane->state (Ville) Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Fixes: d6b9af1097fe ("drm/atomic-helper: Add helper drm_atomic_helper_check_crtc_state()") Cc: Thomas Zimmermann Cc: Jocelyn Falempe Cc: Maarten Lankhorst Cc: Maxime Ripard Cc: David Airlie Cc: Daniel Vetter Cc: dri-devel@lists.freedesktop.org Link: https://patchwork.freedesktop.org/patch/msgid/20221007124338.24152-2-tzimmermann@suse.de --- drivers/gpu/drm/drm_atomic_helper.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 98cc3137c062..02b4a7dc92f5 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -945,7 +945,6 @@ int drm_atomic_helper_check_crtc_state(struct drm_crtc_state *crtc_state, bool can_disable_primary_planes) { struct drm_device *dev = crtc_state->crtc->dev; - struct drm_atomic_state *state = crtc_state->state; if (!crtc_state->enable) return 0; @@ -956,14 +955,7 @@ int drm_atomic_helper_check_crtc_state(struct drm_crtc_state *crtc_state, struct drm_plane *plane; drm_for_each_plane_mask(plane, dev, crtc_state->plane_mask) { - struct drm_plane_state *plane_state; - - if (plane->type != DRM_PLANE_TYPE_PRIMARY) - continue; - plane_state = drm_atomic_get_plane_state(state, plane); - if (IS_ERR(plane_state)) - return PTR_ERR(plane_state); - if (plane_state->fb && plane_state->crtc) { + if (plane->type == DRM_PLANE_TYPE_PRIMARY) { has_primary_plane = true; break; } -- cgit From 8f2fd57d834d83fb4f5e0f39a3415bcbe4c1d3b6 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 7 Oct 2022 14:43:38 +0200 Subject: drm/atomic-helper: Replace drm_atomic_helper_check_crtc_state() Rename the atomic helper function drm_atomic_helper_check_crtc_state() to drm_atomic_helper_check_crtc_primary_plane() and only check for an attached primary plane. Adapt callers. Instead of having one big function to check for various CRTC state conditions, we rather want smaller functions that drivers can pick individually. v5: * rebase on top of udl changes Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20221007124338.24152-3-tzimmermann@suse.de --- drivers/gpu/drm/ast/ast_mode.c | 8 ++--- drivers/gpu/drm/drm_atomic_helper.c | 52 ++++++++++++--------------------- drivers/gpu/drm/drm_simple_kms_helper.c | 6 +++- drivers/gpu/drm/mgag200/mgag200_mode.c | 8 ++--- drivers/gpu/drm/solomon/ssd130x.c | 6 +++- drivers/gpu/drm/tiny/simpledrm.c | 6 +++- drivers/gpu/drm/udl/udl_modeset.c | 5 +++- include/drm/drm_atomic_helper.h | 3 +- 8 files changed, 46 insertions(+), 48 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index 8ff998da71ef..d5ee3ad538a8 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -1161,13 +1161,13 @@ static int ast_crtc_helper_atomic_check(struct drm_crtc *crtc, bool succ; int ret; - ret = drm_atomic_helper_check_crtc_state(crtc_state, false); - if (ret) - return ret; - if (!crtc_state->enable) goto out; + ret = drm_atomic_helper_check_crtc_primary_plane(crtc_state); + if (ret) + return ret; + ast_state = to_ast_crtc_state(crtc_state); format = ast_state->format; diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 02b4a7dc92f5..1a586b3c454b 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -924,51 +924,35 @@ int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state, EXPORT_SYMBOL(drm_atomic_helper_check_plane_state); /** - * drm_atomic_helper_check_crtc_state() - Check CRTC state for validity + * drm_atomic_helper_check_crtc_primary_plane() - Check CRTC state for primary plane * @crtc_state: CRTC state to check - * @can_disable_primary_planes: can the CRTC be enabled without a primary plane? * - * Checks that a desired CRTC update is valid. Drivers that provide - * their own CRTC handling rather than helper-provided implementations may - * still wish to call this function to avoid duplication of error checking - * code. - * - * Note that @can_disable_primary_planes only tests if the CRTC can be - * enabled without a primary plane. To test if a primary plane can be updated - * without a CRTC, use drm_atomic_helper_check_plane_state() in the plane's - * atomic check. + * Checks that a CRTC has at least one primary plane attached to it, which is + * a requirement on some hardware. Note that this only involves the CRTC side + * of the test. To test if the primary plane is visible or if it can be updated + * without the CRTC being enabled, use drm_atomic_helper_check_plane_state() in + * the plane's atomic check. * * RETURNS: - * Zero if update appears valid, error code on failure + * 0 if a primary plane is attached to the CRTC, or an error code otherwise */ -int drm_atomic_helper_check_crtc_state(struct drm_crtc_state *crtc_state, - bool can_disable_primary_planes) +int drm_atomic_helper_check_crtc_primary_plane(struct drm_crtc_state *crtc_state) { - struct drm_device *dev = crtc_state->crtc->dev; - - if (!crtc_state->enable) - return 0; + struct drm_crtc *crtc = crtc_state->crtc; + struct drm_device *dev = crtc->dev; + struct drm_plane *plane; /* needs at least one primary plane to be enabled */ - if (!can_disable_primary_planes) { - bool has_primary_plane = false; - struct drm_plane *plane; - - drm_for_each_plane_mask(plane, dev, crtc_state->plane_mask) { - if (plane->type == DRM_PLANE_TYPE_PRIMARY) { - has_primary_plane = true; - break; - } - } - if (!has_primary_plane) { - drm_dbg_kms(dev, "Cannot enable CRTC without a primary plane.\n"); - return -EINVAL; - } + drm_for_each_plane_mask(plane, dev, crtc_state->plane_mask) { + if (plane->type == DRM_PLANE_TYPE_PRIMARY) + return 0; } - return 0; + drm_dbg_atomic(dev, "[CRTC:%d:%s] primary plane missing\n", crtc->base.id, crtc->name); + + return -EINVAL; } -EXPORT_SYMBOL(drm_atomic_helper_check_crtc_state); +EXPORT_SYMBOL(drm_atomic_helper_check_crtc_primary_plane); /** * drm_atomic_helper_check_planes - validate state object for planes changes diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c index e9f782119d3d..31233c6ae3c4 100644 --- a/drivers/gpu/drm/drm_simple_kms_helper.c +++ b/drivers/gpu/drm/drm_simple_kms_helper.c @@ -102,10 +102,14 @@ static int drm_simple_kms_crtc_check(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); int ret; - ret = drm_atomic_helper_check_crtc_state(crtc_state, false); + if (!crtc_state->enable) + goto out; + + ret = drm_atomic_helper_check_crtc_primary_plane(crtc_state); if (ret) return ret; +out: return drm_atomic_add_affected_planes(state, crtc); } diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index bbab2549243a..5f7eb642f0c6 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -579,13 +579,13 @@ int mgag200_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_st struct drm_property_blob *new_gamma_lut = new_crtc_state->gamma_lut; int ret; - ret = drm_atomic_helper_check_crtc_state(new_crtc_state, false); - if (ret) - return ret; - if (!new_crtc_state->enable) return 0; + ret = drm_atomic_helper_check_crtc_primary_plane(new_crtc_state); + if (ret) + return ret; + if (new_crtc_state->mode_changed) { if (funcs->pixpllc_atomic_check) { ret = funcs->pixpllc_atomic_check(crtc, new_state); diff --git a/drivers/gpu/drm/solomon/ssd130x.c b/drivers/gpu/drm/solomon/ssd130x.c index f456b233d2e7..57e48355c008 100644 --- a/drivers/gpu/drm/solomon/ssd130x.c +++ b/drivers/gpu/drm/solomon/ssd130x.c @@ -651,10 +651,14 @@ static int ssd130x_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc); int ret; - ret = drm_atomic_helper_check_crtc_state(new_crtc_state, false); + if (!new_crtc_state->enable) + goto out; + + ret = drm_atomic_helper_check_crtc_primary_plane(new_crtc_state); if (ret) return ret; +out: return drm_atomic_add_affected_planes(new_state, crtc); } diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c index 18489779fb8a..ecd49a8f3334 100644 --- a/drivers/gpu/drm/tiny/simpledrm.c +++ b/drivers/gpu/drm/tiny/simpledrm.c @@ -551,10 +551,14 @@ static int simpledrm_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc); int ret; - ret = drm_atomic_helper_check_crtc_state(new_crtc_state, false); + if (!new_crtc_state->enable) + goto out; + + ret = drm_atomic_helper_check_crtc_primary_plane(new_crtc_state); if (ret) return ret; +out: return drm_atomic_add_affected_planes(new_state, crtc); } diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c index 3a25f3fc2b22..4b79d44752c9 100644 --- a/drivers/gpu/drm/udl/udl_modeset.c +++ b/drivers/gpu/drm/udl/udl_modeset.c @@ -315,7 +315,10 @@ static int udl_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic { struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); - return drm_atomic_helper_check_crtc_state(new_crtc_state, false); + if (!new_crtc_state->enable) + return 0; + + return drm_atomic_helper_check_crtc_primary_plane(new_crtc_state); } static void udl_crtc_helper_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state) diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index 06d8902a8097..33f982cd1a27 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -58,10 +58,9 @@ int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state, int max_scale, bool can_position, bool can_update_disabled); -int drm_atomic_helper_check_crtc_state(struct drm_crtc_state *crtc_state, - bool can_disable_primary_plane); int drm_atomic_helper_check_planes(struct drm_device *dev, struct drm_atomic_state *state); +int drm_atomic_helper_check_crtc_primary_plane(struct drm_crtc_state *crtc_state); int drm_atomic_helper_check(struct drm_device *dev, struct drm_atomic_state *state); void drm_atomic_helper_commit_tail(struct drm_atomic_state *state); -- cgit From 178ce94a15c970b66663e097d694bae6679e9a69 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 7 Oct 2022 20:47:45 +0100 Subject: drm/i915/gem: remove redundant assignments to variable ret The variable ret is being assigned with a value that is never read both before and after a while-loop. The variable is being re-assigned inside the while-loop and afterwards on the call to the function i915_gem_object_lock_interruptible. Remove the redundants assignments. Cleans up clang scan-build warnings: warning: Although the value stored to 'ret' is used in the enclosing expression, the value is never actually read from 'ret' [deadcode.DeadStores] warning: Value stored to 'ret' is never read [deadcode.DeadStores] Signed-off-by: Colin Ian King Reviewed-by: Tvrtko Ursulin Signed-off-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20221007194745.2749277-1-colin.i.king@gmail.com --- drivers/gpu/drm/i915/gem/i915_gem_userptr.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_userptr.c b/drivers/gpu/drm/i915/gem/i915_gem_userptr.c index 8423df021b71..1c60818ed2f1 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_userptr.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_userptr.c @@ -292,7 +292,7 @@ int i915_gem_object_userptr_submit_init(struct drm_i915_gem_object *obj) if (!i915_gem_object_is_readonly(obj)) gup_flags |= FOLL_WRITE; - pinned = ret = 0; + pinned = 0; while (pinned < num_pages) { ret = pin_user_pages_fast(obj->userptr.ptr + pinned * PAGE_SIZE, num_pages - pinned, gup_flags, @@ -302,7 +302,6 @@ int i915_gem_object_userptr_submit_init(struct drm_i915_gem_object *obj) pinned += ret; } - ret = 0; ret = i915_gem_object_lock_interruptible(obj, NULL); if (ret) -- cgit From f1d8e2bf877d3d322aa7149c43bbc99466014eed Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 7 Oct 2022 20:53:45 +0100 Subject: drm/i915/perf: remove redundant variable 'taken' The assignment to variable taken is redundant and so it can be removed as well as the variable too. Cleans up clang-scan build warnings: warning: Although the value stored to 'taken' is used in the enclosing expression, the value is never actually read from 'taken' [deadcode.DeadStores] Signed-off-by: Colin Ian King Reviewed-by: Tvrtko Ursulin Signed-off-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20221007195345.2749911-1-colin.i.king@gmail.com --- drivers/gpu/drm/i915/i915_perf.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index 0defbb43ceea..15816df916c7 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -656,7 +656,6 @@ static int gen8_append_oa_reports(struct i915_perf_stream *stream, size_t start_offset = *offset; unsigned long flags; u32 head, tail; - u32 taken; int ret = 0; if (drm_WARN_ON(&uncore->i915->drm, !stream->enabled)) @@ -692,7 +691,7 @@ static int gen8_append_oa_reports(struct i915_perf_stream *stream, for (/* none */; - (taken = OA_TAKEN(tail, head)); + OA_TAKEN(tail, head); head = (head + report_size) & mask) { u8 *report = oa_buf_base + head; u32 *report32 = (void *)report; @@ -950,7 +949,6 @@ static int gen7_append_oa_reports(struct i915_perf_stream *stream, size_t start_offset = *offset; unsigned long flags; u32 head, tail; - u32 taken; int ret = 0; if (drm_WARN_ON(&uncore->i915->drm, !stream->enabled)) @@ -984,7 +982,7 @@ static int gen7_append_oa_reports(struct i915_perf_stream *stream, for (/* none */; - (taken = OA_TAKEN(tail, head)); + OA_TAKEN(tail, head); head = (head + report_size) & mask) { u8 *report = oa_buf_base + head; u32 *report32 = (void *)report; -- cgit From 542bbaa736026c99237d6d93e4fff46762a55ff7 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 29 Sep 2022 18:30:56 +0200 Subject: drm/tests: Order Kunit tests in Makefile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since we've recently added a ton of tests, the list starts to be a bit of a mess and creates unneeded conflicts. Let's order it alphabetically. Acked-by: Thomas Zimmermann Reviewed-by: Noralf Trønnes Link: https://lore.kernel.org/r/20220728-rpi-analog-tv-properties-v4-2-60d38873f782@cerno.tech Signed-off-by: Maxime Ripard --- drivers/gpu/drm/tests/Makefile | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/tests/Makefile b/drivers/gpu/drm/tests/Makefile index 91b70f7d2769..2d9f49b62ecb 100644 --- a/drivers/gpu/drm/tests/Makefile +++ b/drivers/gpu/drm/tests/Makefile @@ -1,5 +1,13 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_DRM_KUNIT_TEST) += drm_format_helper_test.o drm_damage_helper_test.o \ - drm_cmdline_parser_test.o drm_rect_test.o drm_format_test.o drm_plane_helper_test.o \ - drm_dp_mst_helper_test.o drm_framebuffer_test.o drm_buddy_test.o drm_mm_test.o +obj-$(CONFIG_DRM_KUNIT_TEST) += \ + drm_buddy_test.o \ + drm_cmdline_parser_test.o \ + drm_damage_helper_test.o \ + drm_dp_mst_helper_test.o \ + drm_format_helper_test.o \ + drm_format_test.o \ + drm_framebuffer_test.o \ + drm_mm_test.o \ + drm_plane_helper_test.o \ + drm_rect_test.o -- cgit From 05e70e32f712e9fdf8a351caf97ba60fa8b71b44 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 29 Sep 2022 18:30:58 +0200 Subject: drm/atomic-helper: Rename drm_atomic_helper_connector_tv_reset to avoid ambiguity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We currently have two sets of TV properties. The first one is there to deal with analog TV properties, creating properties such as the TV mode, subconnectors, saturation, hue and so on. It's created by calling the drm_mode_create_tv_properties() function. The second one is there to deal with properties that might be useful on a TV, creating the overscan margins for example. It's created by calling the drm_mode_create_tv_margin_properties(). However, we also have a drm_atomic_helper_connector_tv_reset() function that will reset the TV margin properties to their default values, and thus is supposed to be called for the latter set. This creates an ambiguity due to the inconsistent naming. We can thus rename the drm_atomic_helper_connector_tv_reset() function to drm_atomic_helper_connector_tv_margins_reset() to remove that ambiguity and hopefully make it more obvious. Acked-by: Thomas Zimmermann Reviewed-by: Noralf Trønnes Link: https://lore.kernel.org/r/20220728-rpi-analog-tv-properties-v4-4-60d38873f782@cerno.tech Signed-off-by: Maxime Ripard --- drivers/gpu/drm/drm_atomic_state_helper.c | 6 +++--- drivers/gpu/drm/gud/gud_connector.c | 2 +- drivers/gpu/drm/vc4/vc4_hdmi.c | 2 +- include/drm/drm_atomic_state_helper.h | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c index bf31b9d92094..dfb57217253b 100644 --- a/drivers/gpu/drm/drm_atomic_state_helper.c +++ b/drivers/gpu/drm/drm_atomic_state_helper.c @@ -464,12 +464,12 @@ void drm_atomic_helper_connector_reset(struct drm_connector *connector) EXPORT_SYMBOL(drm_atomic_helper_connector_reset); /** - * drm_atomic_helper_connector_tv_reset - Resets TV connector properties + * drm_atomic_helper_connector_tv_margins_reset - Resets TV connector properties * @connector: DRM connector * * Resets the TV-related properties attached to a connector. */ -void drm_atomic_helper_connector_tv_reset(struct drm_connector *connector) +void drm_atomic_helper_connector_tv_margins_reset(struct drm_connector *connector) { struct drm_cmdline_mode *cmdline = &connector->cmdline_mode; struct drm_connector_state *state = connector->state; @@ -479,7 +479,7 @@ void drm_atomic_helper_connector_tv_reset(struct drm_connector *connector) state->tv.margins.top = cmdline->tv_margins.top; state->tv.margins.bottom = cmdline->tv_margins.bottom; } -EXPORT_SYMBOL(drm_atomic_helper_connector_tv_reset); +EXPORT_SYMBOL(drm_atomic_helper_connector_tv_margins_reset); /** * __drm_atomic_helper_connector_duplicate_state - copy atomic connector state diff --git a/drivers/gpu/drm/gud/gud_connector.c b/drivers/gpu/drm/gud/gud_connector.c index d0addd478815..fa636206f232 100644 --- a/drivers/gpu/drm/gud/gud_connector.c +++ b/drivers/gpu/drm/gud/gud_connector.c @@ -355,7 +355,7 @@ static void gud_connector_reset(struct drm_connector *connector) drm_atomic_helper_connector_reset(connector); connector->state->tv = gconn->initial_tv_state; /* Set margins from command line */ - drm_atomic_helper_connector_tv_reset(connector); + drm_atomic_helper_connector_tv_margins_reset(connector); if (gconn->initial_brightness >= 0) connector->state->tv.brightness = gconn->initial_brightness; } diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 64f9feabf43e..99908137dbe7 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -542,7 +542,7 @@ static void vc4_hdmi_connector_reset(struct drm_connector *connector) new_state->base.max_bpc = 8; new_state->base.max_requested_bpc = 8; new_state->output_format = VC4_HDMI_OUTPUT_RGB; - drm_atomic_helper_connector_tv_reset(connector); + drm_atomic_helper_connector_tv_margins_reset(connector); } static struct drm_connector_state * diff --git a/include/drm/drm_atomic_state_helper.h b/include/drm/drm_atomic_state_helper.h index 3f8f1d627f7c..192766656b88 100644 --- a/include/drm/drm_atomic_state_helper.h +++ b/include/drm/drm_atomic_state_helper.h @@ -70,7 +70,7 @@ void __drm_atomic_helper_connector_state_reset(struct drm_connector_state *conn_ void __drm_atomic_helper_connector_reset(struct drm_connector *connector, struct drm_connector_state *conn_state); void drm_atomic_helper_connector_reset(struct drm_connector *connector); -void drm_atomic_helper_connector_tv_reset(struct drm_connector *connector); +void drm_atomic_helper_connector_tv_margins_reset(struct drm_connector *connector); void __drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector, struct drm_connector_state *state); -- cgit From d0236008f833e058c6abbcbf725cfa60a4d3efc5 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 29 Sep 2022 18:30:59 +0200 Subject: drm/connector: Rename subconnector state variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is two TV subconnector related properties registered by drm_mode_create_tv_properties(): subconnector and select subconnector. While the select subconnector property is stored in the kernel by the drm_tv_connector_state structure, the subconnector property isn't stored anywhere. Worse, the select subconnector property is stored in a field called subconnector, creating some ambiguity about which property content we're accessing. Let's rename that field to one called select_subconnector to make it move obvious what it's about. Acked-by: Thomas Zimmermann Reviewed-by: Noralf Trønnes Link: https://lore.kernel.org/r/20220728-rpi-analog-tv-properties-v4-5-60d38873f782@cerno.tech Signed-off-by: Maxime Ripard --- drivers/gpu/drm/drm_atomic_uapi.c | 4 ++-- include/drm/drm_connector.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index 79730fa1dd8e..c74c78a28171 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -687,7 +687,7 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector, */ return -EINVAL; } else if (property == config->tv_select_subconnector_property) { - state->tv.subconnector = val; + state->tv.select_subconnector = val; } else if (property == config->tv_left_margin_property) { state->tv.margins.left = val; } else if (property == config->tv_right_margin_property) { @@ -795,7 +795,7 @@ drm_atomic_connector_get_property(struct drm_connector *connector, else *val = connector->dpms; } else if (property == config->tv_select_subconnector_property) { - *val = state->tv.subconnector; + *val = state->tv.select_subconnector; } else if (property == config->tv_left_margin_property) { *val = state->tv.margins.left; } else if (property == config->tv_right_margin_property) { diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 248206bbd975..60b5662dec7c 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -692,7 +692,7 @@ struct drm_connector_tv_margins { /** * struct drm_tv_connector_state - TV connector related states - * @subconnector: selected subconnector + * @select_subconnector: selected subconnector * @margins: TV margins * @mode: TV mode * @brightness: brightness in percent @@ -703,7 +703,7 @@ struct drm_connector_tv_margins { * @hue: hue in percent */ struct drm_tv_connector_state { - enum drm_mode_subconnector subconnector; + enum drm_mode_subconnector select_subconnector; struct drm_connector_tv_margins margins; unsigned int mode; unsigned int brightness; -- cgit From 941731a2684251e8854366c75df19185f586c784 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 29 Sep 2022 18:31:00 +0200 Subject: drm/atomic: Add TV subconnector property to get/set_property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The subconnector property was created by drm_mode_create_tv_properties(), but wasn't exposed to the userspace through the generic atomic_get/set_property implementation, and wasn't stored in any generic state structure. Let's solve this. Reviewed-by: Noralf Trønnes Link: https://lore.kernel.org/r/20220728-rpi-analog-tv-properties-v4-6-60d38873f782@cerno.tech Signed-off-by: Maxime Ripard --- drivers/gpu/drm/drm_atomic_uapi.c | 4 ++++ include/drm/drm_connector.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index c74c78a28171..c06d0639d552 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -688,6 +688,8 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector, return -EINVAL; } else if (property == config->tv_select_subconnector_property) { state->tv.select_subconnector = val; + } else if (property == config->tv_subconnector_property) { + state->tv.subconnector = val; } else if (property == config->tv_left_margin_property) { state->tv.margins.left = val; } else if (property == config->tv_right_margin_property) { @@ -796,6 +798,8 @@ drm_atomic_connector_get_property(struct drm_connector *connector, *val = connector->dpms; } else if (property == config->tv_select_subconnector_property) { *val = state->tv.select_subconnector; + } else if (property == config->tv_subconnector_property) { + *val = state->tv.subconnector; } else if (property == config->tv_left_margin_property) { *val = state->tv.margins.left; } else if (property == config->tv_right_margin_property) { diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 60b5662dec7c..1d5e3cccb9e3 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -693,6 +693,7 @@ struct drm_connector_tv_margins { /** * struct drm_tv_connector_state - TV connector related states * @select_subconnector: selected subconnector + * @subconnector: detected subconnector * @margins: TV margins * @mode: TV mode * @brightness: brightness in percent @@ -704,6 +705,7 @@ struct drm_connector_tv_margins { */ struct drm_tv_connector_state { enum drm_mode_subconnector select_subconnector; + enum drm_mode_subconnector subconnector; struct drm_connector_tv_margins margins; unsigned int mode; unsigned int brightness; -- cgit From 90c258ba4a36f610302cdea6ff3b4e1a0811f50e Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 29 Sep 2022 18:31:06 +0200 Subject: drm/modes: Only consider bpp and refresh before options Some video= options might have a value that contains a dash. However, the command line parsing mode considers all dashes as the separator between the mode and the bpp count. Let's rework the parsing code a bit to only consider a dash as the bpp separator if it before a comma, the options separator. A follow-up patch will add a unit-test for this once such an option is introduced. Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20220728-rpi-analog-tv-properties-v4-12-60d38873f782@cerno.tech Signed-off-by: Maxime Ripard --- drivers/gpu/drm/drm_modes.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index 304004fb80aa..e0221183135b 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -1801,20 +1801,22 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, name = mode_option; + /* Locate the start of named options */ + options_ptr = strchr(name, ','); + if (options_ptr) + options_off = options_ptr - name; + else + options_off = strlen(name); + /* Try to locate the bpp and refresh specifiers, if any */ - bpp_ptr = strchr(name, '-'); + bpp_ptr = strnchr(name, options_off, '-'); if (bpp_ptr) bpp_off = bpp_ptr - name; - refresh_ptr = strchr(name, '@'); + refresh_ptr = strnchr(name, options_off, '@'); if (refresh_ptr) refresh_off = refresh_ptr - name; - /* Locate the start of named options */ - options_ptr = strchr(name, ','); - if (options_ptr) - options_off = options_ptr - name; - /* Locate the end of the name / resolution, and parse it */ if (bpp_ptr) { mode_end = bpp_off; -- cgit From 8b6e28ea0a51a74af6a2684591a3471742f90647 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 29 Sep 2022 18:31:07 +0200 Subject: drm/modes: parse_cmdline: Add support for named modes containing dashes It is fairly common for named video modes to contain dashes (e.g. "tt-mid" on Atari, "dblntsc-ff" on Amiga). Currently such mode names are not recognized, as the dash is considered to be a separator between mode name and bpp. Fix this by skipping any dashes that are not followed immediately by a digit when looking for the separator. Signed-off-by: Geert Uytterhoeven Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20220728-rpi-analog-tv-properties-v4-13-60d38873f782@cerno.tech Signed-off-by: Maxime Ripard --- drivers/gpu/drm/drm_modes.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index e0221183135b..5d4ac79381c4 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -1810,6 +1810,8 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, /* Try to locate the bpp and refresh specifiers, if any */ bpp_ptr = strnchr(name, options_off, '-'); + while (bpp_ptr && !isdigit(bpp_ptr[1])) + bpp_ptr = strnchr(bpp_ptr + 1, options_off, '-'); if (bpp_ptr) bpp_off = bpp_ptr - name; -- cgit From 499143e5b413104d0b242e385cb929cd3ac858eb Mon Sep 17 00:00:00 2001 From: Mateusz Kwiatkowski Date: Thu, 29 Sep 2022 18:31:19 +0200 Subject: drm/vc4: vec: Fix definition of PAL-M mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PAL-M is a Brazilian analog TV standard that uses a PAL-style chroma subcarrier at 3.575611[888111] MHz on top of 525-line (480i60) timings. This commit makes the driver actually use the proper VEC preset for this mode instead of just changing PAL subcarrier frequency. Acked-by: Noralf Trønnes Signed-off-by: Mateusz Kwiatkowski Link: https://lore.kernel.org/r/20220728-rpi-analog-tv-properties-v4-25-60d38873f782@cerno.tech Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_vec.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c index 0b3333865702..92c07e31d632 100644 --- a/drivers/gpu/drm/vc4/vc4_vec.c +++ b/drivers/gpu/drm/vc4/vc4_vec.c @@ -69,6 +69,7 @@ #define VEC_CONFIG0_STD_MASK GENMASK(1, 0) #define VEC_CONFIG0_NTSC_STD 0 #define VEC_CONFIG0_PAL_BDGHI_STD 1 +#define VEC_CONFIG0_PAL_M_STD 2 #define VEC_CONFIG0_PAL_N_STD 3 #define VEC_SCHPH 0x108 @@ -255,10 +256,9 @@ static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = { .config1 = VEC_CONFIG1_C_CVBS_CVBS, }, [VC4_VEC_TV_MODE_PAL_M] = { - .mode = &pal_mode, - .config0 = VEC_CONFIG0_PAL_BDGHI_STD, - .config1 = VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ, - .custom_freq = 0x223b61d1, + .mode = &ntsc_mode, + .config0 = VEC_CONFIG0_PAL_M_STD, + .config1 = VEC_CONFIG1_C_CVBS_CVBS, }, }; -- cgit From 8d87088e4e6d4e66f63447c7f9a4b6c3db6e61c2 Mon Sep 17 00:00:00 2001 From: Teresa Remmet Date: Thu, 1 Sep 2022 15:19:51 +0200 Subject: drm/bridge: tc358775: Do not soft reset i2c-slave controller Soft reset during tc_bridge_enable() is triggered by setting all available reset control bits in the SYSRST register. But as noted in the data sheet resetting the i2c-slave controller should be only done over DSI and is only useful for chip debugging. So do not set RSTI2CS (bit0). Signed-off-by: Teresa Remmet Reviewed-by: Robert Foss Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20220901131951.1116512-1-t.remmet@phytec.de --- drivers/gpu/drm/bridge/tc358775.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/tc358775.c b/drivers/gpu/drm/bridge/tc358775.c index f1c6e62b0e1d..a5f5eae1e80f 100644 --- a/drivers/gpu/drm/bridge/tc358775.c +++ b/drivers/gpu/drm/bridge/tc358775.c @@ -408,7 +408,7 @@ static void tc_bridge_enable(struct drm_bridge *bridge) (val >> 8) & 0xFF, val & 0xFF); d2l_write(tc->i2c, SYSRST, SYS_RST_REG | SYS_RST_DSIRX | SYS_RST_BM | - SYS_RST_LCD | SYS_RST_I2CM | SYS_RST_I2CS); + SYS_RST_LCD | SYS_RST_I2CM); usleep_range(30000, 40000); d2l_write(tc->i2c, PPI_TX_RX_TA, TTA_GET | TTA_SURE); -- cgit From cf51cc7b2dec8ef3e3bed537ff12c503674ec180 Mon Sep 17 00:00:00 2001 From: Vinay Belgaumkar Date: Wed, 5 Oct 2022 08:59:42 -0700 Subject: drm/i915: Add a wrapper for frequency debugfs Move it to the RPS source file. v2: Separate out code movement and functional changes (Jani) Signed-off-by: Vinay Belgaumkar Reviewed-by: Jani Nikula Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20221005155943.34747-2-vinay.belgaumkar@intel.com --- drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c | 157 +------------------------ drivers/gpu/drm/i915/gt/intel_rps.c | 163 ++++++++++++++++++++++++++ drivers/gpu/drm/i915/gt/intel_rps.h | 3 + 3 files changed, 167 insertions(+), 156 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c index 10f680dbd7b6..40d0a3be42ac 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c @@ -344,162 +344,7 @@ void intel_gt_pm_frequency_dump(struct intel_gt *gt, struct drm_printer *p) drm_printf(p, "efficient (RPe) frequency: %d MHz\n", intel_gpu_freq(rps, rps->efficient_freq)); } else if (GRAPHICS_VER(i915) >= 6) { - u32 rp_state_limits; - u32 gt_perf_status; - struct intel_rps_freq_caps caps; - u32 rpmodectl, rpinclimit, rpdeclimit; - u32 rpstat, cagf, reqf; - u32 rpcurupei, rpcurup, rpprevup; - u32 rpcurdownei, rpcurdown, rpprevdown; - u32 rpupei, rpupt, rpdownei, rpdownt; - u32 pm_ier, pm_imr, pm_isr, pm_iir, pm_mask; - - rp_state_limits = intel_uncore_read(uncore, GEN6_RP_STATE_LIMITS); - gen6_rps_get_freq_caps(rps, &caps); - if (IS_GEN9_LP(i915)) - gt_perf_status = intel_uncore_read(uncore, BXT_GT_PERF_STATUS); - else - gt_perf_status = intel_uncore_read(uncore, GEN6_GT_PERF_STATUS); - - /* RPSTAT1 is in the GT power well */ - intel_uncore_forcewake_get(uncore, FORCEWAKE_ALL); - - reqf = intel_uncore_read(uncore, GEN6_RPNSWREQ); - if (GRAPHICS_VER(i915) >= 9) { - reqf >>= 23; - } else { - reqf &= ~GEN6_TURBO_DISABLE; - if (IS_HASWELL(i915) || IS_BROADWELL(i915)) - reqf >>= 24; - else - reqf >>= 25; - } - reqf = intel_gpu_freq(rps, reqf); - - rpmodectl = intel_uncore_read(uncore, GEN6_RP_CONTROL); - rpinclimit = intel_uncore_read(uncore, GEN6_RP_UP_THRESHOLD); - rpdeclimit = intel_uncore_read(uncore, GEN6_RP_DOWN_THRESHOLD); - - rpstat = intel_uncore_read(uncore, GEN6_RPSTAT1); - rpcurupei = intel_uncore_read(uncore, GEN6_RP_CUR_UP_EI) & GEN6_CURICONT_MASK; - rpcurup = intel_uncore_read(uncore, GEN6_RP_CUR_UP) & GEN6_CURBSYTAVG_MASK; - rpprevup = intel_uncore_read(uncore, GEN6_RP_PREV_UP) & GEN6_CURBSYTAVG_MASK; - rpcurdownei = intel_uncore_read(uncore, GEN6_RP_CUR_DOWN_EI) & GEN6_CURIAVG_MASK; - rpcurdown = intel_uncore_read(uncore, GEN6_RP_CUR_DOWN) & GEN6_CURBSYTAVG_MASK; - rpprevdown = intel_uncore_read(uncore, GEN6_RP_PREV_DOWN) & GEN6_CURBSYTAVG_MASK; - - rpupei = intel_uncore_read(uncore, GEN6_RP_UP_EI); - rpupt = intel_uncore_read(uncore, GEN6_RP_UP_THRESHOLD); - - rpdownei = intel_uncore_read(uncore, GEN6_RP_DOWN_EI); - rpdownt = intel_uncore_read(uncore, GEN6_RP_DOWN_THRESHOLD); - - cagf = intel_rps_read_actual_frequency(rps); - - intel_uncore_forcewake_put(uncore, FORCEWAKE_ALL); - - if (GRAPHICS_VER(i915) >= 11) { - pm_ier = intel_uncore_read(uncore, GEN11_GPM_WGBOXPERF_INTR_ENABLE); - pm_imr = intel_uncore_read(uncore, GEN11_GPM_WGBOXPERF_INTR_MASK); - /* - * The equivalent to the PM ISR & IIR cannot be read - * without affecting the current state of the system - */ - pm_isr = 0; - pm_iir = 0; - } else if (GRAPHICS_VER(i915) >= 8) { - pm_ier = intel_uncore_read(uncore, GEN8_GT_IER(2)); - pm_imr = intel_uncore_read(uncore, GEN8_GT_IMR(2)); - pm_isr = intel_uncore_read(uncore, GEN8_GT_ISR(2)); - pm_iir = intel_uncore_read(uncore, GEN8_GT_IIR(2)); - } else { - pm_ier = intel_uncore_read(uncore, GEN6_PMIER); - pm_imr = intel_uncore_read(uncore, GEN6_PMIMR); - pm_isr = intel_uncore_read(uncore, GEN6_PMISR); - pm_iir = intel_uncore_read(uncore, GEN6_PMIIR); - } - pm_mask = intel_uncore_read(uncore, GEN6_PMINTRMSK); - - drm_printf(p, "Video Turbo Mode: %s\n", - str_yes_no(rpmodectl & GEN6_RP_MEDIA_TURBO)); - drm_printf(p, "HW control enabled: %s\n", - str_yes_no(rpmodectl & GEN6_RP_ENABLE)); - drm_printf(p, "SW control enabled: %s\n", - str_yes_no((rpmodectl & GEN6_RP_MEDIA_MODE_MASK) == GEN6_RP_MEDIA_SW_MODE)); - - drm_printf(p, "PM IER=0x%08x IMR=0x%08x, MASK=0x%08x\n", - pm_ier, pm_imr, pm_mask); - if (GRAPHICS_VER(i915) <= 10) - drm_printf(p, "PM ISR=0x%08x IIR=0x%08x\n", - pm_isr, pm_iir); - drm_printf(p, "pm_intrmsk_mbz: 0x%08x\n", - rps->pm_intrmsk_mbz); - drm_printf(p, "GT_PERF_STATUS: 0x%08x\n", gt_perf_status); - drm_printf(p, "Render p-state ratio: %d\n", - (gt_perf_status & (GRAPHICS_VER(i915) >= 9 ? 0x1ff00 : 0xff00)) >> 8); - drm_printf(p, "Render p-state VID: %d\n", - gt_perf_status & 0xff); - drm_printf(p, "Render p-state limit: %d\n", - rp_state_limits & 0xff); - drm_printf(p, "RPSTAT1: 0x%08x\n", rpstat); - drm_printf(p, "RPMODECTL: 0x%08x\n", rpmodectl); - drm_printf(p, "RPINCLIMIT: 0x%08x\n", rpinclimit); - drm_printf(p, "RPDECLIMIT: 0x%08x\n", rpdeclimit); - drm_printf(p, "RPNSWREQ: %dMHz\n", reqf); - drm_printf(p, "CAGF: %dMHz\n", cagf); - drm_printf(p, "RP CUR UP EI: %d (%lldns)\n", - rpcurupei, - intel_gt_pm_interval_to_ns(gt, rpcurupei)); - drm_printf(p, "RP CUR UP: %d (%lldns)\n", - rpcurup, intel_gt_pm_interval_to_ns(gt, rpcurup)); - drm_printf(p, "RP PREV UP: %d (%lldns)\n", - rpprevup, intel_gt_pm_interval_to_ns(gt, rpprevup)); - drm_printf(p, "Up threshold: %d%%\n", - rps->power.up_threshold); - drm_printf(p, "RP UP EI: %d (%lldns)\n", - rpupei, intel_gt_pm_interval_to_ns(gt, rpupei)); - drm_printf(p, "RP UP THRESHOLD: %d (%lldns)\n", - rpupt, intel_gt_pm_interval_to_ns(gt, rpupt)); - - drm_printf(p, "RP CUR DOWN EI: %d (%lldns)\n", - rpcurdownei, - intel_gt_pm_interval_to_ns(gt, rpcurdownei)); - drm_printf(p, "RP CUR DOWN: %d (%lldns)\n", - rpcurdown, - intel_gt_pm_interval_to_ns(gt, rpcurdown)); - drm_printf(p, "RP PREV DOWN: %d (%lldns)\n", - rpprevdown, - intel_gt_pm_interval_to_ns(gt, rpprevdown)); - drm_printf(p, "Down threshold: %d%%\n", - rps->power.down_threshold); - drm_printf(p, "RP DOWN EI: %d (%lldns)\n", - rpdownei, intel_gt_pm_interval_to_ns(gt, rpdownei)); - drm_printf(p, "RP DOWN THRESHOLD: %d (%lldns)\n", - rpdownt, intel_gt_pm_interval_to_ns(gt, rpdownt)); - - drm_printf(p, "Lowest (RPN) frequency: %dMHz\n", - intel_gpu_freq(rps, caps.min_freq)); - drm_printf(p, "Nominal (RP1) frequency: %dMHz\n", - intel_gpu_freq(rps, caps.rp1_freq)); - drm_printf(p, "Max non-overclocked (RP0) frequency: %dMHz\n", - intel_gpu_freq(rps, caps.rp0_freq)); - drm_printf(p, "Max overclocked frequency: %dMHz\n", - intel_gpu_freq(rps, rps->max_freq)); - - drm_printf(p, "Current freq: %d MHz\n", - intel_gpu_freq(rps, rps->cur_freq)); - drm_printf(p, "Actual freq: %d MHz\n", cagf); - drm_printf(p, "Idle freq: %d MHz\n", - intel_gpu_freq(rps, rps->idle_freq)); - drm_printf(p, "Min freq: %d MHz\n", - intel_gpu_freq(rps, rps->min_freq)); - drm_printf(p, "Boost freq: %d MHz\n", - intel_gpu_freq(rps, rps->boost_freq)); - drm_printf(p, "Max freq: %d MHz\n", - intel_gpu_freq(rps, rps->max_freq)); - drm_printf(p, - "efficient (RPe) frequency: %d MHz\n", - intel_gpu_freq(rps, rps->efficient_freq)); + gen6_rps_frequency_dump(rps, p); } else { drm_puts(p, "no P-state info available\n"); } diff --git a/drivers/gpu/drm/i915/gt/intel_rps.c b/drivers/gpu/drm/i915/gt/intel_rps.c index 17b40b625e31..737db780db00 100644 --- a/drivers/gpu/drm/i915/gt/intel_rps.c +++ b/drivers/gpu/drm/i915/gt/intel_rps.c @@ -2219,6 +2219,169 @@ u32 intel_rps_get_rpn_frequency(struct intel_rps *rps) return intel_gpu_freq(rps, rps->min_freq); } +void gen6_rps_frequency_dump(struct intel_rps *rps, struct drm_printer *p) +{ + struct intel_gt *gt = rps_to_gt(rps); + struct drm_i915_private *i915 = gt->i915; + struct intel_uncore *uncore = gt->uncore; + struct intel_rps_freq_caps caps; + u32 rp_state_limits; + u32 gt_perf_status; + u32 rpmodectl, rpinclimit, rpdeclimit; + u32 rpstat, cagf, reqf; + u32 rpcurupei, rpcurup, rpprevup; + u32 rpcurdownei, rpcurdown, rpprevdown; + u32 rpupei, rpupt, rpdownei, rpdownt; + u32 pm_ier, pm_imr, pm_isr, pm_iir, pm_mask; + + rp_state_limits = intel_uncore_read(uncore, GEN6_RP_STATE_LIMITS); + gen6_rps_get_freq_caps(rps, &caps); + if (IS_GEN9_LP(i915)) + gt_perf_status = intel_uncore_read(uncore, BXT_GT_PERF_STATUS); + else + gt_perf_status = intel_uncore_read(uncore, GEN6_GT_PERF_STATUS); + + /* RPSTAT1 is in the GT power well */ + intel_uncore_forcewake_get(uncore, FORCEWAKE_ALL); + + reqf = intel_uncore_read(uncore, GEN6_RPNSWREQ); + if (GRAPHICS_VER(i915) >= 9) { + reqf >>= 23; + } else { + reqf &= ~GEN6_TURBO_DISABLE; + if (IS_HASWELL(i915) || IS_BROADWELL(i915)) + reqf >>= 24; + else + reqf >>= 25; + } + reqf = intel_gpu_freq(rps, reqf); + + rpmodectl = intel_uncore_read(uncore, GEN6_RP_CONTROL); + rpinclimit = intel_uncore_read(uncore, GEN6_RP_UP_THRESHOLD); + rpdeclimit = intel_uncore_read(uncore, GEN6_RP_DOWN_THRESHOLD); + + rpstat = intel_uncore_read(uncore, GEN6_RPSTAT1); + rpcurupei = intel_uncore_read(uncore, GEN6_RP_CUR_UP_EI) & GEN6_CURICONT_MASK; + rpcurup = intel_uncore_read(uncore, GEN6_RP_CUR_UP) & GEN6_CURBSYTAVG_MASK; + rpprevup = intel_uncore_read(uncore, GEN6_RP_PREV_UP) & GEN6_CURBSYTAVG_MASK; + rpcurdownei = intel_uncore_read(uncore, GEN6_RP_CUR_DOWN_EI) & GEN6_CURIAVG_MASK; + rpcurdown = intel_uncore_read(uncore, GEN6_RP_CUR_DOWN) & GEN6_CURBSYTAVG_MASK; + rpprevdown = intel_uncore_read(uncore, GEN6_RP_PREV_DOWN) & GEN6_CURBSYTAVG_MASK; + + rpupei = intel_uncore_read(uncore, GEN6_RP_UP_EI); + rpupt = intel_uncore_read(uncore, GEN6_RP_UP_THRESHOLD); + + rpdownei = intel_uncore_read(uncore, GEN6_RP_DOWN_EI); + rpdownt = intel_uncore_read(uncore, GEN6_RP_DOWN_THRESHOLD); + + cagf = intel_rps_read_actual_frequency(rps); + + intel_uncore_forcewake_put(uncore, FORCEWAKE_ALL); + + if (GRAPHICS_VER(i915) >= 11) { + pm_ier = intel_uncore_read(uncore, GEN11_GPM_WGBOXPERF_INTR_ENABLE); + pm_imr = intel_uncore_read(uncore, GEN11_GPM_WGBOXPERF_INTR_MASK); + /* + * The equivalent to the PM ISR & IIR cannot be read + * without affecting the current state of the system + */ + pm_isr = 0; + pm_iir = 0; + } else if (GRAPHICS_VER(i915) >= 8) { + pm_ier = intel_uncore_read(uncore, GEN8_GT_IER(2)); + pm_imr = intel_uncore_read(uncore, GEN8_GT_IMR(2)); + pm_isr = intel_uncore_read(uncore, GEN8_GT_ISR(2)); + pm_iir = intel_uncore_read(uncore, GEN8_GT_IIR(2)); + } else { + pm_ier = intel_uncore_read(uncore, GEN6_PMIER); + pm_imr = intel_uncore_read(uncore, GEN6_PMIMR); + pm_isr = intel_uncore_read(uncore, GEN6_PMISR); + pm_iir = intel_uncore_read(uncore, GEN6_PMIIR); + } + pm_mask = intel_uncore_read(uncore, GEN6_PMINTRMSK); + + drm_printf(p, "Video Turbo Mode: %s\n", + str_yes_no(rpmodectl & GEN6_RP_MEDIA_TURBO)); + drm_printf(p, "HW control enabled: %s\n", + str_yes_no(rpmodectl & GEN6_RP_ENABLE)); + drm_printf(p, "SW control enabled: %s\n", + str_yes_no((rpmodectl & GEN6_RP_MEDIA_MODE_MASK) == GEN6_RP_MEDIA_SW_MODE)); + + drm_printf(p, "PM IER=0x%08x IMR=0x%08x, MASK=0x%08x\n", + pm_ier, pm_imr, pm_mask); + if (GRAPHICS_VER(i915) <= 10) + drm_printf(p, "PM ISR=0x%08x IIR=0x%08x\n", + pm_isr, pm_iir); + drm_printf(p, "pm_intrmsk_mbz: 0x%08x\n", + rps->pm_intrmsk_mbz); + drm_printf(p, "GT_PERF_STATUS: 0x%08x\n", gt_perf_status); + drm_printf(p, "Render p-state ratio: %d\n", + (gt_perf_status & (GRAPHICS_VER(i915) >= 9 ? 0x1ff00 : 0xff00)) >> 8); + drm_printf(p, "Render p-state VID: %d\n", + gt_perf_status & 0xff); + drm_printf(p, "Render p-state limit: %d\n", + rp_state_limits & 0xff); + drm_printf(p, "RPSTAT1: 0x%08x\n", rpstat); + drm_printf(p, "RPMODECTL: 0x%08x\n", rpmodectl); + drm_printf(p, "RPINCLIMIT: 0x%08x\n", rpinclimit); + drm_printf(p, "RPDECLIMIT: 0x%08x\n", rpdeclimit); + drm_printf(p, "RPNSWREQ: %dMHz\n", reqf); + drm_printf(p, "CAGF: %dMHz\n", cagf); + drm_printf(p, "RP CUR UP EI: %d (%lldns)\n", + rpcurupei, + intel_gt_pm_interval_to_ns(gt, rpcurupei)); + drm_printf(p, "RP CUR UP: %d (%lldns)\n", + rpcurup, intel_gt_pm_interval_to_ns(gt, rpcurup)); + drm_printf(p, "RP PREV UP: %d (%lldns)\n", + rpprevup, intel_gt_pm_interval_to_ns(gt, rpprevup)); + drm_printf(p, "Up threshold: %d%%\n", + rps->power.up_threshold); + drm_printf(p, "RP UP EI: %d (%lldns)\n", + rpupei, intel_gt_pm_interval_to_ns(gt, rpupei)); + drm_printf(p, "RP UP THRESHOLD: %d (%lldns)\n", + rpupt, intel_gt_pm_interval_to_ns(gt, rpupt)); + + drm_printf(p, "RP CUR DOWN EI: %d (%lldns)\n", + rpcurdownei, + intel_gt_pm_interval_to_ns(gt, rpcurdownei)); + drm_printf(p, "RP CUR DOWN: %d (%lldns)\n", + rpcurdown, + intel_gt_pm_interval_to_ns(gt, rpcurdown)); + drm_printf(p, "RP PREV DOWN: %d (%lldns)\n", + rpprevdown, + intel_gt_pm_interval_to_ns(gt, rpprevdown)); + drm_printf(p, "Down threshold: %d%%\n", + rps->power.down_threshold); + drm_printf(p, "RP DOWN EI: %d (%lldns)\n", + rpdownei, intel_gt_pm_interval_to_ns(gt, rpdownei)); + drm_printf(p, "RP DOWN THRESHOLD: %d (%lldns)\n", + rpdownt, intel_gt_pm_interval_to_ns(gt, rpdownt)); + + drm_printf(p, "Lowest (RPN) frequency: %dMHz\n", + intel_gpu_freq(rps, caps.min_freq)); + drm_printf(p, "Nominal (RP1) frequency: %dMHz\n", + intel_gpu_freq(rps, caps.rp1_freq)); + drm_printf(p, "Max non-overclocked (RP0) frequency: %dMHz\n", + intel_gpu_freq(rps, caps.rp0_freq)); + drm_printf(p, "Max overclocked frequency: %dMHz\n", + intel_gpu_freq(rps, rps->max_freq)); + + drm_printf(p, "Current freq: %d MHz\n", + intel_gpu_freq(rps, rps->cur_freq)); + drm_printf(p, "Actual freq: %d MHz\n", cagf); + drm_printf(p, "Idle freq: %d MHz\n", + intel_gpu_freq(rps, rps->idle_freq)); + drm_printf(p, "Min freq: %d MHz\n", + intel_gpu_freq(rps, rps->min_freq)); + drm_printf(p, "Boost freq: %d MHz\n", + intel_gpu_freq(rps, rps->boost_freq)); + drm_printf(p, "Max freq: %d MHz\n", + intel_gpu_freq(rps, rps->max_freq)); + drm_printf(p, + "efficient (RPe) frequency: %d MHz\n", + intel_gpu_freq(rps, rps->efficient_freq)); +} + static int set_max_freq(struct intel_rps *rps, u32 val) { struct drm_i915_private *i915 = rps_to_i915(rps); diff --git a/drivers/gpu/drm/i915/gt/intel_rps.h b/drivers/gpu/drm/i915/gt/intel_rps.h index 4509dfdc52e0..110300dfd438 100644 --- a/drivers/gpu/drm/i915/gt/intel_rps.h +++ b/drivers/gpu/drm/i915/gt/intel_rps.h @@ -10,6 +10,7 @@ #include "i915_reg_defs.h" struct i915_request; +struct drm_printer; void intel_rps_init_early(struct intel_rps *rps); void intel_rps_init(struct intel_rps *rps); @@ -54,6 +55,8 @@ void intel_rps_lower_unslice(struct intel_rps *rps); u32 intel_rps_read_throttle_reason(struct intel_rps *rps); bool rps_read_mask_mmio(struct intel_rps *rps, i915_reg_t reg32, u32 mask); +void gen6_rps_frequency_dump(struct intel_rps *rps, struct drm_printer *p); + void gen5_rps_irq_handler(struct intel_rps *rps); void gen6_rps_irq_handler(struct intel_rps *rps, u32 pm_iir); void gen11_rps_irq_handler(struct intel_rps *rps, u32 pm_iir); -- cgit From 83d495a5b4b8cb6791e3ec6c14bd792e9c196cf9 Mon Sep 17 00:00:00 2001 From: Vinay Belgaumkar Date: Wed, 5 Oct 2022 08:59:43 -0700 Subject: drm/i915/slpc: Update the frequency debugfs Read the values stored in the SLPC structures. Remove the fields that are no longer valid (like RPS interrupts) as well. v2: Move all functionality changes to this patch (Jani) v3: Fix compile warning and if condition (Jani) Signed-off-by: Vinay Belgaumkar Reviewed-by: Rodrigo Vivi Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20221005155943.34747-3-vinay.belgaumkar@intel.com --- drivers/gpu/drm/i915/gt/intel_rps.c | 46 ++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gt/intel_rps.c b/drivers/gpu/drm/i915/gt/intel_rps.c index 737db780db00..fc23c562d9b2 100644 --- a/drivers/gpu/drm/i915/gt/intel_rps.c +++ b/drivers/gpu/drm/i915/gt/intel_rps.c @@ -2219,7 +2219,7 @@ u32 intel_rps_get_rpn_frequency(struct intel_rps *rps) return intel_gpu_freq(rps, rps->min_freq); } -void gen6_rps_frequency_dump(struct intel_rps *rps, struct drm_printer *p) +static void rps_frequency_dump(struct intel_rps *rps, struct drm_printer *p) { struct intel_gt *gt = rps_to_gt(rps); struct drm_i915_private *i915 = gt->i915; @@ -2382,6 +2382,50 @@ void gen6_rps_frequency_dump(struct intel_rps *rps, struct drm_printer *p) intel_gpu_freq(rps, rps->efficient_freq)); } +static void slpc_frequency_dump(struct intel_rps *rps, struct drm_printer *p) +{ + struct intel_gt *gt = rps_to_gt(rps); + struct intel_uncore *uncore = gt->uncore; + struct intel_rps_freq_caps caps; + u32 pm_mask; + + gen6_rps_get_freq_caps(rps, &caps); + pm_mask = intel_uncore_read(uncore, GEN6_PMINTRMSK); + + drm_printf(p, "PM MASK=0x%08x\n", pm_mask); + drm_printf(p, "pm_intrmsk_mbz: 0x%08x\n", + rps->pm_intrmsk_mbz); + drm_printf(p, "RPSTAT1: 0x%08x\n", intel_uncore_read(uncore, GEN6_RPSTAT1)); + drm_printf(p, "RPNSWREQ: %dMHz\n", intel_rps_get_requested_frequency(rps)); + drm_printf(p, "Lowest (RPN) frequency: %dMHz\n", + intel_gpu_freq(rps, caps.min_freq)); + drm_printf(p, "Nominal (RP1) frequency: %dMHz\n", + intel_gpu_freq(rps, caps.rp1_freq)); + drm_printf(p, "Max non-overclocked (RP0) frequency: %dMHz\n", + intel_gpu_freq(rps, caps.rp0_freq)); + drm_printf(p, "Current freq: %d MHz\n", + intel_rps_get_requested_frequency(rps)); + drm_printf(p, "Actual freq: %d MHz\n", + intel_rps_read_actual_frequency(rps)); + drm_printf(p, "Min freq: %d MHz\n", + intel_rps_get_min_frequency(rps)); + drm_printf(p, "Boost freq: %d MHz\n", + intel_rps_get_boost_frequency(rps)); + drm_printf(p, "Max freq: %d MHz\n", + intel_rps_get_max_frequency(rps)); + drm_printf(p, + "efficient (RPe) frequency: %d MHz\n", + intel_gpu_freq(rps, caps.rp1_freq)); +} + +void gen6_rps_frequency_dump(struct intel_rps *rps, struct drm_printer *p) +{ + if (rps_uses_slpc(rps)) + return slpc_frequency_dump(rps, p); + else + return rps_frequency_dump(rps, p); +} + static int set_max_freq(struct intel_rps *rps, u32 val) { struct drm_i915_private *i915 = rps_to_i915(rps); -- cgit From f38f614fa995f9555d7238df50253d550a7b5607 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Sat, 8 Oct 2022 00:11:07 +0300 Subject: drm/i915: Do the DRIVER_ATOMIC feature disable later MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we do the DRIVER_ATOMIC disable as almost the first thing during pci probe. That involves the use of DISPLAY_VER() which is perhaps a bit sketchy now that we may need to read that out from the hardware itself. Looks like we do populate a default value for it anyway so the current does at least still work. But let's make this safer anyway and move the code into intel_device_info_runtime_init() where we also handle the same thing for the !HAS_DISPLAY case. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221007211108.3883-1-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/i915_driver.c | 4 ---- drivers/gpu/drm/i915/intel_device_info.c | 4 ++++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c index f1e06758db19..764026d1c5c8 100644 --- a/drivers/gpu/drm/i915/i915_driver.c +++ b/drivers/gpu/drm/i915/i915_driver.c @@ -861,10 +861,6 @@ int i915_driver_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (IS_ERR(i915)) return PTR_ERR(i915); - /* Disable nuclear pageflip by default on pre-ILK */ - if (!i915->params.nuclear_pageflip && DISPLAY_VER(i915) < 5) - i915->drm.driver_features &= ~DRIVER_ATOMIC; - ret = pci_enable_device(pdev); if (ret) goto out_fini; diff --git a/drivers/gpu/drm/i915/intel_device_info.c b/drivers/gpu/drm/i915/intel_device_info.c index 908ec241fe71..b691b7c8c254 100644 --- a/drivers/gpu/drm/i915/intel_device_info.c +++ b/drivers/gpu/drm/i915/intel_device_info.c @@ -507,6 +507,10 @@ void intel_device_info_runtime_init(struct drm_i915_private *dev_priv) runtime->has_dmc = false; runtime->has_dsc = false; } + + /* Disable nuclear pageflip by default on pre-ILK */ + if (!dev_priv->params.nuclear_pageflip && DISPLAY_VER(dev_priv) < 5) + dev_priv->drm.driver_features &= ~DRIVER_ATOMIC; } void intel_driver_caps_print(const struct intel_driver_caps *caps, -- cgit From bfc82b2277db8e2210aa31492998d6e806eae9e4 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Sat, 8 Oct 2022 00:11:08 +0300 Subject: drm/i915: Enable atomic by default on ctg/elk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The watermark code for ctg/elk has been atomic ready for a long time so let's just flip the switch now that some of the last CxSR issues have been sorted out (which granted was a problem for vlv/chv as well despite them already having atomic enabled by default). v2: Rebase Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221007211108.3883-2-ville.syrjala@linux.intel.com Acked-by: Jani Nikula --- drivers/gpu/drm/i915/intel_device_info.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_device_info.c b/drivers/gpu/drm/i915/intel_device_info.c index b691b7c8c254..090097bb3c0a 100644 --- a/drivers/gpu/drm/i915/intel_device_info.c +++ b/drivers/gpu/drm/i915/intel_device_info.c @@ -508,8 +508,9 @@ void intel_device_info_runtime_init(struct drm_i915_private *dev_priv) runtime->has_dsc = false; } - /* Disable nuclear pageflip by default on pre-ILK */ - if (!dev_priv->params.nuclear_pageflip && DISPLAY_VER(dev_priv) < 5) + /* Disable nuclear pageflip by default on pre-g4x */ + if (!dev_priv->params.nuclear_pageflip && + DISPLAY_VER(dev_priv) < 5 && !IS_G4X(dev_priv)) dev_priv->drm.driver_features &= ~DRIVER_ATOMIC; } -- cgit From bc2472538c0d1cce334ffc9e97df0614cd2b1469 Mon Sep 17 00:00:00 2001 From: Thomas Hellström Date: Wed, 5 Oct 2022 14:11:59 +0200 Subject: drm/i915: Fix display problems after resume MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 39a2bd34c933 ("drm/i915: Use the vma resource as argument for gtt binding / unbinding") introduced a regression that due to the vma resource tracking of the binding state, dpt ptes were not correctly repopulated. Fix this by clearing the vma resource state before repopulating. The state will subsequently be restored by the bind_vma operation. Fixes: 39a2bd34c933 ("drm/i915: Use the vma resource as argument for gtt binding / unbinding") Signed-off-by: Thomas Hellström Link: https://patchwork.freedesktop.org/patch/msgid/20220912121957.31310-1-thomas.hellstrom@linux.intel.com Cc: Matthew Auld Cc: intel-gfx@lists.freedesktop.org Cc: # v5.18+ Reported-and-tested-by: Kevin Boulain Tested-by: David de Sousa Reviewed-by: Matthew Auld Reviewed-by: Andrzej Hajda Signed-off-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20221005121159.340245-1-thomas.hellstrom@linux.intel.com --- drivers/gpu/drm/i915/gt/intel_ggtt.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt.c b/drivers/gpu/drm/i915/gt/intel_ggtt.c index b31fe0fb013f..5c67e49aacf6 100644 --- a/drivers/gpu/drm/i915/gt/intel_ggtt.c +++ b/drivers/gpu/drm/i915/gt/intel_ggtt.c @@ -1275,10 +1275,16 @@ bool i915_ggtt_resume_vm(struct i915_address_space *vm) atomic_read(&vma->flags) & I915_VMA_BIND_MASK; GEM_BUG_ON(!was_bound); - if (!retained_ptes) + if (!retained_ptes) { + /* + * Clear the bound flags of the vma resource to allow + * ptes to be repopulated. + */ + vma->resource->bound_flags = 0; vma->ops->bind_vma(vm, NULL, vma->resource, obj ? obj->cache_level : 0, was_bound); + } if (obj) { /* only used during resume => exclusive access */ write_domain_objs |= fetch_and_zero(&obj->write_domain); obj->read_domains |= I915_GEM_DOMAIN_GTT; -- cgit From 3703060d17b0c35d8eece6c12550dba759e52c6a Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Thu, 6 Oct 2022 22:48:44 +0200 Subject: drm/i915/display: remove drm_device aliases drm_device pointers are unwelcome. Signed-off-by: Andrzej Hajda Signed-off-by: Andi Shyti Acked-by: Jani Nikula Reviewed-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20221006204844.2831303-1-andrzej.hajda@intel.com --- drivers/gpu/drm/i915/display/icl_dsi.c | 9 ++-- drivers/gpu/drm/i915/display/intel_display.c | 9 ++-- .../gpu/drm/i915/display/intel_display_debugfs.c | 51 +++++++++------------- drivers/gpu/drm/i915/display/intel_display_power.c | 3 +- drivers/gpu/drm/i915/display/intel_dp.c | 7 ++- drivers/gpu/drm/i915/display/intel_hotplug.c | 28 +++++------- drivers/gpu/drm/i915/display/intel_lpe_audio.c | 5 +-- drivers/gpu/drm/i915/display/intel_lvds.c | 11 +++-- drivers/gpu/drm/i915/display/intel_opregion.c | 7 ++- drivers/gpu/drm/i915/display/intel_pipe_crc.c | 9 ++-- drivers/gpu/drm/i915/display/intel_psr.c | 5 +-- drivers/gpu/drm/i915/display/intel_tv.c | 5 +-- drivers/gpu/drm/i915/display/vlv_dsi.c | 9 ++-- drivers/gpu/drm/i915/i915_driver.c | 18 +++----- drivers/gpu/drm/i915/i915_irq.c | 3 +- 15 files changed, 74 insertions(+), 105 deletions(-) diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c index 47f13750f6fa..e05e7cd6c412 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi.c +++ b/drivers/gpu/drm/i915/display/icl_dsi.c @@ -1985,7 +1985,6 @@ static void icl_dsi_add_properties(struct intel_connector *connector) void icl_dsi_init(struct drm_i915_private *dev_priv) { - struct drm_device *dev = &dev_priv->drm; struct intel_dsi *intel_dsi; struct intel_encoder *encoder; struct intel_connector *intel_connector; @@ -2010,7 +2009,7 @@ void icl_dsi_init(struct drm_i915_private *dev_priv) connector = &intel_connector->base; /* register DSI encoder with DRM subsystem */ - drm_encoder_init(dev, &encoder->base, &gen11_dsi_encoder_funcs, + drm_encoder_init(&dev_priv->drm, &encoder->base, &gen11_dsi_encoder_funcs, DRM_MODE_ENCODER_DSI, "DSI %c", port_name(port)); encoder->pre_pll_enable = gen11_dsi_pre_pll_enable; @@ -2034,7 +2033,7 @@ void icl_dsi_init(struct drm_i915_private *dev_priv) encoder->is_clock_enabled = gen11_dsi_is_clock_enabled; /* register DSI connector with DRM subsystem */ - drm_connector_init(dev, connector, &gen11_dsi_connector_funcs, + drm_connector_init(&dev_priv->drm, connector, &gen11_dsi_connector_funcs, DRM_MODE_CONNECTOR_DSI); drm_connector_helper_add(connector, &gen11_dsi_connector_helper_funcs); connector->display_info.subpixel_order = SubPixelHorizontalRGB; @@ -2045,9 +2044,9 @@ void icl_dsi_init(struct drm_i915_private *dev_priv) intel_bios_init_panel(dev_priv, &intel_connector->panel, NULL, NULL); - mutex_lock(&dev->mode_config.mutex); + mutex_lock(&dev_priv->drm.mode_config.mutex); intel_panel_add_vbt_lfp_fixed_mode(intel_connector); - mutex_unlock(&dev->mode_config.mutex); + mutex_unlock(&dev_priv->drm.mode_config.mutex); if (!intel_panel_preferred_fixed_mode(intel_connector)) { drm_err(&dev_priv->drm, "DSI fixed mode info missing\n"); diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index ff8ca79432a2..a31d7e890f61 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -878,7 +878,6 @@ static bool gpu_reset_clobbers_display(struct drm_i915_private *dev_priv) void intel_display_prepare_reset(struct drm_i915_private *dev_priv) { - struct drm_device *dev = &dev_priv->drm; struct drm_modeset_acquire_ctx *ctx = &dev_priv->reset_ctx; struct drm_atomic_state *state; int ret; @@ -906,10 +905,10 @@ void intel_display_prepare_reset(struct drm_i915_private *dev_priv) * Need mode_config.mutex so that we don't * trample ongoing ->detect() and whatnot. */ - mutex_lock(&dev->mode_config.mutex); + mutex_lock(&dev_priv->drm.mode_config.mutex); drm_modeset_acquire_init(ctx, 0); while (1) { - ret = drm_modeset_lock_all_ctx(dev, ctx); + ret = drm_modeset_lock_all_ctx(&dev_priv->drm, ctx); if (ret != -EDEADLK) break; @@ -919,7 +918,7 @@ void intel_display_prepare_reset(struct drm_i915_private *dev_priv) * Disabling the crtcs gracefully seems nicer. Also the * g33 docs say we should at least disable all the planes. */ - state = drm_atomic_helper_duplicate_state(dev, ctx); + state = drm_atomic_helper_duplicate_state(&dev_priv->drm, ctx); if (IS_ERR(state)) { ret = PTR_ERR(state); drm_err(&dev_priv->drm, "Duplicating state failed with %i\n", @@ -927,7 +926,7 @@ void intel_display_prepare_reset(struct drm_i915_private *dev_priv) return; } - ret = drm_atomic_helper_disable_all(dev, ctx); + ret = drm_atomic_helper_disable_all(&dev_priv->drm, ctx); if (ret) { drm_err(&dev_priv->drm, "Suspending crtc's failed with %i\n", ret); diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c index 372a5b427e4f..cfc056a05bbf 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c @@ -128,7 +128,6 @@ static int i915_vbt(struct seq_file *m, void *unused) static int i915_gem_framebuffer_info(struct seq_file *m, void *data) { struct drm_i915_private *dev_priv = node_to_i915(m->private); - struct drm_device *dev = &dev_priv->drm; struct intel_framebuffer *fbdev_fb = NULL; struct drm_framebuffer *drm_fb; @@ -147,8 +146,8 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data) } #endif - mutex_lock(&dev->mode_config.fb_lock); - drm_for_each_fb(drm_fb, dev) { + mutex_lock(&dev_priv->drm.mode_config.fb_lock); + drm_for_each_fb(drm_fb, &dev_priv->drm) { struct intel_framebuffer *fb = to_intel_framebuffer(drm_fb); if (fb == fbdev_fb) continue; @@ -163,7 +162,7 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data) i915_debugfs_describe_obj(m, intel_fb_obj(&fb->base)); seq_putc(m, '\n'); } - mutex_unlock(&dev->mode_config.fb_lock); + mutex_unlock(&dev_priv->drm.mode_config.fb_lock); return 0; } @@ -898,7 +897,6 @@ static void intel_crtc_info(struct seq_file *m, struct intel_crtc *crtc) static int i915_display_info(struct seq_file *m, void *unused) { struct drm_i915_private *dev_priv = node_to_i915(m->private); - struct drm_device *dev = &dev_priv->drm; struct intel_crtc *crtc; struct drm_connector *connector; struct drm_connector_list_iter conn_iter; @@ -906,22 +904,22 @@ static int i915_display_info(struct seq_file *m, void *unused) wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm); - drm_modeset_lock_all(dev); + drm_modeset_lock_all(&dev_priv->drm); seq_printf(m, "CRTC info\n"); seq_printf(m, "---------\n"); - for_each_intel_crtc(dev, crtc) + for_each_intel_crtc(&dev_priv->drm, crtc) intel_crtc_info(m, crtc); seq_printf(m, "\n"); seq_printf(m, "Connector info\n"); seq_printf(m, "--------------\n"); - drm_connector_list_iter_begin(dev, &conn_iter); + drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter); drm_for_each_connector_iter(connector, &conn_iter) intel_connector_info(m, connector); drm_connector_list_iter_end(&conn_iter); - drm_modeset_unlock_all(dev); + drm_modeset_unlock_all(&dev_priv->drm); intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref); @@ -931,10 +929,9 @@ static int i915_display_info(struct seq_file *m, void *unused) static int i915_shared_dplls_info(struct seq_file *m, void *unused) { struct drm_i915_private *dev_priv = node_to_i915(m->private); - struct drm_device *dev = &dev_priv->drm; int i; - drm_modeset_lock_all(dev); + drm_modeset_lock_all(&dev_priv->drm); seq_printf(m, "PLL refclks: non-SSC: %d kHz, SSC: %d kHz\n", dev_priv->display.dpll.ref_clks.nssc, @@ -979,7 +976,7 @@ static int i915_shared_dplls_info(struct seq_file *m, void *unused) seq_printf(m, " mg_pll_tdc_coldst_bias: 0x%08x\n", pll->state.hw_state.mg_pll_tdc_coldst_bias); } - drm_modeset_unlock_all(dev); + drm_modeset_unlock_all(&dev_priv->drm); return 0; } @@ -987,14 +984,13 @@ static int i915_shared_dplls_info(struct seq_file *m, void *unused) static int i915_ddb_info(struct seq_file *m, void *unused) { struct drm_i915_private *dev_priv = node_to_i915(m->private); - struct drm_device *dev = &dev_priv->drm; struct skl_ddb_entry *entry; struct intel_crtc *crtc; if (DISPLAY_VER(dev_priv) < 9) return -ENODEV; - drm_modeset_lock_all(dev); + drm_modeset_lock_all(&dev_priv->drm); seq_printf(m, "%-15s%8s%8s%8s\n", "", "Start", "End", "Size"); @@ -1018,7 +1014,7 @@ static int i915_ddb_info(struct seq_file *m, void *unused) entry->end, skl_ddb_entry_size(entry)); } - drm_modeset_unlock_all(dev); + drm_modeset_unlock_all(&dev_priv->drm); return 0; } @@ -1062,13 +1058,12 @@ static int i915_lpsp_status(struct seq_file *m, void *unused) static int i915_dp_mst_info(struct seq_file *m, void *unused) { struct drm_i915_private *dev_priv = node_to_i915(m->private); - struct drm_device *dev = &dev_priv->drm; struct intel_encoder *intel_encoder; struct intel_digital_port *dig_port; struct drm_connector *connector; struct drm_connector_list_iter conn_iter; - drm_connector_list_iter_begin(dev, &conn_iter); + drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter); drm_for_each_connector_iter(connector, &conn_iter) { if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) continue; @@ -1155,12 +1150,11 @@ static ssize_t i915_displayport_test_active_write(struct file *file, static int i915_displayport_test_active_show(struct seq_file *m, void *data) { struct drm_i915_private *dev_priv = m->private; - struct drm_device *dev = &dev_priv->drm; struct drm_connector *connector; struct drm_connector_list_iter conn_iter; struct intel_dp *intel_dp; - drm_connector_list_iter_begin(dev, &conn_iter); + drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter); drm_for_each_connector_iter(connector, &conn_iter) { struct intel_encoder *encoder; @@ -1205,12 +1199,11 @@ static const struct file_operations i915_displayport_test_active_fops = { static int i915_displayport_test_data_show(struct seq_file *m, void *data) { struct drm_i915_private *dev_priv = m->private; - struct drm_device *dev = &dev_priv->drm; struct drm_connector *connector; struct drm_connector_list_iter conn_iter; struct intel_dp *intel_dp; - drm_connector_list_iter_begin(dev, &conn_iter); + drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter); drm_for_each_connector_iter(connector, &conn_iter) { struct intel_encoder *encoder; @@ -1259,12 +1252,11 @@ DEFINE_SHOW_ATTRIBUTE(i915_displayport_test_data); static int i915_displayport_test_type_show(struct seq_file *m, void *data) { struct drm_i915_private *dev_priv = m->private; - struct drm_device *dev = &dev_priv->drm; struct drm_connector *connector; struct drm_connector_list_iter conn_iter; struct intel_dp *intel_dp; - drm_connector_list_iter_begin(dev, &conn_iter); + drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter); drm_for_each_connector_iter(connector, &conn_iter) { struct intel_encoder *encoder; @@ -1291,7 +1283,6 @@ DEFINE_SHOW_ATTRIBUTE(i915_displayport_test_type); static void wm_latency_show(struct seq_file *m, const u16 wm[8]) { struct drm_i915_private *dev_priv = m->private; - struct drm_device *dev = &dev_priv->drm; int level; int num_levels; @@ -1304,7 +1295,7 @@ static void wm_latency_show(struct seq_file *m, const u16 wm[8]) else num_levels = ilk_wm_max_level(dev_priv) + 1; - drm_modeset_lock_all(dev); + drm_modeset_lock_all(&dev_priv->drm); for (level = 0; level < num_levels; level++) { unsigned int latency = wm[level]; @@ -1325,7 +1316,7 @@ static void wm_latency_show(struct seq_file *m, const u16 wm[8]) level, wm[level], latency / 10, latency % 10); } - drm_modeset_unlock_all(dev); + drm_modeset_unlock_all(&dev_priv->drm); } static int pri_wm_latency_show(struct seq_file *m, void *data) @@ -1408,7 +1399,6 @@ static ssize_t wm_latency_write(struct file *file, const char __user *ubuf, { struct seq_file *m = file->private_data; struct drm_i915_private *dev_priv = m->private; - struct drm_device *dev = &dev_priv->drm; u16 new[8] = { 0 }; int num_levels; int level; @@ -1438,12 +1428,12 @@ static ssize_t wm_latency_write(struct file *file, const char __user *ubuf, if (ret != num_levels) return -EINVAL; - drm_modeset_lock_all(dev); + drm_modeset_lock_all(&dev_priv->drm); for (level = 0; level < num_levels; level++) wm[level] = new[level]; - drm_modeset_unlock_all(dev); + drm_modeset_unlock_all(&dev_priv->drm); return len; } @@ -1528,7 +1518,6 @@ i915_fifo_underrun_reset_write(struct file *filp, { struct drm_i915_private *dev_priv = filp->private_data; struct intel_crtc *crtc; - struct drm_device *dev = &dev_priv->drm; int ret; bool reset; @@ -1539,7 +1528,7 @@ i915_fifo_underrun_reset_write(struct file *filp, if (!reset) return cnt; - for_each_intel_crtc(dev, crtc) { + for_each_intel_crtc(&dev_priv->drm, crtc) { struct drm_crtc_commit *commit; struct intel_crtc_state *crtc_state; diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index 1e608b9e5055..4c1de91e56ff 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -1148,10 +1148,9 @@ static void hsw_assert_cdclk(struct drm_i915_private *dev_priv) static void assert_can_disable_lcpll(struct drm_i915_private *dev_priv) { - struct drm_device *dev = &dev_priv->drm; struct intel_crtc *crtc; - for_each_intel_crtc(dev, crtc) + for_each_intel_crtc(&dev_priv->drm, crtc) I915_STATE_WARN(crtc->active, "CRTC for pipe %c enabled\n", pipe_name(crtc->pipe)); diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 70b06806ec0d..a060903891b2 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -5229,7 +5229,6 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, struct intel_connector *intel_connector) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); - struct drm_device *dev = &dev_priv->drm; struct drm_connector *connector = &intel_connector->base; struct drm_display_mode *fixed_mode; struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; @@ -5246,7 +5245,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, * with an already powered-on LVDS power sequencer. */ if (intel_get_lvds_encoder(dev_priv)) { - drm_WARN_ON(dev, + drm_WARN_ON(&dev_priv->drm, !(HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv))); drm_info(&dev_priv->drm, "LVDS was detected, not registering eDP\n"); @@ -5267,7 +5266,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, goto out_vdd_off; } - mutex_lock(&dev->mode_config.mutex); + mutex_lock(&dev_priv->drm.mode_config.mutex); edid = drm_get_edid(connector, &intel_dp->aux.ddc); if (!edid) { /* Fallback to EDID from ACPI OpRegion, if any */ @@ -5305,7 +5304,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, if (!intel_panel_preferred_fixed_mode(intel_connector)) intel_panel_add_vbt_lfp_fixed_mode(intel_connector); - mutex_unlock(&dev->mode_config.mutex); + mutex_unlock(&dev_priv->drm.mode_config.mutex); if (!intel_panel_preferred_fixed_mode(intel_connector)) { drm_info(&dev_priv->drm, diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.c b/drivers/gpu/drm/i915/display/intel_hotplug.c index 352a1b53b63e..907ab7526cb4 100644 --- a/drivers/gpu/drm/i915/display/intel_hotplug.c +++ b/drivers/gpu/drm/i915/display/intel_hotplug.c @@ -178,14 +178,13 @@ static bool intel_hpd_irq_storm_detect(struct drm_i915_private *dev_priv, static void intel_hpd_irq_storm_switch_to_polling(struct drm_i915_private *dev_priv) { - struct drm_device *dev = &dev_priv->drm; struct drm_connector_list_iter conn_iter; struct intel_connector *connector; bool hpd_disabled = false; lockdep_assert_held(&dev_priv->irq_lock); - drm_connector_list_iter_begin(dev, &conn_iter); + drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter); for_each_intel_connector_iter(connector, &conn_iter) { enum hpd_pin pin; @@ -211,7 +210,7 @@ intel_hpd_irq_storm_switch_to_polling(struct drm_i915_private *dev_priv) /* Enable polling and queue hotplug re-enabling. */ if (hpd_disabled) { - drm_kms_helper_poll_enable(dev); + drm_kms_helper_poll_enable(&dev_priv->drm); mod_delayed_work(system_wq, &dev_priv->display.hotplug.reenable_work, msecs_to_jiffies(HPD_STORM_REENABLE_DELAY)); } @@ -222,7 +221,6 @@ static void intel_hpd_irq_storm_reenable_work(struct work_struct *work) struct drm_i915_private *dev_priv = container_of(work, typeof(*dev_priv), display.hotplug.reenable_work.work); - struct drm_device *dev = &dev_priv->drm; struct drm_connector_list_iter conn_iter; struct intel_connector *connector; intel_wakeref_t wakeref; @@ -232,7 +230,7 @@ static void intel_hpd_irq_storm_reenable_work(struct work_struct *work) spin_lock_irq(&dev_priv->irq_lock); - drm_connector_list_iter_begin(dev, &conn_iter); + drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter); for_each_intel_connector_iter(connector, &conn_iter) { pin = intel_connector_hpd_pin(connector); if (pin == HPD_NONE || @@ -370,14 +368,13 @@ static void i915_hotplug_work_func(struct work_struct *work) struct drm_i915_private *dev_priv = container_of(work, struct drm_i915_private, display.hotplug.hotplug_work.work); - struct drm_device *dev = &dev_priv->drm; struct drm_connector_list_iter conn_iter; struct intel_connector *connector; u32 changed = 0, retry = 0; u32 hpd_event_bits; u32 hpd_retry_bits; - mutex_lock(&dev->mode_config.mutex); + mutex_lock(&dev_priv->drm.mode_config.mutex); drm_dbg_kms(&dev_priv->drm, "running encoder hotplug functions\n"); spin_lock_irq(&dev_priv->irq_lock); @@ -392,7 +389,7 @@ static void i915_hotplug_work_func(struct work_struct *work) spin_unlock_irq(&dev_priv->irq_lock); - drm_connector_list_iter_begin(dev, &conn_iter); + drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter); for_each_intel_connector_iter(connector, &conn_iter) { enum hpd_pin pin; u32 hpd_bit; @@ -429,10 +426,10 @@ static void i915_hotplug_work_func(struct work_struct *work) } } drm_connector_list_iter_end(&conn_iter); - mutex_unlock(&dev->mode_config.mutex); + mutex_unlock(&dev_priv->drm.mode_config.mutex); if (changed) - drm_kms_helper_hotplug_event(dev); + drm_kms_helper_hotplug_event(&dev_priv->drm); /* Remove shared HPD pins that have changed */ retry &= ~changed; @@ -615,16 +612,15 @@ static void i915_hpd_poll_init_work(struct work_struct *work) struct drm_i915_private *dev_priv = container_of(work, struct drm_i915_private, display.hotplug.poll_init_work); - struct drm_device *dev = &dev_priv->drm; struct drm_connector_list_iter conn_iter; struct intel_connector *connector; bool enabled; - mutex_lock(&dev->mode_config.mutex); + mutex_lock(&dev_priv->drm.mode_config.mutex); enabled = READ_ONCE(dev_priv->display.hotplug.poll_enabled); - drm_connector_list_iter_begin(dev, &conn_iter); + drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter); for_each_intel_connector_iter(connector, &conn_iter) { enum hpd_pin pin; @@ -641,16 +637,16 @@ static void i915_hpd_poll_init_work(struct work_struct *work) drm_connector_list_iter_end(&conn_iter); if (enabled) - drm_kms_helper_poll_enable(dev); + drm_kms_helper_poll_enable(&dev_priv->drm); - mutex_unlock(&dev->mode_config.mutex); + mutex_unlock(&dev_priv->drm.mode_config.mutex); /* * We might have missed any hotplugs that happened while we were * in the middle of disabling polling */ if (!enabled) - drm_helper_hpd_irq_event(dev); + drm_helper_hpd_irq_event(&dev_priv->drm); } /** diff --git a/drivers/gpu/drm/i915/display/intel_lpe_audio.c b/drivers/gpu/drm/i915/display/intel_lpe_audio.c index dca6003ccac8..6a7ac60e4f76 100644 --- a/drivers/gpu/drm/i915/display/intel_lpe_audio.c +++ b/drivers/gpu/drm/i915/display/intel_lpe_audio.c @@ -80,8 +80,7 @@ static struct platform_device * lpe_audio_platdev_create(struct drm_i915_private *dev_priv) { - struct drm_device *dev = &dev_priv->drm; - struct pci_dev *pdev = to_pci_dev(dev->dev); + struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); struct platform_device_info pinfo = {}; struct resource *rsc; struct platform_device *platdev; @@ -108,7 +107,7 @@ lpe_audio_platdev_create(struct drm_i915_private *dev_priv) rsc[1].flags = IORESOURCE_MEM; rsc[1].name = "hdmi-lpe-audio-mmio"; - pinfo.parent = dev->dev; + pinfo.parent = dev_priv->drm.dev; pinfo.name = "hdmi-lpe-audio"; pinfo.id = -1; pinfo.res = rsc; diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c index e97e24f690a9..246787bbf5ef 100644 --- a/drivers/gpu/drm/i915/display/intel_lvds.c +++ b/drivers/gpu/drm/i915/display/intel_lvds.c @@ -828,7 +828,6 @@ static void intel_lvds_add_properties(struct drm_connector *connector) */ void intel_lvds_init(struct drm_i915_private *dev_priv) { - struct drm_device *dev = &dev_priv->drm; struct intel_lvds_encoder *lvds_encoder; struct intel_encoder *intel_encoder; struct intel_connector *intel_connector; @@ -841,7 +840,7 @@ void intel_lvds_init(struct drm_i915_private *dev_priv) /* Skip init on machines we know falsely report LVDS */ if (dmi_check_system(intel_no_lvds)) { - drm_WARN(dev, !dev_priv->display.vbt.int_lvds_support, + drm_WARN(&dev_priv->drm, !dev_priv->display.vbt.int_lvds_support, "Useless DMI match. Internal LVDS support disabled by VBT\n"); return; } @@ -890,10 +889,10 @@ void intel_lvds_init(struct drm_i915_private *dev_priv) intel_encoder = &lvds_encoder->base; encoder = &intel_encoder->base; connector = &intel_connector->base; - drm_connector_init(dev, &intel_connector->base, &intel_lvds_connector_funcs, + drm_connector_init(&dev_priv->drm, &intel_connector->base, &intel_lvds_connector_funcs, DRM_MODE_CONNECTOR_LVDS); - drm_encoder_init(dev, &intel_encoder->base, &intel_lvds_enc_funcs, + drm_encoder_init(&dev_priv->drm, &intel_encoder->base, &intel_lvds_enc_funcs, DRM_MODE_ENCODER_LVDS, "LVDS"); intel_encoder->enable = intel_enable_lvds; @@ -944,7 +943,7 @@ void intel_lvds_init(struct drm_i915_private *dev_priv) * Attempt to get the fixed panel mode from DDC. Assume that the * preferred mode is the right one. */ - mutex_lock(&dev->mode_config.mutex); + mutex_lock(&dev_priv->drm.mode_config.mutex); if (vga_switcheroo_handler_flags() & VGA_SWITCHEROO_CAN_SWITCH_DDC) edid = drm_get_edid_switcheroo(connector, intel_gmbus_get_adapter(dev_priv, pin)); @@ -982,7 +981,7 @@ void intel_lvds_init(struct drm_i915_private *dev_priv) if (!intel_panel_preferred_fixed_mode(intel_connector)) intel_panel_add_encoder_fixed_mode(intel_connector, intel_encoder); - mutex_unlock(&dev->mode_config.mutex); + mutex_unlock(&dev_priv->drm.mode_config.mutex); /* If we still don't have a mode after all that, give up. */ if (!intel_panel_preferred_fixed_mode(intel_connector)) diff --git a/drivers/gpu/drm/i915/display/intel_opregion.c b/drivers/gpu/drm/i915/display/intel_opregion.c index caa07ef34f21..e0184745632c 100644 --- a/drivers/gpu/drm/i915/display/intel_opregion.c +++ b/drivers/gpu/drm/i915/display/intel_opregion.c @@ -463,7 +463,6 @@ static u32 asle_set_backlight(struct drm_i915_private *dev_priv, u32 bclp) struct intel_connector *connector; struct drm_connector_list_iter conn_iter; struct opregion_asle *asle = dev_priv->display.opregion.asle; - struct drm_device *dev = &dev_priv->drm; drm_dbg(&dev_priv->drm, "bclp = 0x%08x\n", bclp); @@ -480,7 +479,7 @@ static u32 asle_set_backlight(struct drm_i915_private *dev_priv, u32 bclp) if (bclp > 255) return ASLC_BACKLIGHT_FAILED; - drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); + drm_modeset_lock(&dev_priv->drm.mode_config.connection_mutex, NULL); /* * Update backlight on all connectors that support backlight (usually @@ -488,13 +487,13 @@ static u32 asle_set_backlight(struct drm_i915_private *dev_priv, u32 bclp) */ drm_dbg_kms(&dev_priv->drm, "updating opregion backlight %d/255\n", bclp); - drm_connector_list_iter_begin(dev, &conn_iter); + drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter); for_each_intel_connector_iter(connector, &conn_iter) intel_backlight_set_acpi(connector->base.state, bclp, 255); drm_connector_list_iter_end(&conn_iter); asle->cblv = DIV_ROUND_UP(bclp * 100, 255) | ASLE_CBLV_VALID; - drm_modeset_unlock(&dev->mode_config.connection_mutex); + drm_modeset_unlock(&dev_priv->drm.mode_config.connection_mutex); return 0; diff --git a/drivers/gpu/drm/i915/display/intel_pipe_crc.c b/drivers/gpu/drm/i915/display/intel_pipe_crc.c index 8ac263f471be..1c74388c60d7 100644 --- a/drivers/gpu/drm/i915/display/intel_pipe_crc.c +++ b/drivers/gpu/drm/i915/display/intel_pipe_crc.c @@ -75,7 +75,6 @@ static int i9xx_pipe_crc_auto_source(struct drm_i915_private *dev_priv, enum pipe pipe, enum intel_pipe_crc_source *source) { - struct drm_device *dev = &dev_priv->drm; struct intel_encoder *encoder; struct intel_crtc *crtc; struct intel_digital_port *dig_port; @@ -83,8 +82,8 @@ static int i9xx_pipe_crc_auto_source(struct drm_i915_private *dev_priv, *source = INTEL_PIPE_CRC_SOURCE_PIPE; - drm_modeset_lock_all(dev); - for_each_intel_encoder(dev, encoder) { + drm_modeset_lock_all(&dev_priv->drm); + for_each_intel_encoder(&dev_priv->drm, encoder) { if (!encoder->base.crtc) continue; @@ -111,7 +110,7 @@ static int i9xx_pipe_crc_auto_source(struct drm_i915_private *dev_priv, *source = INTEL_PIPE_CRC_SOURCE_DP_D; break; default: - drm_WARN(dev, 1, "nonexisting DP port %c\n", + drm_WARN(&dev_priv->drm, 1, "nonexisting DP port %c\n", port_name(dig_port->base.port)); break; } @@ -120,7 +119,7 @@ static int i9xx_pipe_crc_auto_source(struct drm_i915_private *dev_priv, break; } } - drm_modeset_unlock_all(dev); + drm_modeset_unlock_all(&dev_priv->drm); return ret; } diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 16cf17b1e9d9..904a1049eff3 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -2063,13 +2063,12 @@ static bool __psr_wait_for_idle_locked(struct intel_dp *intel_dp) static int intel_psr_fastset_force(struct drm_i915_private *dev_priv) { struct drm_connector_list_iter conn_iter; - struct drm_device *dev = &dev_priv->drm; struct drm_modeset_acquire_ctx ctx; struct drm_atomic_state *state; struct drm_connector *conn; int err = 0; - state = drm_atomic_state_alloc(dev); + state = drm_atomic_state_alloc(&dev_priv->drm); if (!state) return -ENOMEM; @@ -2078,7 +2077,7 @@ static int intel_psr_fastset_force(struct drm_i915_private *dev_priv) retry: - drm_connector_list_iter_begin(dev, &conn_iter); + drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter); drm_for_each_connector_iter(conn, &conn_iter) { struct drm_connector_state *conn_state; struct drm_crtc_state *crtc_state; diff --git a/drivers/gpu/drm/i915/display/intel_tv.c b/drivers/gpu/drm/i915/display/intel_tv.c index b2e93c2ad8f3..cf7d5c1ab406 100644 --- a/drivers/gpu/drm/i915/display/intel_tv.c +++ b/drivers/gpu/drm/i915/display/intel_tv.c @@ -1925,7 +1925,6 @@ static void intel_tv_add_properties(struct drm_connector *connector) void intel_tv_init(struct drm_i915_private *dev_priv) { - struct drm_device *dev = &dev_priv->drm; struct drm_connector *connector; struct intel_tv *intel_tv; struct intel_encoder *intel_encoder; @@ -1989,10 +1988,10 @@ intel_tv_init(struct drm_i915_private *dev_priv) */ intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT; - drm_connector_init(dev, connector, &intel_tv_connector_funcs, + drm_connector_init(&dev_priv->drm, connector, &intel_tv_connector_funcs, DRM_MODE_CONNECTOR_SVIDEO); - drm_encoder_init(dev, &intel_encoder->base, &intel_tv_enc_funcs, + drm_encoder_init(&dev_priv->drm, &intel_encoder->base, &intel_tv_enc_funcs, DRM_MODE_ENCODER_TVDAC, "TV"); intel_encoder->compute_config = intel_tv_compute_config; diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c index dee0147a316c..5a741ea4505f 100644 --- a/drivers/gpu/drm/i915/display/vlv_dsi.c +++ b/drivers/gpu/drm/i915/display/vlv_dsi.c @@ -1845,7 +1845,6 @@ static void vlv_dphy_param_init(struct intel_dsi *intel_dsi) void vlv_dsi_init(struct drm_i915_private *dev_priv) { - struct drm_device *dev = &dev_priv->drm; struct intel_dsi *intel_dsi; struct intel_encoder *intel_encoder; struct drm_encoder *encoder; @@ -1882,7 +1881,7 @@ void vlv_dsi_init(struct drm_i915_private *dev_priv) connector = &intel_connector->base; - drm_encoder_init(dev, encoder, &intel_dsi_funcs, DRM_MODE_ENCODER_DSI, + drm_encoder_init(&dev_priv->drm, encoder, &intel_dsi_funcs, DRM_MODE_ENCODER_DSI, "DSI %c", port_name(port)); intel_encoder->compute_config = intel_dsi_compute_config; @@ -1965,7 +1964,7 @@ void vlv_dsi_init(struct drm_i915_private *dev_priv) intel_dsi_vbt_gpio_init(intel_dsi, intel_dsi_get_hw_state(intel_encoder, &pipe)); - drm_connector_init(dev, connector, &intel_dsi_connector_funcs, + drm_connector_init(&dev_priv->drm, connector, &intel_dsi_connector_funcs, DRM_MODE_CONNECTOR_DSI); drm_connector_helper_add(connector, &intel_dsi_connector_helper_funcs); @@ -1974,9 +1973,9 @@ void vlv_dsi_init(struct drm_i915_private *dev_priv) intel_connector_attach_encoder(intel_connector, intel_encoder); - mutex_lock(&dev->mode_config.mutex); + mutex_lock(&dev_priv->drm.mode_config.mutex); intel_panel_add_vbt_lfp_fixed_mode(intel_connector); - mutex_unlock(&dev->mode_config.mutex); + mutex_unlock(&dev_priv->drm.mode_config.mutex); if (!intel_panel_preferred_fixed_mode(intel_connector)) { drm_dbg_kms(&dev_priv->drm, "no fixed mode\n"); diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c index 764026d1c5c8..e7b2ebc6b88d 100644 --- a/drivers/gpu/drm/i915/i915_driver.c +++ b/drivers/gpu/drm/i915/i915_driver.c @@ -716,15 +716,13 @@ static void i915_driver_hw_remove(struct drm_i915_private *dev_priv) */ static void i915_driver_register(struct drm_i915_private *dev_priv) { - struct drm_device *dev = &dev_priv->drm; - i915_gem_driver_register(dev_priv); i915_pmu_register(dev_priv); intel_vgpu_register(dev_priv); /* Reveal our presence to userspace */ - if (drm_dev_register(dev, 0)) { + if (drm_dev_register(&dev_priv->drm, 0)) { drm_err(&dev_priv->drm, "Failed to register driver for userspace access!\n"); return; @@ -1056,32 +1054,30 @@ static void i915_driver_postclose(struct drm_device *dev, struct drm_file *file) static void intel_suspend_encoders(struct drm_i915_private *dev_priv) { - struct drm_device *dev = &dev_priv->drm; struct intel_encoder *encoder; if (!HAS_DISPLAY(dev_priv)) return; - drm_modeset_lock_all(dev); - for_each_intel_encoder(dev, encoder) + drm_modeset_lock_all(&dev_priv->drm); + for_each_intel_encoder(&dev_priv->drm, encoder) if (encoder->suspend) encoder->suspend(encoder); - drm_modeset_unlock_all(dev); + drm_modeset_unlock_all(&dev_priv->drm); } static void intel_shutdown_encoders(struct drm_i915_private *dev_priv) { - struct drm_device *dev = &dev_priv->drm; struct intel_encoder *encoder; if (!HAS_DISPLAY(dev_priv)) return; - drm_modeset_lock_all(dev); - for_each_intel_encoder(dev, encoder) + drm_modeset_lock_all(&dev_priv->drm); + for_each_intel_encoder(&dev_priv->drm, encoder) if (encoder->shutdown) encoder->shutdown(encoder); - drm_modeset_unlock_all(dev); + drm_modeset_unlock_all(&dev_priv->drm); } void i915_driver_shutdown(struct drm_i915_private *i915) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 8c301b1682b4..5464225d2f53 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -4384,7 +4384,6 @@ void intel_hpd_irq_setup(struct drm_i915_private *i915) */ void intel_irq_init(struct drm_i915_private *dev_priv) { - struct drm_device *dev = &dev_priv->drm; int i; INIT_WORK(&dev_priv->l3_parity.error_work, ivb_parity_work); @@ -4402,7 +4401,7 @@ void intel_irq_init(struct drm_i915_private *dev_priv) intel_hpd_init_early(dev_priv); - dev->vblank_disable_immediate = true; + dev_priv->drm.vblank_disable_immediate = true; /* Most platforms treat the display irq block as an always-on * power domain. vlv/chv can disable it at runtime and need -- cgit From e58c2cac2c21f2785d4ab9f4ddf6d9e7a92dd8e7 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Thu, 6 Oct 2022 18:31:58 +0200 Subject: drm/i915/display: Use intel_uncore alias if defined Alias is shorter and more readable. Signed-off-by: Andrzej Hajda Reviewed-by: Andi Shyti Signed-off-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20221006163200.2803722-3-andrzej.hajda@intel.com --- drivers/gpu/drm/i915/i915_irq.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 5464225d2f53..30860e03ab66 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -3020,7 +3020,7 @@ static void vlv_display_irq_reset(struct drm_i915_private *dev_priv) intel_uncore_write(uncore, DPINVGTT, DPINVGTT_STATUS_MASK_VLV); i915_hotplug_interrupt_update_locked(dev_priv, 0xffffffff, 0); - intel_uncore_write(uncore, PORT_HOTPLUG_STAT, intel_uncore_read(&dev_priv->uncore, PORT_HOTPLUG_STAT)); + intel_uncore_write(uncore, PORT_HOTPLUG_STAT, intel_uncore_read(uncore, PORT_HOTPLUG_STAT)); i9xx_pipestat_irq_reset(dev_priv); @@ -3118,7 +3118,7 @@ static void gen8_irq_reset(struct drm_i915_private *dev_priv) { struct intel_uncore *uncore = &dev_priv->uncore; - gen8_master_intr_disable(dev_priv->uncore.regs); + gen8_master_intr_disable(uncore->regs); gen8_gt_irq_reset(to_gt(dev_priv)); gen8_display_irq_reset(dev_priv); @@ -3250,7 +3250,7 @@ static void cherryview_irq_reset(struct drm_i915_private *dev_priv) { struct intel_uncore *uncore = &dev_priv->uncore; - intel_uncore_write(&dev_priv->uncore, GEN8_MASTER_IRQ, 0); + intel_uncore_write(uncore, GEN8_MASTER_IRQ, 0); intel_uncore_posting_read(&dev_priv->uncore, GEN8_MASTER_IRQ); gen8_gt_irq_reset(to_gt(dev_priv)); @@ -4110,8 +4110,8 @@ static void i915_irq_postinstall(struct drm_i915_private *dev_priv) struct intel_uncore *uncore = &dev_priv->uncore; u32 enable_mask; - intel_uncore_write(&dev_priv->uncore, EMR, ~(I915_ERROR_PAGE_TABLE | - I915_ERROR_MEMORY_REFRESH)); + intel_uncore_write(uncore, EMR, ~(I915_ERROR_PAGE_TABLE | + I915_ERROR_MEMORY_REFRESH)); /* Unmask the interrupts that we always want on. */ dev_priv->irq_mask = @@ -4206,7 +4206,7 @@ static void i965_irq_reset(struct drm_i915_private *dev_priv) struct intel_uncore *uncore = &dev_priv->uncore; i915_hotplug_interrupt_update(dev_priv, 0xffffffff, 0); - intel_uncore_write(&dev_priv->uncore, PORT_HOTPLUG_STAT, intel_uncore_read(&dev_priv->uncore, PORT_HOTPLUG_STAT)); + intel_uncore_write(uncore, PORT_HOTPLUG_STAT, intel_uncore_read(uncore, PORT_HOTPLUG_STAT)); i9xx_pipestat_irq_reset(dev_priv); @@ -4233,7 +4233,7 @@ static void i965_irq_postinstall(struct drm_i915_private *dev_priv) error_mask = ~(I915_ERROR_PAGE_TABLE | I915_ERROR_MEMORY_REFRESH); } - intel_uncore_write(&dev_priv->uncore, EMR, error_mask); + intel_uncore_write(uncore, EMR, error_mask); /* Unmask the interrupts that we always want on. */ dev_priv->irq_mask = -- cgit From 06b975d58fd6105e3fad8b3a1122749f79dd7df3 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Thu, 6 Oct 2022 18:31:59 +0200 Subject: drm/i915: make intel_uncore_rmw() write unconditionally Two small changes in intel_uncore_rmw will allow to use it more broadly: - write register unconditionally, for use with latch registers, - return old value of the register, IRQ cleanup and similar. If we really want to keep write-only-if-changed feature maybe other helper will be more suitable for it, intel_uncore_rmw name suggests unconditional write. Signed-off-by: Andrzej Hajda Reviewed-by: Andi Shyti Acked-by: Jani Nikula Signed-off-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20221006163200.2803722-4-andrzej.hajda@intel.com --- drivers/gpu/drm/i915/intel_uncore.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.h b/drivers/gpu/drm/i915/intel_uncore.h index b1fa912a65e7..ca741206887f 100644 --- a/drivers/gpu/drm/i915/intel_uncore.h +++ b/drivers/gpu/drm/i915/intel_uncore.h @@ -413,15 +413,15 @@ intel_uncore_read64_2x32(struct intel_uncore *uncore, #define intel_uncore_write64_fw(...) __raw_uncore_write64(__VA_ARGS__) #define intel_uncore_posting_read_fw(...) ((void)intel_uncore_read_fw(__VA_ARGS__)) -static inline void intel_uncore_rmw(struct intel_uncore *uncore, - i915_reg_t reg, u32 clear, u32 set) +static inline u32 intel_uncore_rmw(struct intel_uncore *uncore, + i915_reg_t reg, u32 clear, u32 set) { u32 old, val; old = intel_uncore_read(uncore, reg); val = (old & ~clear) | set; - if (val != old) - intel_uncore_write(uncore, reg, val); + intel_uncore_write(uncore, reg, val); + return old; } static inline void intel_uncore_rmw_fw(struct intel_uncore *uncore, -- cgit From 8cee664d3eb6f80eb7ecc46b9a32214f0fe629d3 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Thu, 6 Oct 2022 18:32:00 +0200 Subject: drm/i915: use proper helper for register updates There is special helper for register read/modify/write. Signed-off-by: Andrzej Hajda Reviewed-by: Andi Shyti Signed-off-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20221006163200.2803722-5-andrzej.hajda@intel.com --- drivers/gpu/drm/i915/display/intel_tc.c | 9 +- drivers/gpu/drm/i915/i915_irq.c | 227 ++++++++++++-------------------- drivers/gpu/drm/i915/intel_pm.c | 60 +++------ drivers/gpu/drm/i915/vlv_suspend.c | 28 ++-- 4 files changed, 112 insertions(+), 212 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index b0aa1edd8302..8cecd41ed003 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -408,14 +408,9 @@ static bool adl_tc_phy_take_ownership(struct intel_digital_port *dig_port, struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); struct intel_uncore *uncore = &i915->uncore; enum port port = dig_port->base.port; - u32 val; - val = intel_uncore_read(uncore, DDI_BUF_CTL(port)); - if (take) - val |= DDI_BUF_CTL_TC_PHY_OWNERSHIP; - else - val &= ~DDI_BUF_CTL_TC_PHY_OWNERSHIP; - intel_uncore_write(uncore, DDI_BUF_CTL(port), val); + intel_uncore_rmw(uncore, DDI_BUF_CTL(port), DDI_BUF_CTL_TC_PHY_OWNERSHIP, + take ? DDI_BUF_CTL_TC_PHY_OWNERSHIP : 0); return true; } diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 30860e03ab66..2048ee10af33 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -325,15 +325,10 @@ i915_hotplug_interrupt_update_locked(struct drm_i915_private *dev_priv, u32 mask, u32 bits) { - u32 val; - lockdep_assert_held(&dev_priv->irq_lock); drm_WARN_ON(&dev_priv->drm, bits & ~mask); - val = intel_uncore_read(&dev_priv->uncore, PORT_HOTPLUG_EN); - val &= ~mask; - val |= bits; - intel_uncore_write(&dev_priv->uncore, PORT_HOTPLUG_EN, val); + intel_uncore_rmw(&dev_priv->uncore, PORT_HOTPLUG_EN, mask, bits); } /** @@ -1057,8 +1052,8 @@ static void ivb_parity_work(struct work_struct *work) if (drm_WARN_ON(&dev_priv->drm, !dev_priv->l3_parity.which_slice)) goto out; - misccpctl = intel_uncore_read(&dev_priv->uncore, GEN7_MISCCPCTL); - intel_uncore_write(&dev_priv->uncore, GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE); + misccpctl = intel_uncore_rmw(&dev_priv->uncore, GEN7_MISCCPCTL, ~GEN7_DOP_CLOCK_GATE_ENABLE, + 0); intel_uncore_posting_read(&dev_priv->uncore, GEN7_MISCCPCTL); while ((slice = ffs(dev_priv->l3_parity.which_slice)) != 0) { @@ -1689,8 +1684,7 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg) * bits this time around. */ intel_uncore_write(&dev_priv->uncore, VLV_MASTER_IER, 0); - ier = intel_uncore_read(&dev_priv->uncore, VLV_IER); - intel_uncore_write(&dev_priv->uncore, VLV_IER, 0); + ier = intel_uncore_rmw(&dev_priv->uncore, VLV_IER, ~0, 0); if (gt_iir) intel_uncore_write(&dev_priv->uncore, GTIIR, gt_iir); @@ -1775,8 +1769,7 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg) * bits this time around. */ intel_uncore_write(&dev_priv->uncore, GEN8_MASTER_IRQ, 0); - ier = intel_uncore_read(&dev_priv->uncore, VLV_IER); - intel_uncore_write(&dev_priv->uncore, VLV_IER, 0); + ier = intel_uncore_rmw(&dev_priv->uncore, VLV_IER, ~0, 0); gen8_gt_irq_handler(to_gt(dev_priv), master_ctl); @@ -1981,8 +1974,7 @@ static void icp_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir) if (ddi_hotplug_trigger) { u32 dig_hotplug_reg; - dig_hotplug_reg = intel_uncore_read(&dev_priv->uncore, SHOTPLUG_CTL_DDI); - intel_uncore_write(&dev_priv->uncore, SHOTPLUG_CTL_DDI, dig_hotplug_reg); + dig_hotplug_reg = intel_uncore_rmw(&dev_priv->uncore, SHOTPLUG_CTL_DDI, 0, 0); intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, ddi_hotplug_trigger, dig_hotplug_reg, @@ -1993,8 +1985,7 @@ static void icp_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir) if (tc_hotplug_trigger) { u32 dig_hotplug_reg; - dig_hotplug_reg = intel_uncore_read(&dev_priv->uncore, SHOTPLUG_CTL_TC); - intel_uncore_write(&dev_priv->uncore, SHOTPLUG_CTL_TC, dig_hotplug_reg); + dig_hotplug_reg = intel_uncore_rmw(&dev_priv->uncore, SHOTPLUG_CTL_TC, 0, 0); intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, tc_hotplug_trigger, dig_hotplug_reg, @@ -2019,8 +2010,7 @@ static void spt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir) if (hotplug_trigger) { u32 dig_hotplug_reg; - dig_hotplug_reg = intel_uncore_read(&dev_priv->uncore, PCH_PORT_HOTPLUG); - intel_uncore_write(&dev_priv->uncore, PCH_PORT_HOTPLUG, dig_hotplug_reg); + dig_hotplug_reg = intel_uncore_rmw(&dev_priv->uncore, PCH_PORT_HOTPLUG, 0, 0); intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, hotplug_trigger, dig_hotplug_reg, @@ -2031,8 +2021,7 @@ static void spt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir) if (hotplug2_trigger) { u32 dig_hotplug_reg; - dig_hotplug_reg = intel_uncore_read(&dev_priv->uncore, PCH_PORT_HOTPLUG2); - intel_uncore_write(&dev_priv->uncore, PCH_PORT_HOTPLUG2, dig_hotplug_reg); + dig_hotplug_reg = intel_uncore_rmw(&dev_priv->uncore, PCH_PORT_HOTPLUG2, 0, 0); intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, hotplug2_trigger, dig_hotplug_reg, @@ -2052,8 +2041,7 @@ static void ilk_hpd_irq_handler(struct drm_i915_private *dev_priv, { u32 dig_hotplug_reg, pin_mask = 0, long_mask = 0; - dig_hotplug_reg = intel_uncore_read(&dev_priv->uncore, DIGITAL_PORT_HOTPLUG_CNTRL); - intel_uncore_write(&dev_priv->uncore, DIGITAL_PORT_HOTPLUG_CNTRL, dig_hotplug_reg); + dig_hotplug_reg = intel_uncore_rmw(&dev_priv->uncore, DIGITAL_PORT_HOTPLUG_CNTRL, 0, 0); intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, hotplug_trigger, dig_hotplug_reg, @@ -2232,8 +2220,7 @@ static void bxt_hpd_irq_handler(struct drm_i915_private *dev_priv, { u32 dig_hotplug_reg, pin_mask = 0, long_mask = 0; - dig_hotplug_reg = intel_uncore_read(&dev_priv->uncore, PCH_PORT_HOTPLUG); - intel_uncore_write(&dev_priv->uncore, PCH_PORT_HOTPLUG, dig_hotplug_reg); + dig_hotplug_reg = intel_uncore_rmw(&dev_priv->uncore, PCH_PORT_HOTPLUG, 0, 0); intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, hotplug_trigger, dig_hotplug_reg, @@ -2252,8 +2239,7 @@ static void gen11_hpd_irq_handler(struct drm_i915_private *dev_priv, u32 iir) if (trigger_tc) { u32 dig_hotplug_reg; - dig_hotplug_reg = intel_uncore_read(&dev_priv->uncore, GEN11_TC_HOTPLUG_CTL); - intel_uncore_write(&dev_priv->uncore, GEN11_TC_HOTPLUG_CTL, dig_hotplug_reg); + dig_hotplug_reg = intel_uncore_rmw(&dev_priv->uncore, GEN11_TC_HOTPLUG_CTL, 0, 0); intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, trigger_tc, dig_hotplug_reg, @@ -2264,8 +2250,7 @@ static void gen11_hpd_irq_handler(struct drm_i915_private *dev_priv, u32 iir) if (trigger_tbt) { u32 dig_hotplug_reg; - dig_hotplug_reg = intel_uncore_read(&dev_priv->uncore, GEN11_TBT_HOTPLUG_CTL); - intel_uncore_write(&dev_priv->uncore, GEN11_TBT_HOTPLUG_CTL, dig_hotplug_reg); + dig_hotplug_reg = intel_uncore_rmw(&dev_priv->uncore, GEN11_TBT_HOTPLUG_CTL, 0, 0); intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, trigger_tbt, dig_hotplug_reg, @@ -2355,8 +2340,7 @@ gen8_de_misc_irq_handler(struct drm_i915_private *dev_priv, u32 iir) else iir_reg = EDP_PSR_IIR; - psr_iir = intel_uncore_read(&dev_priv->uncore, iir_reg); - intel_uncore_write(&dev_priv->uncore, iir_reg, psr_iir); + psr_iir = intel_uncore_rmw(&dev_priv->uncore, iir_reg, 0, 0); if (psr_iir) found = true; @@ -2426,8 +2410,7 @@ static void gen11_dsi_te_interrupt_handler(struct drm_i915_private *dev_priv, /* clear TE in dsi IIR */ port = (te_trigger & DSI1_TE) ? PORT_B : PORT_A; - tmp = intel_uncore_read(&dev_priv->uncore, DSI_INTR_IDENT_REG(port)); - intel_uncore_write(&dev_priv->uncore, DSI_INTR_IDENT_REG(port), tmp); + tmp = intel_uncore_rmw(&dev_priv->uncore, DSI_INTR_IDENT_REG(port), 0, 0); } static u32 gen8_de_pipe_flip_done_mask(struct drm_i915_private *i915) @@ -2884,7 +2867,6 @@ static bool gen11_dsi_configure_te(struct intel_crtc *intel_crtc, { struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev); enum port port; - u32 tmp; if (!(intel_crtc->mode_flags & (I915_MODE_FLAG_DSI_USE_TE1 | I915_MODE_FLAG_DSI_USE_TE0))) @@ -2896,16 +2878,10 @@ static bool gen11_dsi_configure_te(struct intel_crtc *intel_crtc, else port = PORT_A; - tmp = intel_uncore_read(&dev_priv->uncore, DSI_INTR_MASK_REG(port)); - if (enable) - tmp &= ~DSI_TE_EVENT; - else - tmp |= DSI_TE_EVENT; - - intel_uncore_write(&dev_priv->uncore, DSI_INTR_MASK_REG(port), tmp); + intel_uncore_rmw(&dev_priv->uncore, DSI_INTR_MASK_REG(port), DSI_TE_EVENT, + enable ? 0 : DSI_TE_EVENT); - tmp = intel_uncore_read(&dev_priv->uncore, DSI_INTR_IDENT_REG(port)); - intel_uncore_write(&dev_priv->uncore, DSI_INTR_IDENT_REG(port), tmp); + intel_uncore_rmw(&dev_priv->uncore, DSI_INTR_IDENT_REG(port), 0, 0); return true; } @@ -3020,7 +2996,7 @@ static void vlv_display_irq_reset(struct drm_i915_private *dev_priv) intel_uncore_write(uncore, DPINVGTT, DPINVGTT_STATUS_MASK_VLV); i915_hotplug_interrupt_update_locked(dev_priv, 0xffffffff, 0); - intel_uncore_write(uncore, PORT_HOTPLUG_STAT, intel_uncore_read(uncore, PORT_HOTPLUG_STAT)); + intel_uncore_rmw(uncore, PORT_HOTPLUG_STAT, 0, 0); i9xx_pipestat_irq_reset(dev_priv); @@ -3290,23 +3266,20 @@ static u32 ibx_hotplug_enables(struct drm_i915_private *i915, static void ibx_hpd_detection_setup(struct drm_i915_private *dev_priv) { - u32 hotplug; - /* * Enable digital hotplug on the PCH, and configure the DP short pulse * duration to 2ms (which is the minimum in the Display Port spec). * The pulse duration bits are reserved on LPT+. */ - hotplug = intel_uncore_read(&dev_priv->uncore, PCH_PORT_HOTPLUG); - hotplug &= ~(PORTA_HOTPLUG_ENABLE | - PORTB_HOTPLUG_ENABLE | - PORTC_HOTPLUG_ENABLE | - PORTD_HOTPLUG_ENABLE | - PORTB_PULSE_DURATION_MASK | - PORTC_PULSE_DURATION_MASK | - PORTD_PULSE_DURATION_MASK); - hotplug |= intel_hpd_hotplug_enables(dev_priv, ibx_hotplug_enables); - intel_uncore_write(&dev_priv->uncore, PCH_PORT_HOTPLUG, hotplug); + intel_uncore_rmw(&dev_priv->uncore, PCH_PORT_HOTPLUG, + PORTA_HOTPLUG_ENABLE | + PORTB_HOTPLUG_ENABLE | + PORTC_HOTPLUG_ENABLE | + PORTD_HOTPLUG_ENABLE | + PORTB_PULSE_DURATION_MASK | + PORTC_PULSE_DURATION_MASK | + PORTD_PULSE_DURATION_MASK, + intel_hpd_hotplug_enables(dev_priv, ibx_hotplug_enables)); } static void ibx_hpd_irq_setup(struct drm_i915_private *dev_priv) @@ -3353,30 +3326,24 @@ static u32 icp_tc_hotplug_enables(struct drm_i915_private *i915, static void icp_ddi_hpd_detection_setup(struct drm_i915_private *dev_priv) { - u32 hotplug; - - hotplug = intel_uncore_read(&dev_priv->uncore, SHOTPLUG_CTL_DDI); - hotplug &= ~(SHOTPLUG_CTL_DDI_HPD_ENABLE(HPD_PORT_A) | - SHOTPLUG_CTL_DDI_HPD_ENABLE(HPD_PORT_B) | - SHOTPLUG_CTL_DDI_HPD_ENABLE(HPD_PORT_C) | - SHOTPLUG_CTL_DDI_HPD_ENABLE(HPD_PORT_D)); - hotplug |= intel_hpd_hotplug_enables(dev_priv, icp_ddi_hotplug_enables); - intel_uncore_write(&dev_priv->uncore, SHOTPLUG_CTL_DDI, hotplug); + intel_uncore_rmw(&dev_priv->uncore, SHOTPLUG_CTL_DDI, + SHOTPLUG_CTL_DDI_HPD_ENABLE(HPD_PORT_A) | + SHOTPLUG_CTL_DDI_HPD_ENABLE(HPD_PORT_B) | + SHOTPLUG_CTL_DDI_HPD_ENABLE(HPD_PORT_C) | + SHOTPLUG_CTL_DDI_HPD_ENABLE(HPD_PORT_D), + intel_hpd_hotplug_enables(dev_priv, icp_ddi_hotplug_enables)); } static void icp_tc_hpd_detection_setup(struct drm_i915_private *dev_priv) { - u32 hotplug; - - hotplug = intel_uncore_read(&dev_priv->uncore, SHOTPLUG_CTL_TC); - hotplug &= ~(ICP_TC_HPD_ENABLE(HPD_PORT_TC1) | - ICP_TC_HPD_ENABLE(HPD_PORT_TC2) | - ICP_TC_HPD_ENABLE(HPD_PORT_TC3) | - ICP_TC_HPD_ENABLE(HPD_PORT_TC4) | - ICP_TC_HPD_ENABLE(HPD_PORT_TC5) | - ICP_TC_HPD_ENABLE(HPD_PORT_TC6)); - hotplug |= intel_hpd_hotplug_enables(dev_priv, icp_tc_hotplug_enables); - intel_uncore_write(&dev_priv->uncore, SHOTPLUG_CTL_TC, hotplug); + intel_uncore_rmw(&dev_priv->uncore, SHOTPLUG_CTL_TC, + ICP_TC_HPD_ENABLE(HPD_PORT_TC1) | + ICP_TC_HPD_ENABLE(HPD_PORT_TC2) | + ICP_TC_HPD_ENABLE(HPD_PORT_TC3) | + ICP_TC_HPD_ENABLE(HPD_PORT_TC4) | + ICP_TC_HPD_ENABLE(HPD_PORT_TC5) | + ICP_TC_HPD_ENABLE(HPD_PORT_TC6), + intel_hpd_hotplug_enables(dev_priv, icp_tc_hotplug_enables)); } static void icp_hpd_irq_setup(struct drm_i915_private *dev_priv) @@ -3428,46 +3395,37 @@ static void dg1_hpd_irq_setup(struct drm_i915_private *dev_priv) static void gen11_tc_hpd_detection_setup(struct drm_i915_private *dev_priv) { - u32 hotplug; - - hotplug = intel_uncore_read(&dev_priv->uncore, GEN11_TC_HOTPLUG_CTL); - hotplug &= ~(GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC1) | - GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC2) | - GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC3) | - GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC4) | - GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC5) | - GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC6)); - hotplug |= intel_hpd_hotplug_enables(dev_priv, gen11_hotplug_enables); - intel_uncore_write(&dev_priv->uncore, GEN11_TC_HOTPLUG_CTL, hotplug); + intel_uncore_rmw(&dev_priv->uncore, GEN11_TC_HOTPLUG_CTL, + GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC1) | + GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC2) | + GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC3) | + GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC4) | + GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC5) | + GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC6), + intel_hpd_hotplug_enables(dev_priv, gen11_hotplug_enables)); } static void gen11_tbt_hpd_detection_setup(struct drm_i915_private *dev_priv) { - u32 hotplug; - - hotplug = intel_uncore_read(&dev_priv->uncore, GEN11_TBT_HOTPLUG_CTL); - hotplug &= ~(GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC1) | - GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC2) | - GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC3) | - GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC4) | - GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC5) | - GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC6)); - hotplug |= intel_hpd_hotplug_enables(dev_priv, gen11_hotplug_enables); - intel_uncore_write(&dev_priv->uncore, GEN11_TBT_HOTPLUG_CTL, hotplug); + intel_uncore_rmw(&dev_priv->uncore, GEN11_TBT_HOTPLUG_CTL, + GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC1) | + GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC2) | + GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC3) | + GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC4) | + GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC5) | + GEN11_HOTPLUG_CTL_ENABLE(HPD_PORT_TC6), + intel_hpd_hotplug_enables(dev_priv, gen11_hotplug_enables)); } static void gen11_hpd_irq_setup(struct drm_i915_private *dev_priv) { u32 hotplug_irqs, enabled_irqs; - u32 val; enabled_irqs = intel_hpd_enabled_irqs(dev_priv, dev_priv->display.hotplug.hpd); hotplug_irqs = intel_hpd_hotplug_irqs(dev_priv, dev_priv->display.hotplug.hpd); - val = intel_uncore_read(&dev_priv->uncore, GEN11_DE_HPD_IMR); - val &= ~hotplug_irqs; - val |= ~enabled_irqs & hotplug_irqs; - intel_uncore_write(&dev_priv->uncore, GEN11_DE_HPD_IMR, val); + intel_uncore_rmw(&dev_priv->uncore, GEN11_DE_HPD_IMR, hotplug_irqs, + ~enabled_irqs & hotplug_irqs); intel_uncore_posting_read(&dev_priv->uncore, GEN11_DE_HPD_IMR); gen11_tc_hpd_detection_setup(dev_priv); @@ -3507,29 +3465,22 @@ static u32 spt_hotplug2_enables(struct drm_i915_private *i915, static void spt_hpd_detection_setup(struct drm_i915_private *dev_priv) { - u32 val, hotplug; - /* Display WA #1179 WaHardHangonHotPlug: cnp */ if (HAS_PCH_CNP(dev_priv)) { - val = intel_uncore_read(&dev_priv->uncore, SOUTH_CHICKEN1); - val &= ~CHASSIS_CLK_REQ_DURATION_MASK; - val |= CHASSIS_CLK_REQ_DURATION(0xf); - intel_uncore_write(&dev_priv->uncore, SOUTH_CHICKEN1, val); + intel_uncore_rmw(&dev_priv->uncore, SOUTH_CHICKEN1, CHASSIS_CLK_REQ_DURATION_MASK, + CHASSIS_CLK_REQ_DURATION(0xf)); } /* Enable digital hotplug on the PCH */ - hotplug = intel_uncore_read(&dev_priv->uncore, PCH_PORT_HOTPLUG); - hotplug &= ~(PORTA_HOTPLUG_ENABLE | - PORTB_HOTPLUG_ENABLE | - PORTC_HOTPLUG_ENABLE | - PORTD_HOTPLUG_ENABLE); - hotplug |= intel_hpd_hotplug_enables(dev_priv, spt_hotplug_enables); - intel_uncore_write(&dev_priv->uncore, PCH_PORT_HOTPLUG, hotplug); + intel_uncore_rmw(&dev_priv->uncore, PCH_PORT_HOTPLUG, + PORTA_HOTPLUG_ENABLE | + PORTB_HOTPLUG_ENABLE | + PORTC_HOTPLUG_ENABLE | + PORTD_HOTPLUG_ENABLE, + intel_hpd_hotplug_enables(dev_priv, spt_hotplug_enables)); - hotplug = intel_uncore_read(&dev_priv->uncore, PCH_PORT_HOTPLUG2); - hotplug &= ~PORTE_HOTPLUG_ENABLE; - hotplug |= intel_hpd_hotplug_enables(dev_priv, spt_hotplug2_enables); - intel_uncore_write(&dev_priv->uncore, PCH_PORT_HOTPLUG2, hotplug); + intel_uncore_rmw(&dev_priv->uncore, PCH_PORT_HOTPLUG2, PORTE_HOTPLUG_ENABLE, + intel_hpd_hotplug_enables(dev_priv, spt_hotplug2_enables)); } static void spt_hpd_irq_setup(struct drm_i915_private *dev_priv) @@ -3561,18 +3512,14 @@ static u32 ilk_hotplug_enables(struct drm_i915_private *i915, static void ilk_hpd_detection_setup(struct drm_i915_private *dev_priv) { - u32 hotplug; - /* * Enable digital hotplug on the CPU, and configure the DP short pulse * duration to 2ms (which is the minimum in the Display Port spec) * The pulse duration bits are reserved on HSW+. */ - hotplug = intel_uncore_read(&dev_priv->uncore, DIGITAL_PORT_HOTPLUG_CNTRL); - hotplug &= ~(DIGITAL_PORTA_HOTPLUG_ENABLE | - DIGITAL_PORTA_PULSE_DURATION_MASK); - hotplug |= intel_hpd_hotplug_enables(dev_priv, ilk_hotplug_enables); - intel_uncore_write(&dev_priv->uncore, DIGITAL_PORT_HOTPLUG_CNTRL, hotplug); + intel_uncore_rmw(&dev_priv->uncore, DIGITAL_PORT_HOTPLUG_CNTRL, + DIGITAL_PORTA_HOTPLUG_ENABLE | DIGITAL_PORTA_PULSE_DURATION_MASK, + intel_hpd_hotplug_enables(dev_priv, ilk_hotplug_enables)); } static void ilk_hpd_irq_setup(struct drm_i915_private *dev_priv) @@ -3620,17 +3567,12 @@ static u32 bxt_hotplug_enables(struct drm_i915_private *i915, static void bxt_hpd_detection_setup(struct drm_i915_private *dev_priv) { - u32 hotplug; - - hotplug = intel_uncore_read(&dev_priv->uncore, PCH_PORT_HOTPLUG); - hotplug &= ~(PORTA_HOTPLUG_ENABLE | - PORTB_HOTPLUG_ENABLE | - PORTC_HOTPLUG_ENABLE | - BXT_DDIA_HPD_INVERT | - BXT_DDIB_HPD_INVERT | - BXT_DDIC_HPD_INVERT); - hotplug |= intel_hpd_hotplug_enables(dev_priv, bxt_hotplug_enables); - intel_uncore_write(&dev_priv->uncore, PCH_PORT_HOTPLUG, hotplug); + intel_uncore_rmw(&dev_priv->uncore, PCH_PORT_HOTPLUG, + PORTA_HOTPLUG_ENABLE | + PORTB_HOTPLUG_ENABLE | + PORTC_HOTPLUG_ENABLE | + BXT_DDI_HPD_INVERT_MASK, + intel_hpd_hotplug_enables(dev_priv, bxt_hotplug_enables)); } static void bxt_hpd_irq_setup(struct drm_i915_private *dev_priv) @@ -4010,9 +3952,7 @@ static void i9xx_error_irq_ack(struct drm_i915_private *dev_priv, { u32 emr; - *eir = intel_uncore_read(&dev_priv->uncore, EIR); - - intel_uncore_write(&dev_priv->uncore, EIR, *eir); + *eir = intel_uncore_rmw(&dev_priv->uncore, EIR, 0, 0); *eir_stuck = intel_uncore_read(&dev_priv->uncore, EIR); if (*eir_stuck == 0) @@ -4028,8 +3968,7 @@ static void i9xx_error_irq_ack(struct drm_i915_private *dev_priv, * (or by a GPU reset) so we mask any bit that * remains set. */ - emr = intel_uncore_read(&dev_priv->uncore, EMR); - intel_uncore_write(&dev_priv->uncore, EMR, 0xffffffff); + emr = intel_uncore_rmw(&dev_priv->uncore, EMR, ~0, 0xffffffff); intel_uncore_write(&dev_priv->uncore, EMR, emr | *eir_stuck); } @@ -4096,7 +4035,7 @@ static void i915_irq_reset(struct drm_i915_private *dev_priv) if (I915_HAS_HOTPLUG(dev_priv)) { i915_hotplug_interrupt_update(dev_priv, 0xffffffff, 0); - intel_uncore_write(&dev_priv->uncore, PORT_HOTPLUG_STAT, intel_uncore_read(&dev_priv->uncore, PORT_HOTPLUG_STAT)); + intel_uncore_rmw(&dev_priv->uncore, PORT_HOTPLUG_STAT, 0, 0); } i9xx_pipestat_irq_reset(dev_priv); @@ -4206,7 +4145,7 @@ static void i965_irq_reset(struct drm_i915_private *dev_priv) struct intel_uncore *uncore = &dev_priv->uncore; i915_hotplug_interrupt_update(dev_priv, 0xffffffff, 0); - intel_uncore_write(uncore, PORT_HOTPLUG_STAT, intel_uncore_read(uncore, PORT_HOTPLUG_STAT)); + intel_uncore_rmw(uncore, PORT_HOTPLUG_STAT, 0, 0); i9xx_pipestat_irq_reset(dev_priv); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 3cd696806b58..efe334dad372 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -895,19 +895,14 @@ static void pnv_update_wm(struct drm_i915_private *dev_priv) wm = intel_calculate_wm(pixel_rate, &pnv_cursor_wm, pnv_display_wm.fifo_size, 4, latency->cursor_sr); - reg = intel_uncore_read(&dev_priv->uncore, DSPFW3); - reg &= ~DSPFW_CURSOR_SR_MASK; - reg |= FW_WM(wm, CURSOR_SR); - intel_uncore_write(&dev_priv->uncore, DSPFW3, reg); + intel_uncore_rmw(&dev_priv->uncore, DSPFW3, DSPFW_CURSOR_SR_MASK, + FW_WM(wm, CURSOR_SR)); /* Display HPLL off SR */ wm = intel_calculate_wm(pixel_rate, &pnv_display_hplloff_wm, pnv_display_hplloff_wm.fifo_size, cpp, latency->display_hpll_disable); - reg = intel_uncore_read(&dev_priv->uncore, DSPFW3); - reg &= ~DSPFW_HPLL_SR_MASK; - reg |= FW_WM(wm, HPLL_SR); - intel_uncore_write(&dev_priv->uncore, DSPFW3, reg); + intel_uncore_rmw(&dev_priv->uncore, DSPFW3, DSPFW_HPLL_SR_MASK, FW_WM(wm, HPLL_SR)); /* cursor HPLL off SR */ wm = intel_calculate_wm(pixel_rate, &pnv_cursor_hplloff_wm, @@ -3480,7 +3475,6 @@ static void ilk_write_wm_values(struct drm_i915_private *dev_priv, { struct ilk_wm_values *previous = &dev_priv->display.wm.hw; unsigned int dirty; - u32 val; dirty = ilk_compute_wm_dirty(dev_priv, previous, results); if (!dirty) @@ -3496,32 +3490,20 @@ static void ilk_write_wm_values(struct drm_i915_private *dev_priv, intel_uncore_write(&dev_priv->uncore, WM0_PIPE_ILK(PIPE_C), results->wm_pipe[2]); if (dirty & WM_DIRTY_DDB) { - if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) { - val = intel_uncore_read(&dev_priv->uncore, WM_MISC); - if (results->partitioning == INTEL_DDB_PART_1_2) - val &= ~WM_MISC_DATA_PARTITION_5_6; - else - val |= WM_MISC_DATA_PARTITION_5_6; - intel_uncore_write(&dev_priv->uncore, WM_MISC, val); - } else { - val = intel_uncore_read(&dev_priv->uncore, DISP_ARB_CTL2); - if (results->partitioning == INTEL_DDB_PART_1_2) - val &= ~DISP_DATA_PARTITION_5_6; - else - val |= DISP_DATA_PARTITION_5_6; - intel_uncore_write(&dev_priv->uncore, DISP_ARB_CTL2, val); - } - } - - if (dirty & WM_DIRTY_FBC) { - val = intel_uncore_read(&dev_priv->uncore, DISP_ARB_CTL); - if (results->enable_fbc_wm) - val &= ~DISP_FBC_WM_DIS; + if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) + intel_uncore_rmw(&dev_priv->uncore, WM_MISC, WM_MISC_DATA_PARTITION_5_6, + results->partitioning == INTEL_DDB_PART_1_2 ? 0 : + WM_MISC_DATA_PARTITION_5_6); else - val |= DISP_FBC_WM_DIS; - intel_uncore_write(&dev_priv->uncore, DISP_ARB_CTL, val); + intel_uncore_rmw(&dev_priv->uncore, DISP_ARB_CTL2, DISP_DATA_PARTITION_5_6, + results->partitioning == INTEL_DDB_PART_1_2 ? 0 : + DISP_DATA_PARTITION_5_6); } + if (dirty & WM_DIRTY_FBC) + intel_uncore_rmw(&dev_priv->uncore, DISP_ARB_CTL, DISP_FBC_WM_DIS, + results->enable_fbc_wm ? 0 : DISP_FBC_WM_DIS); + if (dirty & WM_DIRTY_LP(1) && previous->wm_lp_spr[0] != results->wm_lp_spr[0]) intel_uncore_write(&dev_priv->uncore, WM1S_LP_ILK, results->wm_lp_spr[0]); @@ -4131,7 +4113,7 @@ static void g4x_disable_trickle_feed(struct drm_i915_private *dev_priv) intel_uncore_read(&dev_priv->uncore, DSPCNTR(pipe)) | DISP_TRICKLE_FEED_DISABLE); - intel_uncore_write(&dev_priv->uncore, DSPSURF(pipe), intel_uncore_read(&dev_priv->uncore, DSPSURF(pipe))); + intel_uncore_rmw(&dev_priv->uncore, DSPSURF(pipe), 0, 0); intel_uncore_posting_read(&dev_priv->uncore, DSPSURF(pipe)); } } @@ -4339,8 +4321,8 @@ static void gen8_set_l3sqc_credits(struct drm_i915_private *dev_priv, u32 val; /* WaTempDisableDOPClkGating:bdw */ - misccpctl = intel_uncore_read(&dev_priv->uncore, GEN7_MISCCPCTL); - intel_uncore_write(&dev_priv->uncore, GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE); + misccpctl = intel_uncore_rmw(&dev_priv->uncore, GEN7_MISCCPCTL, ~GEN7_DOP_CLOCK_GATE_ENABLE, + 0); val = intel_uncore_read(&dev_priv->uncore, GEN8_L3SQCREG1); val &= ~L3_PRIO_CREDITS_MASK; @@ -4620,8 +4602,6 @@ static void hsw_init_clock_gating(struct drm_i915_private *dev_priv) static void ivb_init_clock_gating(struct drm_i915_private *dev_priv) { - u32 snpcr; - intel_uncore_write(&dev_priv->uncore, ILK_DSPCLK_GATE_D, ILK_VRHUNIT_CLOCK_GATE_DISABLE); /* WaFbcAsynchFlipDisableFbcQueue:ivb */ @@ -4659,10 +4639,8 @@ static void ivb_init_clock_gating(struct drm_i915_private *dev_priv) g4x_disable_trickle_feed(dev_priv); - snpcr = intel_uncore_read(&dev_priv->uncore, GEN6_MBCUNIT_SNPCR); - snpcr &= ~GEN6_MBC_SNPCR_MASK; - snpcr |= GEN6_MBC_SNPCR_MED; - intel_uncore_write(&dev_priv->uncore, GEN6_MBCUNIT_SNPCR, snpcr); + intel_uncore_rmw(&dev_priv->uncore, GEN6_MBCUNIT_SNPCR, GEN6_MBC_SNPCR_MASK, + GEN6_MBC_SNPCR_MED); if (!HAS_PCH_NOP(dev_priv)) cpt_init_clock_gating(dev_priv); diff --git a/drivers/gpu/drm/i915/vlv_suspend.c b/drivers/gpu/drm/i915/vlv_suspend.c index 664fde244f59..02e63ed77f60 100644 --- a/drivers/gpu/drm/i915/vlv_suspend.c +++ b/drivers/gpu/drm/i915/vlv_suspend.c @@ -194,7 +194,6 @@ static void vlv_restore_gunit_s0ix_state(struct drm_i915_private *i915) { struct vlv_s0ix_state *s = i915->vlv_s0ix_state; struct intel_uncore *uncore = &i915->uncore; - u32 val; int i; if (!s) @@ -262,15 +261,11 @@ static void vlv_restore_gunit_s0ix_state(struct drm_i915_private *i915) * be restored, as they are used to control the s0ix suspend/resume * sequence by the caller. */ - val = intel_uncore_read(uncore, VLV_GTLC_WAKE_CTRL); - val &= VLV_GTLC_ALLOWWAKEREQ; - val |= s->gtlc_wake_ctrl & ~VLV_GTLC_ALLOWWAKEREQ; - intel_uncore_write(uncore, VLV_GTLC_WAKE_CTRL, val); + intel_uncore_rmw(uncore, VLV_GTLC_WAKE_CTRL, ~VLV_GTLC_ALLOWWAKEREQ, + s->gtlc_wake_ctrl & ~VLV_GTLC_ALLOWWAKEREQ); - val = intel_uncore_read(uncore, VLV_GTLC_SURVIVABILITY_REG); - val &= VLV_GFX_CLK_FORCE_ON_BIT; - val |= s->gtlc_survive & ~VLV_GFX_CLK_FORCE_ON_BIT; - intel_uncore_write(uncore, VLV_GTLC_SURVIVABILITY_REG, val); + intel_uncore_rmw(uncore, VLV_GTLC_SURVIVABILITY_REG, ~VLV_GFX_CLK_FORCE_ON_BIT, + s->gtlc_survive & ~VLV_GFX_CLK_FORCE_ON_BIT); intel_uncore_write(uncore, VLV_PMWGICZ, s->pmwgicz); @@ -308,14 +303,10 @@ static int vlv_wait_for_pw_status(struct drm_i915_private *i915, static int vlv_force_gfx_clock(struct drm_i915_private *i915, bool force_on) { struct intel_uncore *uncore = &i915->uncore; - u32 val; int err; - val = intel_uncore_read(uncore, VLV_GTLC_SURVIVABILITY_REG); - val &= ~VLV_GFX_CLK_FORCE_ON_BIT; - if (force_on) - val |= VLV_GFX_CLK_FORCE_ON_BIT; - intel_uncore_write(uncore, VLV_GTLC_SURVIVABILITY_REG, val); + intel_uncore_rmw(uncore, VLV_GTLC_SURVIVABILITY_REG, VLV_GFX_CLK_FORCE_ON_BIT, + force_on ? VLV_GFX_CLK_FORCE_ON_BIT : 0); if (!force_on) return 0; @@ -340,11 +331,8 @@ static int vlv_allow_gt_wake(struct drm_i915_private *i915, bool allow) u32 val; int err; - val = intel_uncore_read(uncore, VLV_GTLC_WAKE_CTRL); - val &= ~VLV_GTLC_ALLOWWAKEREQ; - if (allow) - val |= VLV_GTLC_ALLOWWAKEREQ; - intel_uncore_write(uncore, VLV_GTLC_WAKE_CTRL, val); + intel_uncore_rmw(uncore, VLV_GTLC_WAKE_CTRL, VLV_GTLC_ALLOWWAKEREQ, + allow ? VLV_GTLC_ALLOWWAKEREQ : 0); intel_uncore_posting_read(uncore, VLV_GTLC_WAKE_CTRL); mask = VLV_GTLC_ALLOWWAKEACK; -- cgit From 636123a8357f465ba453480ed55fb206d9c961e7 Mon Sep 17 00:00:00 2001 From: Anusha Srivatsa Date: Mon, 10 Oct 2022 13:21:35 -0700 Subject: drm/i915/display: Add DC5 counter and DMC debugfs entries for MTL MTL and dgfx use the same DC5 counter. While at it, this patch also adds the corresponding debugfs entries. Some cleanup wrt dc3co register which makes the code more readable. Driver loads all firmware that it finds in the firmware binary but platform doesn't *need* all of them. Cleaning the previous debugs entries to reflect which firmware is needed and if the needed firmware is loaded or not. MTL needs both Pipe A and Pipe B DMC to be loaded along with Main DMC. BSpec: 49788 Cc: Lucas De Marchi Cc: Radhakrishna Sripada Signed-off-by: Anusha Srivatsa Reviewed-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20221010202135.28388-1-anusha.srivatsa@intel.com --- drivers/gpu/drm/i915/display/intel_dmc.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dmc.c b/drivers/gpu/drm/i915/display/intel_dmc.c index e52ecc0738a6..081a4d0083b1 100644 --- a/drivers/gpu/drm/i915/display/intel_dmc.c +++ b/drivers/gpu/drm/i915/display/intel_dmc.c @@ -1065,12 +1065,13 @@ static int intel_dmc_debugfs_status_show(struct seq_file *m, void *unused) seq_printf(m, "fw loaded: %s\n", str_yes_no(intel_dmc_has_payload(i915))); seq_printf(m, "path: %s\n", dmc->fw_path); - seq_printf(m, "Pipe A fw support: %s\n", + seq_printf(m, "Pipe A fw needed: %s\n", str_yes_no(GRAPHICS_VER(i915) >= 12)); seq_printf(m, "Pipe A fw loaded: %s\n", str_yes_no(dmc->dmc_info[DMC_FW_PIPEA].payload)); - seq_printf(m, "Pipe B fw support: %s\n", - str_yes_no(IS_ALDERLAKE_P(i915))); + seq_printf(m, "Pipe B fw needed: %s\n", + str_yes_no(IS_ALDERLAKE_P(i915) || + DISPLAY_VER(i915) >= 14)); seq_printf(m, "Pipe B fw loaded: %s\n", str_yes_no(dmc->dmc_info[DMC_FW_PIPEB].payload)); @@ -1081,22 +1082,19 @@ static int intel_dmc_debugfs_status_show(struct seq_file *m, void *unused) DMC_VERSION_MINOR(dmc->version)); if (DISPLAY_VER(i915) >= 12) { - if (IS_DGFX(i915)) { + i915_reg_t dc3co_reg; + + if (IS_DGFX(i915) || DISPLAY_VER(i915) >= 14) { + dc3co_reg = DG1_DMC_DEBUG3; dc5_reg = DG1_DMC_DEBUG_DC5_COUNT; } else { + dc3co_reg = TGL_DMC_DEBUG3; dc5_reg = TGL_DMC_DEBUG_DC5_COUNT; dc6_reg = TGL_DMC_DEBUG_DC6_COUNT; } - /* - * NOTE: DMC_DEBUG3 is a general purpose reg. - * According to B.Specs:49196 DMC f/w reuses DC5/6 counter - * reg for DC3CO debugging and validation, - * but TGL DMC f/w is using DMC_DEBUG3 reg for DC3CO counter. - */ seq_printf(m, "DC3CO count: %d\n", - intel_de_read(i915, IS_DGFX(i915) ? - DG1_DMC_DEBUG3 : TGL_DMC_DEBUG3)); + intel_de_read(i915, dc3co_reg)); } else { dc5_reg = IS_BROXTON(i915) ? BXT_DMC_DC3_DC5_COUNT : SKL_DMC_DC3_DC5_COUNT; -- cgit From e55427b46852f11ca37f33abb7d7ec76bb4c9ed3 Mon Sep 17 00:00:00 2001 From: Andi Shyti Date: Tue, 11 Oct 2022 15:59:40 +0200 Subject: drm/i915/trace: Remove unused frequency trace Commit 3e7abf814193 ("drm/i915: Extract GT render power state management") removes the "trace_intel_gpu_freq_change()" trace points but their definition was left without users. Remove it. Suggested-by: Tvrtko Ursulin Signed-off-by: Andi Shyti Cc: Chris Wilson Reviewed-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20221011135940.367048-1-andi.shyti@linux.intel.com --- drivers/gpu/drm/i915/i915_trace.h | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h index 37b5c9e9d260..c70a02517e02 100644 --- a/drivers/gpu/drm/i915/i915_trace.h +++ b/drivers/gpu/drm/i915/i915_trace.h @@ -671,21 +671,6 @@ TRACE_EVENT_CONDITION(i915_reg_rw, (u32)(__entry->val >> 32)) ); -TRACE_EVENT(intel_gpu_freq_change, - TP_PROTO(u32 freq), - TP_ARGS(freq), - - TP_STRUCT__entry( - __field(u32, freq) - ), - - TP_fast_assign( - __entry->freq = freq; - ), - - TP_printk("new_freq=%u", __entry->freq) -); - /** * DOC: i915_ppgtt_create and i915_ppgtt_release tracepoints * -- cgit From ca0022425b3303786a563f8e40c26164970eb632 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 11 Oct 2022 17:08:30 +0300 Subject: drm: split build lists one per line and sort While it takes more vertical space, sorted build lists with one object per line are arguably easier to manage, especially when there are conflicting changes. Split anything with more than one object file. v2: also split drm_cache.o and put it after drm_bridge.o (Andi) Signed-off-by: Jani Nikula Reviewed-by: Andi Shyti Acked-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20221011140830.3257655-1-jani.nikula@intel.com --- drivers/gpu/drm/Makefile | 107 ++++++++++++++++++++++++++++----------- drivers/gpu/drm/display/Makefile | 14 ++--- 2 files changed, 85 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 25d0ba310509..6ad98d3ceff7 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -3,32 +3,71 @@ # Makefile for the drm device driver. This driver provides support for the # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. -drm-y := drm_aperture.o drm_auth.o drm_cache.o \ - drm_file.o drm_gem.o drm_ioctl.o \ - drm_drv.o \ - drm_sysfs.o drm_mm.o \ - drm_crtc.o drm_fourcc.o drm_modes.o drm_edid.o drm_displayid.o \ - drm_trace_points.o drm_prime.o \ - drm_vma_manager.o \ - drm_modeset_lock.o drm_atomic.o drm_bridge.o \ - drm_framebuffer.o drm_connector.o drm_blend.o \ - drm_encoder.o drm_mode_object.o drm_property.o \ - drm_plane.o drm_color_mgmt.o drm_print.o \ - drm_dumb_buffers.o drm_mode_config.o drm_vblank.o \ - drm_syncobj.o drm_lease.o drm_writeback.o drm_client.o \ - drm_client_modeset.o drm_atomic_uapi.o \ - drm_managed.o drm_vblank_work.o -drm-$(CONFIG_DRM_LEGACY) += drm_agpsupport.o drm_bufs.o drm_context.o drm_dma.o \ - drm_hashtab.o drm_irq.o drm_legacy_misc.o drm_lock.o \ - drm_memory.o drm_scatter.o drm_vm.o +drm-y := \ + drm_aperture.o \ + drm_atomic.o \ + drm_atomic_uapi.o \ + drm_auth.o \ + drm_blend.o \ + drm_bridge.o \ + drm_cache.o \ + drm_client.o \ + drm_client_modeset.o \ + drm_color_mgmt.o \ + drm_connector.o \ + drm_crtc.o \ + drm_displayid.o \ + drm_drv.o \ + drm_dumb_buffers.o \ + drm_edid.o \ + drm_encoder.o \ + drm_file.o \ + drm_fourcc.o \ + drm_framebuffer.o \ + drm_gem.o \ + drm_ioctl.o \ + drm_lease.o \ + drm_managed.o \ + drm_mm.o \ + drm_mode_config.o \ + drm_mode_object.o \ + drm_modes.o \ + drm_modeset_lock.o \ + drm_plane.o \ + drm_prime.o \ + drm_print.o \ + drm_property.o \ + drm_syncobj.o \ + drm_sysfs.o \ + drm_trace_points.o \ + drm_vblank.o \ + drm_vblank_work.o \ + drm_vma_manager.o \ + drm_writeback.o +drm-$(CONFIG_DRM_LEGACY) += \ + drm_agpsupport.o \ + drm_bufs.o \ + drm_context.o \ + drm_dma.o \ + drm_hashtab.o \ + drm_irq.o \ + drm_legacy_misc.o \ + drm_lock.o \ + drm_memory.o \ + drm_scatter.o \ + drm_vm.o drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o drm-$(CONFIG_COMPAT) += drm_ioc32.o drm-$(CONFIG_DRM_PANEL) += drm_panel.o drm-$(CONFIG_OF) += drm_of.o drm-$(CONFIG_PCI) += drm_pci.o -drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o +drm-$(CONFIG_DEBUG_FS) += \ + drm_debugfs.o \ + drm_debugfs_crc.o drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o -drm-$(CONFIG_DRM_PRIVACY_SCREEN) += drm_privacy_screen.o drm_privacy_screen_x86.o +drm-$(CONFIG_DRM_PRIVACY_SCREEN) += \ + drm_privacy_screen.o \ + drm_privacy_screen_x86.o obj-$(CONFIG_DRM) += drm.o obj-$(CONFIG_DRM_NOMODESET) += drm_nomodeset.o @@ -57,16 +96,24 @@ obj-$(CONFIG_DRM_TTM_HELPER) += drm_ttm_helper.o # Modesetting helpers # -drm_kms_helper-y := drm_bridge_connector.o drm_crtc_helper.o \ - drm_encoder_slave.o drm_flip_work.o \ - drm_probe_helper.o \ - drm_plane_helper.o drm_atomic_helper.o \ - drm_kms_helper_common.o \ - drm_simple_kms_helper.o drm_modeset_helper.o \ - drm_gem_atomic_helper.o \ - drm_gem_framebuffer_helper.o \ - drm_atomic_state_helper.o drm_damage_helper.o \ - drm_format_helper.o drm_self_refresh_helper.o drm_rect.o +drm_kms_helper-y := \ + drm_atomic_helper.o \ + drm_atomic_state_helper.o \ + drm_bridge_connector.o \ + drm_crtc_helper.o \ + drm_damage_helper.o \ + drm_encoder_slave.o \ + drm_flip_work.o \ + drm_format_helper.o \ + drm_gem_atomic_helper.o \ + drm_gem_framebuffer_helper.o \ + drm_kms_helper_common.o \ + drm_modeset_helper.o \ + drm_plane_helper.o \ + drm_probe_helper.o \ + drm_rect.o \ + drm_self_refresh_helper.o \ + drm_simple_kms_helper.o drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o diff --git a/drivers/gpu/drm/display/Makefile b/drivers/gpu/drm/display/Makefile index 52cdda1180d9..17ac4a1006a8 100644 --- a/drivers/gpu/drm/display/Makefile +++ b/drivers/gpu/drm/display/Makefile @@ -3,13 +3,15 @@ obj-$(CONFIG_DRM_DP_AUX_BUS) += drm_dp_aux_bus.o drm_display_helper-y := drm_display_helper_mod.o -drm_display_helper-$(CONFIG_DRM_DISPLAY_DP_HELPER) += drm_dp_dual_mode_helper.o \ - drm_dp_helper.o \ - drm_dp_mst_topology.o \ - drm_dsc_helper.o +drm_display_helper-$(CONFIG_DRM_DISPLAY_DP_HELPER) += \ + drm_dp_dual_mode_helper.o \ + drm_dp_helper.o \ + drm_dp_mst_topology.o \ + drm_dsc_helper.o drm_display_helper-$(CONFIG_DRM_DISPLAY_HDCP_HELPER) += drm_hdcp_helper.o -drm_display_helper-$(CONFIG_DRM_DISPLAY_HDMI_HELPER) += drm_hdmi_helper.o \ - drm_scdc_helper.o +drm_display_helper-$(CONFIG_DRM_DISPLAY_HDMI_HELPER) += \ + drm_hdmi_helper.o \ + drm_scdc_helper.o drm_display_helper-$(CONFIG_DRM_DP_AUX_CHARDEV) += drm_dp_aux_dev.o drm_display_helper-$(CONFIG_DRM_DP_CEC) += drm_dp_cec.o -- cgit From 9cf06d6ef7fd08adf51568b704ab7ba6007b6fe8 Mon Sep 17 00:00:00 2001 From: ruanjinjie Date: Sat, 24 Sep 2022 17:25:16 +0800 Subject: drm/nouveau/disp: fix cast removes address space of expression warnings When build Linux kernel with 'make C=2', encounter the following warnings: ./drivers/gpu/drm/nouveau/dispnv50/disp.c:134:34: warning: cast removes address space '__iomem' of expression ./drivers/gpu/drm/nouveau/dispnv50/disp.c:197:34: warning: cast removes address space '__iomem' of expression The data type of dmac->_push.mem.object.map.ptr is 'void __iomem *', but converted to 'u32 *' directly and cause above warnings, now recover their data types to fix these warnings. Signed-off-by: ruanjinjie Reviewed-by: Lyude Paul Signed-off-by: Lyude Paul Link: https://patchwork.freedesktop.org/patch/msgid/20220924092516.10007-1-ruanjinjie@huawei.com --- drivers/gpu/drm/nouveau/dispnv50/disp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 33c97d510999..aa94f8e284dd 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -131,7 +131,7 @@ nv50_dmac_kick(struct nvif_push *push) { struct nv50_dmac *dmac = container_of(push, typeof(*dmac), _push); - dmac->cur = push->cur - (u32 *)dmac->_push.mem.object.map.ptr; + dmac->cur = push->cur - (u32 __iomem *)dmac->_push.mem.object.map.ptr; if (dmac->put != dmac->cur) { /* Push buffer fetches are not coherent with BAR1, we need to ensure * writes have been flushed right through to VRAM before writing PUT. @@ -194,7 +194,7 @@ nv50_dmac_wait(struct nvif_push *push, u32 size) if (WARN_ON(size > dmac->max)) return -EINVAL; - dmac->cur = push->cur - (u32 *)dmac->_push.mem.object.map.ptr; + dmac->cur = push->cur - (u32 __iomem *)dmac->_push.mem.object.map.ptr; if (dmac->cur + size >= dmac->max) { int ret = nv50_dmac_wind(dmac); if (ret) -- cgit From 9cebffdf0d9c2b045fa3ecde43a2c0014953087a Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Tue, 11 Oct 2022 18:51:33 +0200 Subject: drm/mgag200: Do not call drm_atomic_add_affected_planes() There's no need to add planes to the atomic state. Remove the call to drm_atomic_add_affected_planes() from mgag200. On full modesets, the DRM helpers already add a CRTC's planes to the atomic state; see drm_atomic_helper_check_modeset(). There's no reason to call drm_atomic_add_affected_planes() unconditionally in the CRTC's atomic_check() in mgag200. It's also too late, as the atomic_check() of the added planes will not be called before the commit. Suggested-by: Thomas Zimmermann Signed-off-by: Javier Martinez Canillas Reviewed-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20221011165136.469750-2-javierm@redhat.com --- drivers/gpu/drm/mgag200/mgag200_mode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 5f7eb642f0c6..758629da95d9 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -601,7 +601,7 @@ int mgag200_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_st } } - return drm_atomic_add_affected_planes(new_state, crtc); + return 0; } void mgag200_crtc_helper_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *old_state) -- cgit From 3339aa186cc11fece96b77e2d4bc80678f90b440 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Tue, 11 Oct 2022 18:51:34 +0200 Subject: drm/simpledrm: Do not call drm_atomic_add_affected_planes() There's no need to add planes to the atomic state. Remove the call to drm_atomic_add_affected_planes() from simpledrm. On full modesets, the DRM helpers already add a CRTC's planes to the atomic state; see drm_atomic_helper_check_modeset(). There's no reason to call drm_atomic_add_affected_planes() unconditionally in the CRTC's atomic_check() in simpledrm. It's also too late, as the atomic_check() of the added planes will not be called before the commit. Suggested-by: Thomas Zimmermann Signed-off-by: Javier Martinez Canillas Reviewed-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20221011165136.469750-3-javierm@redhat.com --- drivers/gpu/drm/tiny/simpledrm.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c index ecd49a8f3334..f03f17f62a56 100644 --- a/drivers/gpu/drm/tiny/simpledrm.c +++ b/drivers/gpu/drm/tiny/simpledrm.c @@ -549,17 +549,11 @@ static int simpledrm_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *new_state) { struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc); - int ret; if (!new_crtc_state->enable) - goto out; - - ret = drm_atomic_helper_check_crtc_primary_plane(new_crtc_state); - if (ret) - return ret; + return 0; -out: - return drm_atomic_add_affected_planes(new_state, crtc); + return drm_atomic_helper_check_crtc_primary_plane(new_crtc_state); } /* -- cgit From 6c3d9cf400dc085de0bde33dde73d47c71b7b2df Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Tue, 11 Oct 2022 18:51:35 +0200 Subject: drm/ssd130x: Do not call drm_atomic_add_affected_planes() There's no need to add planes to the atomic state. Remove the call to drm_atomic_add_affected_planes() from ssd130x. On full modesets, the DRM helpers already add a CRTC's planes to the atomic state; see drm_atomic_helper_check_modeset(). There's no reason to call drm_atomic_add_affected_planes() unconditionally in the CRTC's atomic_check() in ssd130x. It's also too late, as the atomic_check() of the added planes will not be called before the commit. Suggested-by: Thomas Zimmermann Signed-off-by: Javier Martinez Canillas Reviewed-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20221011165136.469750-4-javierm@redhat.com --- drivers/gpu/drm/solomon/ssd130x.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/solomon/ssd130x.c b/drivers/gpu/drm/solomon/ssd130x.c index 57e48355c008..0d4ab65233db 100644 --- a/drivers/gpu/drm/solomon/ssd130x.c +++ b/drivers/gpu/drm/solomon/ssd130x.c @@ -649,17 +649,11 @@ static int ssd130x_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *new_state) { struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc); - int ret; if (!new_crtc_state->enable) - goto out; - - ret = drm_atomic_helper_check_crtc_primary_plane(new_crtc_state); - if (ret) - return ret; + return 0; -out: - return drm_atomic_add_affected_planes(new_state, crtc); + return drm_atomic_helper_check_crtc_primary_plane(new_crtc_state); } /* -- cgit From 7fed7fa340691ef4b78f5f3aebde44715128d868 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Tue, 11 Oct 2022 18:51:36 +0200 Subject: drm/crtc-helper: Add a drm_crtc_helper_atomic_check() helper Provides a default CRTC state check handler for CRTCs that only have one primary plane attached. There are some drivers that duplicate this logic in their helpers, such as simpledrm and ssd130x. Factor out this common code into a CRTC helper and make drivers use it. Signed-off-by: Javier Martinez Canillas Reviewed-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20221011165136.469750-5-javierm@redhat.com --- drivers/gpu/drm/drm_crtc_helper.c | 26 ++++++++++++++++++++++++++ drivers/gpu/drm/drm_plane_helper.c | 4 +++- drivers/gpu/drm/solomon/ssd130x.c | 14 ++------------ drivers/gpu/drm/tiny/simpledrm.c | 14 ++------------ include/drm/drm_crtc_helper.h | 2 ++ 5 files changed, 35 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 457448cc60f7..1f0a270ac984 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -421,6 +421,32 @@ done: } EXPORT_SYMBOL(drm_crtc_helper_set_mode); +/** + * drm_crtc_helper_atomic_check() - Helper to check CRTC atomic-state + * @crtc: CRTC to check + * @state: atomic state object + * + * Provides a default CRTC-state check handler for CRTCs that only have + * one primary plane attached to it. + * + * This is often the case for the CRTC of simple framebuffers. See also + * drm_plane_helper_atomic_check() for the respective plane-state check + * helper function. + * + * RETURNS: + * Zero on success, or an errno code otherwise. + */ +int drm_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state) +{ + struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + + if (!new_crtc_state->enable) + return 0; + + return drm_atomic_helper_check_crtc_primary_plane(new_crtc_state); +} +EXPORT_SYMBOL(drm_crtc_helper_atomic_check); + static void drm_crtc_helper_disable(struct drm_crtc *crtc) { diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index 865bd999b187..ba6a9136a065 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -298,7 +298,9 @@ EXPORT_SYMBOL(drm_plane_helper_destroy); * scale and positioning are not expected to change since the plane is always * a fullscreen scanout buffer. * - * This is often the case for the primary plane of simple framebuffers. + * This is often the case for the primary plane of simple framebuffers. See + * also drm_crtc_helper_atomic_check() for the respective CRTC-state check + * helper function. * * RETURNS: * Zero on success, or an errno code otherwise. diff --git a/drivers/gpu/drm/solomon/ssd130x.c b/drivers/gpu/drm/solomon/ssd130x.c index 0d4ab65233db..f2795f90ea69 100644 --- a/drivers/gpu/drm/solomon/ssd130x.c +++ b/drivers/gpu/drm/solomon/ssd130x.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -645,17 +646,6 @@ static enum drm_mode_status ssd130x_crtc_helper_mode_valid(struct drm_crtc *crtc return MODE_OK; } -static int ssd130x_crtc_helper_atomic_check(struct drm_crtc *crtc, - struct drm_atomic_state *new_state) -{ - struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc); - - if (!new_crtc_state->enable) - return 0; - - return drm_atomic_helper_check_crtc_primary_plane(new_crtc_state); -} - /* * The CRTC is always enabled. Screen updates are performed by * the primary plane's atomic_update function. Disabling clears @@ -663,7 +653,7 @@ static int ssd130x_crtc_helper_atomic_check(struct drm_crtc *crtc, */ static const struct drm_crtc_helper_funcs ssd130x_crtc_helper_funcs = { .mode_valid = ssd130x_crtc_helper_mode_valid, - .atomic_check = ssd130x_crtc_helper_atomic_check, + .atomic_check = drm_crtc_helper_atomic_check, }; static void ssd130x_crtc_reset(struct drm_crtc *crtc) diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c index f03f17f62a56..cbb100753154 100644 --- a/drivers/gpu/drm/tiny/simpledrm.c +++ b/drivers/gpu/drm/tiny/simpledrm.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -545,17 +546,6 @@ static enum drm_mode_status simpledrm_crtc_helper_mode_valid(struct drm_crtc *cr return drm_crtc_helper_mode_valid_fixed(crtc, mode, &sdev->mode); } -static int simpledrm_crtc_helper_atomic_check(struct drm_crtc *crtc, - struct drm_atomic_state *new_state) -{ - struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc); - - if (!new_crtc_state->enable) - return 0; - - return drm_atomic_helper_check_crtc_primary_plane(new_crtc_state); -} - /* * The CRTC is always enabled. Screen updates are performed by * the primary plane's atomic_update function. Disabling clears @@ -563,7 +553,7 @@ static int simpledrm_crtc_helper_atomic_check(struct drm_crtc *crtc, */ static const struct drm_crtc_helper_funcs simpledrm_crtc_helper_funcs = { .mode_valid = simpledrm_crtc_helper_mode_valid, - .atomic_check = simpledrm_crtc_helper_atomic_check, + .atomic_check = drm_crtc_helper_atomic_check, }; static const struct drm_crtc_funcs simpledrm_crtc_funcs = { diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index a6d520d5b6ca..1840db247f69 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -50,6 +50,8 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, int x, int y, struct drm_framebuffer *old_fb); +int drm_crtc_helper_atomic_check(struct drm_crtc *crtc, + struct drm_atomic_state *state); bool drm_helper_crtc_in_use(struct drm_crtc *crtc); bool drm_helper_encoder_in_use(struct drm_encoder *encoder); -- cgit From 9a0cdcd6649b76f0b7ceec0e55b0a718321e34d3 Mon Sep 17 00:00:00 2001 From: Abhinav Kumar Date: Tue, 11 Oct 2022 14:10:49 -0700 Subject: drm/bridge: adv7533: remove dynamic lane switching from adv7533 bridge adv7533 bridge tries to dynamically switch lanes based on the mode by detaching and attaching the mipi dsi device. This approach is incorrect because this method of dynamic switch of detaching and attaching the mipi dsi device also results in removing and adding the component which is not necessary. This approach is also prone to deadlocks. So for example, on the db410c whenever this path is executed with lockdep enabled, this results in a deadlock due to below ordering of locks. -> #1 (crtc_ww_class_acquire){+.+.}-{0:0}: lock_acquire+0x6c/0x90 drm_modeset_acquire_init+0xf4/0x150 drmm_mode_config_init+0x220/0x770 msm_drm_bind+0x13c/0x654 try_to_bring_up_aggregate_device+0x164/0x1d0 __component_add+0xa8/0x174 component_add+0x18/0x2c dsi_dev_attach+0x24/0x30 dsi_host_attach+0x98/0x14c devm_mipi_dsi_attach+0x38/0xb0 adv7533_attach_dsi+0x8c/0x110 adv7511_probe+0x5a0/0x930 i2c_device_probe+0x30c/0x350 really_probe.part.0+0x9c/0x2b0 __driver_probe_device+0x98/0x144 driver_probe_device+0xac/0x14c __device_attach_driver+0xbc/0x124 bus_for_each_drv+0x78/0xd0 __device_attach+0xa8/0x1c0 device_initial_probe+0x18/0x24 bus_probe_device+0xa0/0xac deferred_probe_work_func+0x90/0xd0 process_one_work+0x28c/0x6b0 worker_thread+0x240/0x444 kthread+0x110/0x114 ret_from_fork+0x10/0x20 -> #0 (component_mutex){+.+.}-{3:3}: __lock_acquire+0x1280/0x20ac lock_acquire.part.0+0xe0/0x230 lock_acquire+0x6c/0x90 __mutex_lock+0x84/0x400 mutex_lock_nested+0x3c/0x70 component_del+0x34/0x170 dsi_dev_detach+0x24/0x30 dsi_host_detach+0x20/0x64 mipi_dsi_detach+0x2c/0x40 adv7533_mode_set+0x64/0x90 adv7511_bridge_mode_set+0x210/0x214 drm_bridge_chain_mode_set+0x5c/0x84 crtc_set_mode+0x18c/0x1dc drm_atomic_helper_commit_modeset_disables+0x40/0x50 msm_atomic_commit_tail+0x1d0/0x6e0 commit_tail+0xa4/0x180 drm_atomic_helper_commit+0x178/0x3b0 drm_atomic_commit+0xa4/0xe0 drm_client_modeset_commit_atomic+0x228/0x284 drm_client_modeset_commit_locked+0x64/0x1d0 drm_client_modeset_commit+0x34/0x60 drm_fb_helper_lastclose+0x74/0xcc drm_lastclose+0x3c/0x80 drm_release+0xfc/0x114 __fput+0x70/0x224 ____fput+0x14/0x20 task_work_run+0x88/0x1a0 do_exit+0x350/0xa50 do_group_exit+0x38/0xa4 __wake_up_parent+0x0/0x34 invoke_syscall+0x48/0x114 el0_svc_common.constprop.0+0x60/0x11c do_el0_svc+0x30/0xc0 el0_svc+0x58/0x100 el0t_64_sync_handler+0x1b0/0x1bc el0t_64_sync+0x18c/0x190 Due to above reasons, remove the dynamic lane switching code from adv7533 bridge chip and filter out the modes which would need different number of lanes as compared to the initialization time using the mode_valid callback. This can be potentially re-introduced by using the pre_enable() callback but this needs to be evaluated first whether such an approach will work so this will be done with a separate change. changes since RFC: - Fix commit text and add TODO comment changes in v2: - Fix checkpatch formatting errors Fixes: 62b2f026cd8e ("drm/bridge: adv7533: Change number of DSI lanes dynamically") Closes: https://gitlab.freedesktop.org/drm/msm/-/issues/16 Suggested-by: Dmitry Baryshkov Signed-off-by: Abhinav Kumar Reviewed-by: Robert Foss Link: https://lore.kernel.org/r/1661797363-7564-1-git-send-email-quic_abhinavk@quicinc.com Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/1665522649-3423-1-git-send-email-quic_abhinavk@quicinc.com --- drivers/gpu/drm/bridge/adv7511/adv7511.h | 3 ++- drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 18 ++++++++++++++---- drivers/gpu/drm/bridge/adv7511/adv7533.c | 25 +++++++++++++------------ 3 files changed, 29 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h b/drivers/gpu/drm/bridge/adv7511/adv7511.h index 94de73cbeb2d..17445800248d 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511.h +++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h @@ -402,7 +402,8 @@ static inline int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511) void adv7533_dsi_power_on(struct adv7511 *adv); void adv7533_dsi_power_off(struct adv7511 *adv); -void adv7533_mode_set(struct adv7511 *adv, const struct drm_display_mode *mode); +enum drm_mode_status adv7533_mode_valid(struct adv7511 *adv, + const struct drm_display_mode *mode); int adv7533_patch_registers(struct adv7511 *adv); int adv7533_patch_cec_registers(struct adv7511 *adv); int adv7533_attach_dsi(struct adv7511 *adv); diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index 6031bdd92342..0f0950c11196 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -697,7 +697,7 @@ adv7511_detect(struct adv7511 *adv7511, struct drm_connector *connector) } static enum drm_mode_status adv7511_mode_valid(struct adv7511 *adv7511, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { if (mode->clock > 165000) return MODE_CLOCK_HIGH; @@ -791,9 +791,6 @@ static void adv7511_mode_set(struct adv7511 *adv7511, regmap_update_bits(adv7511->regmap, 0x17, 0x60, (vsync_polarity << 6) | (hsync_polarity << 5)); - if (adv7511->type == ADV7533 || adv7511->type == ADV7535) - adv7533_mode_set(adv7511, adj_mode); - drm_mode_copy(&adv7511->curr_mode, adj_mode); /* @@ -913,6 +910,18 @@ static void adv7511_bridge_mode_set(struct drm_bridge *bridge, adv7511_mode_set(adv, mode, adj_mode); } +static enum drm_mode_status adv7511_bridge_mode_valid(struct drm_bridge *bridge, + const struct drm_display_info *info, + const struct drm_display_mode *mode) +{ + struct adv7511 *adv = bridge_to_adv7511(bridge); + + if (adv->type == ADV7533 || adv->type == ADV7535) + return adv7533_mode_valid(adv, mode); + else + return adv7511_mode_valid(adv, mode); +} + static int adv7511_bridge_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags) { @@ -960,6 +969,7 @@ static const struct drm_bridge_funcs adv7511_bridge_funcs = { .enable = adv7511_bridge_enable, .disable = adv7511_bridge_disable, .mode_set = adv7511_bridge_mode_set, + .mode_valid = adv7511_bridge_mode_valid, .attach = adv7511_bridge_attach, .detect = adv7511_bridge_detect, .get_edid = adv7511_bridge_get_edid, diff --git a/drivers/gpu/drm/bridge/adv7511/adv7533.c b/drivers/gpu/drm/bridge/adv7511/adv7533.c index ef6270806d1d..258c79d4dab0 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7533.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7533.c @@ -100,26 +100,27 @@ void adv7533_dsi_power_off(struct adv7511 *adv) regmap_write(adv->regmap_cec, 0x27, 0x0b); } -void adv7533_mode_set(struct adv7511 *adv, const struct drm_display_mode *mode) +enum drm_mode_status adv7533_mode_valid(struct adv7511 *adv, + const struct drm_display_mode *mode) { + int lanes; struct mipi_dsi_device *dsi = adv->dsi; - int lanes, ret; - - if (adv->num_dsi_lanes != 4) - return; if (mode->clock > 80000) lanes = 4; else lanes = 3; - if (lanes != dsi->lanes) { - mipi_dsi_detach(dsi); - dsi->lanes = lanes; - ret = mipi_dsi_attach(dsi); - if (ret) - dev_err(&dsi->dev, "failed to change host lanes\n"); - } + /* + * TODO: add support for dynamic switching of lanes + * by using the bridge pre_enable() op . Till then filter + * out the modes which shall need different number of lanes + * than what was configured in the device tree. + */ + if (lanes != dsi->lanes) + return MODE_BAD; + + return MODE_OK; } int adv7533_patch_registers(struct adv7511 *adv) -- cgit From c8a17756c42581ba1a567d1dd3b69e8f5619a7d8 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 11 Oct 2022 17:07:08 +0200 Subject: drm/ofdrm: Add ofdrm for Open Firmware framebuffers Open Firmware provides basic display output via the 'display' node. DT platform code already provides a device that represents the node's framebuffer. Add a DRM driver for the device. The display mode and color format is pre-initialized by the system's firmware. Runtime modesetting via DRM is not possible. The display is useful during early boot stages or as error fallback. Similar functionality is already provided by fbdev's offb driver, which is insufficient for modern userspace. The old driver includes support for BootX device tree, which can be found on old 32-bit PowerPC Macintosh systems. If these are still in use, the functionality can be added to ofdrm or implemented in a new driver. As with simpledrm, the fbdev driver cannot be selected if ofdrm is already enabled. Two notable points about the driver: * Reading the framebuffer aperture from the device tree is not reliable on all systems. Ofdrm takes the heuristics and a comment from offb to pick the correct range. * No resource management may be tied to the underlying PCI device. Otherwise the handover to the native driver will fail with a resource conflict. PCI management is therefore done as part of the platform device's cleanup. The driver has been tested on qemu's ppc64le emulation. The device hand-over has been tested with bochs. v5: * use drm_atomic_helper_check_crtc_primary_plane() v4: * set preferred depth to the correct value * set bpp value for console emulation * output scanout-buffer parameters with drm_dbg() v3: * reintegrate FWFB helpers into ofdrm * use damage iterator * sync GEM BOs with drm_gem_fb_{begin,end}_cpu_access() * fix various atomic_check helpers * remove CRTC atomic_{enable,disable} (Javier) * compute stride with drm_format_info_min_pitch() (Daniel) v2: * removed simple-pipe helpers * built driver on top of FWFB helpers * merged all init code into single function * make PCI support optional (Michal) * support COMPILE_TEST (Javier) Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas convert Link: https://patchwork.freedesktop.org/patch/msgid/20221011150712.3928-2-tzimmermann@suse.de --- MAINTAINERS | 1 + drivers/gpu/drm/tiny/Kconfig | 13 + drivers/gpu/drm/tiny/Makefile | 1 + drivers/gpu/drm/tiny/ofdrm.c | 763 ++++++++++++++++++++++++++++++++++++++++++ drivers/video/fbdev/Kconfig | 1 + 5 files changed, 779 insertions(+) create mode 100644 drivers/gpu/drm/tiny/ofdrm.c diff --git a/MAINTAINERS b/MAINTAINERS index 4f2fa9925116..78f670955434 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6653,6 +6653,7 @@ L: dri-devel@lists.freedesktop.org S: Maintained T: git git://anongit.freedesktop.org/drm/drm-misc F: drivers/gpu/drm/drm_aperture.c +F: drivers/gpu/drm/tiny/ofdrm.c F: drivers/gpu/drm/tiny/simpledrm.c F: drivers/video/aperture.c F: include/drm/drm_aperture.h diff --git a/drivers/gpu/drm/tiny/Kconfig b/drivers/gpu/drm/tiny/Kconfig index 565957264875..a300b03a3c7a 100644 --- a/drivers/gpu/drm/tiny/Kconfig +++ b/drivers/gpu/drm/tiny/Kconfig @@ -51,6 +51,19 @@ config DRM_GM12U320 This is a KMS driver for projectors which use the GM12U320 chipset for video transfer over USB2/3, such as the Acer C120 mini projector. +config DRM_OFDRM + tristate "Open Firmware display driver" + depends on DRM && OF && (PPC || COMPILE_TEST) + select APERTURE_HELPERS + select DRM_GEM_SHMEM_HELPER + select DRM_KMS_HELPER + help + DRM driver for Open Firmware framebuffers. + + This driver assumes that the display hardware has been initialized + by the Open Firmware before the kernel boots. Scanout buffer, size, + and display format must be provided via device tree. + config DRM_PANEL_MIPI_DBI tristate "DRM support for MIPI DBI compatible panels" depends on DRM && SPI diff --git a/drivers/gpu/drm/tiny/Makefile b/drivers/gpu/drm/tiny/Makefile index 1d9d6227e7ab..76dde89a044b 100644 --- a/drivers/gpu/drm/tiny/Makefile +++ b/drivers/gpu/drm/tiny/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_DRM_ARCPGU) += arcpgu.o obj-$(CONFIG_DRM_BOCHS) += bochs.o obj-$(CONFIG_DRM_CIRRUS_QEMU) += cirrus.o obj-$(CONFIG_DRM_GM12U320) += gm12u320.o +obj-$(CONFIG_DRM_OFDRM) += ofdrm.o obj-$(CONFIG_DRM_PANEL_MIPI_DBI) += panel-mipi-dbi.o obj-$(CONFIG_DRM_SIMPLEDRM) += simpledrm.o obj-$(CONFIG_TINYDRM_HX8357D) += hx8357d.o diff --git a/drivers/gpu/drm/tiny/ofdrm.c b/drivers/gpu/drm/tiny/ofdrm.c new file mode 100644 index 000000000000..96a46078ade8 --- /dev/null +++ b/drivers/gpu/drm/tiny/ofdrm.c @@ -0,0 +1,763 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "ofdrm" +#define DRIVER_DESC "DRM driver for OF platform devices" +#define DRIVER_DATE "20220501" +#define DRIVER_MAJOR 1 +#define DRIVER_MINOR 0 + +/* + * Helpers for display nodes + */ + +static int display_get_validated_int(struct drm_device *dev, const char *name, uint32_t value) +{ + if (value > INT_MAX) { + drm_err(dev, "invalid framebuffer %s of %u\n", name, value); + return -EINVAL; + } + return (int)value; +} + +static int display_get_validated_int0(struct drm_device *dev, const char *name, uint32_t value) +{ + if (!value) { + drm_err(dev, "invalid framebuffer %s of %u\n", name, value); + return -EINVAL; + } + return display_get_validated_int(dev, name, value); +} + +static const struct drm_format_info *display_get_validated_format(struct drm_device *dev, + u32 depth) +{ + const struct drm_format_info *info; + u32 format; + + switch (depth) { + case 8: + format = drm_mode_legacy_fb_format(8, 8); + break; + case 15: + case 16: + format = drm_mode_legacy_fb_format(16, depth); + break; + case 32: + format = drm_mode_legacy_fb_format(32, 24); + break; + default: + drm_err(dev, "unsupported framebuffer depth %u\n", depth); + return ERR_PTR(-EINVAL); + } + + info = drm_format_info(format); + if (!info) { + drm_err(dev, "cannot find framebuffer format for depth %u\n", depth); + return ERR_PTR(-EINVAL); + } + + return info; +} + +static int display_read_u32_of(struct drm_device *dev, struct device_node *of_node, + const char *name, u32 *value) +{ + int ret = of_property_read_u32(of_node, name, value); + + if (ret) + drm_err(dev, "cannot parse framebuffer %s: error %d\n", name, ret); + return ret; +} + +static int display_get_width_of(struct drm_device *dev, struct device_node *of_node) +{ + u32 width; + int ret = display_read_u32_of(dev, of_node, "width", &width); + + if (ret) + return ret; + return display_get_validated_int0(dev, "width", width); +} + +static int display_get_height_of(struct drm_device *dev, struct device_node *of_node) +{ + u32 height; + int ret = display_read_u32_of(dev, of_node, "height", &height); + + if (ret) + return ret; + return display_get_validated_int0(dev, "height", height); +} + +static int display_get_depth_of(struct drm_device *dev, struct device_node *of_node) +{ + u32 depth; + int ret = display_read_u32_of(dev, of_node, "depth", &depth); + + if (ret) + return ret; + return display_get_validated_int0(dev, "depth", depth); +} + +static int display_get_linebytes_of(struct drm_device *dev, struct device_node *of_node) +{ + u32 linebytes; + int ret = display_read_u32_of(dev, of_node, "linebytes", &linebytes); + + if (ret) + return ret; + return display_get_validated_int(dev, "linebytes", linebytes); +} + +static u64 display_get_address_of(struct drm_device *dev, struct device_node *of_node) +{ + u32 address; + int ret; + + /* + * Not all devices provide an address property, it's not + * a bug if this fails. The driver will try to find the + * framebuffer base address from the device's memory regions. + */ + ret = of_property_read_u32(of_node, "address", &address); + if (ret) + return OF_BAD_ADDR; + + return address; +} + +/* + * Open Firmware display device + */ + +struct ofdrm_device { + struct drm_device dev; + struct platform_device *pdev; + + /* firmware-buffer settings */ + struct iosys_map screen_base; + struct drm_display_mode mode; + const struct drm_format_info *format; + unsigned int pitch; + + /* modesetting */ + uint32_t formats[8]; + struct drm_plane primary_plane; + struct drm_crtc crtc; + struct drm_encoder encoder; + struct drm_connector connector; +}; + +static struct ofdrm_device *ofdrm_device_of_dev(struct drm_device *dev) +{ + return container_of(dev, struct ofdrm_device, dev); +} + +/* + * Hardware + */ + +#if defined(CONFIG_PCI) +static struct pci_dev *display_get_pci_dev_of(struct drm_device *dev, struct device_node *of_node) +{ + const __be32 *vendor_p, *device_p; + u32 vendor, device; + struct pci_dev *pcidev; + + vendor_p = of_get_property(of_node, "vendor-id", NULL); + if (!vendor_p) + return ERR_PTR(-ENODEV); + vendor = be32_to_cpup(vendor_p); + + device_p = of_get_property(of_node, "device-id", NULL); + if (!device_p) + return ERR_PTR(-ENODEV); + device = be32_to_cpup(device_p); + + pcidev = pci_get_device(vendor, device, NULL); + if (!pcidev) + return ERR_PTR(-ENODEV); + + return pcidev; +} + +static void ofdrm_pci_release(void *data) +{ + struct pci_dev *pcidev = data; + + pci_disable_device(pcidev); +} + +static int ofdrm_device_init_pci(struct ofdrm_device *odev) +{ + struct drm_device *dev = &odev->dev; + struct platform_device *pdev = to_platform_device(dev->dev); + struct device_node *of_node = pdev->dev.of_node; + struct pci_dev *pcidev; + int ret; + + /* + * Never use pcim_ or other managed helpers on the returned PCI + * device. Otherwise, probing the native driver will fail for + * resource conflicts. PCI-device management has to be tied to + * the lifetime of the platform device until the native driver + * takes over. + */ + pcidev = display_get_pci_dev_of(dev, of_node); + if (IS_ERR(pcidev)) + return 0; /* no PCI device found; ignore the error */ + + ret = pci_enable_device(pcidev); + if (ret) { + drm_err(dev, "pci_enable_device(%s) failed: %d\n", + dev_name(&pcidev->dev), ret); + return ret; + } + ret = devm_add_action_or_reset(&pdev->dev, ofdrm_pci_release, pcidev); + if (ret) + return ret; + + return 0; +} +#else +static int ofdrm_device_init_pci(struct ofdrm_device *odev) +{ + return 0; +} +#endif + +/* + * OF display settings + */ + +static struct resource *ofdrm_find_fb_resource(struct ofdrm_device *odev, + struct resource *fb_res) +{ + struct platform_device *pdev = to_platform_device(odev->dev.dev); + struct resource *res, *max_res = NULL; + u32 i; + + for (i = 0; pdev->num_resources; ++i) { + res = platform_get_resource(pdev, IORESOURCE_MEM, i); + if (!res) + break; /* all resources processed */ + if (resource_size(res) < resource_size(fb_res)) + continue; /* resource too small */ + if (fb_res->start && resource_contains(res, fb_res)) + return res; /* resource contains framebuffer */ + if (!max_res || resource_size(res) > resource_size(max_res)) + max_res = res; /* store largest resource as fallback */ + } + + return max_res; +} + +/* + * Modesetting + */ + +/* + * Support all formats of OF display and maybe more; in order + * of preference. The display's update function will do any + * conversion necessary. + * + * TODO: Add blit helpers for remaining formats and uncomment + * constants. + */ +static const uint32_t ofdrm_primary_plane_formats[] = { + DRM_FORMAT_XRGB8888, + DRM_FORMAT_RGB565, + //DRM_FORMAT_XRGB1555, + //DRM_FORMAT_C8, +}; + +static const uint64_t ofdrm_primary_plane_format_modifiers[] = { + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID +}; + +static int ofdrm_primary_plane_helper_atomic_check(struct drm_plane *plane, + struct drm_atomic_state *new_state) +{ + struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(new_state, plane); + struct drm_crtc *new_crtc = new_plane_state->crtc; + struct drm_crtc_state *new_crtc_state = NULL; + + if (new_crtc) + new_crtc_state = drm_atomic_get_new_crtc_state(new_state, new_plane_state->crtc); + + return drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, + false, false); +} + +static void ofdrm_primary_plane_helper_atomic_update(struct drm_plane *plane, + struct drm_atomic_state *state) +{ + struct drm_device *dev = plane->dev; + struct ofdrm_device *odev = ofdrm_device_of_dev(dev); + struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); + struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); + struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); + struct drm_framebuffer *fb = plane_state->fb; + unsigned int dst_pitch = odev->pitch; + const struct drm_format_info *dst_format = odev->format; + struct drm_atomic_helper_damage_iter iter; + struct drm_rect damage; + int ret, idx; + + ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE); + if (ret) + return; + + if (!drm_dev_enter(dev, &idx)) + goto out_drm_gem_fb_end_cpu_access; + + drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state); + drm_atomic_for_each_plane_damage(&iter, &damage) { + struct iosys_map dst = odev->screen_base; + struct drm_rect dst_clip = plane_state->dst; + + if (!drm_rect_intersect(&dst_clip, &damage)) + continue; + + iosys_map_incr(&dst, drm_fb_clip_offset(dst_pitch, dst_format, &dst_clip)); + drm_fb_blit(&dst, &dst_pitch, dst_format->format, shadow_plane_state->data, fb, + &damage); + } + + drm_dev_exit(idx); +out_drm_gem_fb_end_cpu_access: + drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE); +} + +static void ofdrm_primary_plane_helper_atomic_disable(struct drm_plane *plane, + struct drm_atomic_state *state) +{ + struct drm_device *dev = plane->dev; + struct ofdrm_device *odev = ofdrm_device_of_dev(dev); + struct iosys_map dst = odev->screen_base; + struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); + void __iomem *dst_vmap = dst.vaddr_iomem; /* TODO: Use mapping abstraction */ + unsigned int dst_pitch = odev->pitch; + const struct drm_format_info *dst_format = odev->format; + struct drm_rect dst_clip; + unsigned long lines, linepixels, i; + int idx; + + drm_rect_init(&dst_clip, + plane_state->src_x >> 16, plane_state->src_y >> 16, + plane_state->src_w >> 16, plane_state->src_h >> 16); + + lines = drm_rect_height(&dst_clip); + linepixels = drm_rect_width(&dst_clip); + + if (!drm_dev_enter(dev, &idx)) + return; + + /* Clear buffer to black if disabled */ + dst_vmap += drm_fb_clip_offset(dst_pitch, dst_format, &dst_clip); + for (i = 0; i < lines; ++i) { + memset_io(dst_vmap, 0, linepixels * dst_format->cpp[0]); + dst_vmap += dst_pitch; + } + + drm_dev_exit(idx); +} + +static const struct drm_plane_helper_funcs ofdrm_primary_plane_helper_funcs = { + DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, + .atomic_check = ofdrm_primary_plane_helper_atomic_check, + .atomic_update = ofdrm_primary_plane_helper_atomic_update, + .atomic_disable = ofdrm_primary_plane_helper_atomic_disable, +}; + +static const struct drm_plane_funcs ofdrm_primary_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = drm_plane_cleanup, + DRM_GEM_SHADOW_PLANE_FUNCS, +}; + +static enum drm_mode_status ofdrm_crtc_helper_mode_valid(struct drm_crtc *crtc, + const struct drm_display_mode *mode) +{ + struct ofdrm_device *odev = ofdrm_device_of_dev(crtc->dev); + + return drm_crtc_helper_mode_valid_fixed(crtc, mode, &odev->mode); +} + +static int ofdrm_crtc_helper_atomic_check(struct drm_crtc *crtc, + struct drm_atomic_state *new_state) +{ + struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc); + + if (!new_crtc_state->enable) + return 0; + + return drm_atomic_helper_check_crtc_primary_plane(new_crtc_state); +} + +/* + * The CRTC is always enabled. Screen updates are performed by + * the primary plane's atomic_update function. Disabling clears + * the screen in the primary plane's atomic_disable function. + */ +static const struct drm_crtc_helper_funcs ofdrm_crtc_helper_funcs = { + .mode_valid = ofdrm_crtc_helper_mode_valid, + .atomic_check = ofdrm_crtc_helper_atomic_check, +}; + +static const struct drm_crtc_funcs ofdrm_crtc_funcs = { + .reset = drm_atomic_helper_crtc_reset, + .destroy = drm_crtc_cleanup, + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, +}; + +static int ofdrm_connector_helper_get_modes(struct drm_connector *connector) +{ + struct ofdrm_device *odev = ofdrm_device_of_dev(connector->dev); + + return drm_connector_helper_get_modes_fixed(connector, &odev->mode); +} + +static const struct drm_connector_helper_funcs ofdrm_connector_helper_funcs = { + .get_modes = ofdrm_connector_helper_get_modes, +}; + +static const struct drm_connector_funcs ofdrm_connector_funcs = { + .reset = drm_atomic_helper_connector_reset, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = drm_connector_cleanup, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +static const struct drm_mode_config_funcs ofdrm_mode_config_funcs = { + .fb_create = drm_gem_fb_create_with_dirty, + .atomic_check = drm_atomic_helper_check, + .atomic_commit = drm_atomic_helper_commit, +}; + +/* + * Init / Cleanup + */ + +static struct drm_display_mode ofdrm_mode(unsigned int width, unsigned int height) +{ + /* + * Assume a monitor resolution of 96 dpi to + * get a somewhat reasonable screen size. + */ + const struct drm_display_mode mode = { + DRM_MODE_INIT(60, width, height, + DRM_MODE_RES_MM(width, 96ul), + DRM_MODE_RES_MM(height, 96ul)) + }; + + return mode; +} + +static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv, + struct platform_device *pdev) +{ + struct device_node *of_node = pdev->dev.of_node; + struct ofdrm_device *odev; + struct drm_device *dev; + int width, height, depth, linebytes; + const struct drm_format_info *format; + u64 address; + resource_size_t fb_size, fb_base, fb_pgbase, fb_pgsize; + struct resource *res, *mem; + void __iomem *screen_base; + struct drm_plane *primary_plane; + struct drm_crtc *crtc; + struct drm_encoder *encoder; + struct drm_connector *connector; + unsigned long max_width, max_height; + size_t nformats; + int ret; + + odev = devm_drm_dev_alloc(&pdev->dev, drv, struct ofdrm_device, dev); + if (IS_ERR(odev)) + return ERR_CAST(odev); + dev = &odev->dev; + platform_set_drvdata(pdev, dev); + + ret = ofdrm_device_init_pci(odev); + if (ret) + return ERR_PTR(ret); + + /* + * OF display-node settings + */ + + width = display_get_width_of(dev, of_node); + if (width < 0) + return ERR_PTR(width); + height = display_get_height_of(dev, of_node); + if (height < 0) + return ERR_PTR(height); + depth = display_get_depth_of(dev, of_node); + if (depth < 0) + return ERR_PTR(depth); + linebytes = display_get_linebytes_of(dev, of_node); + if (linebytes < 0) + return ERR_PTR(linebytes); + + format = display_get_validated_format(dev, depth); + if (IS_ERR(format)) + return ERR_CAST(format); + if (!linebytes) { + linebytes = drm_format_info_min_pitch(format, 0, width); + if (drm_WARN_ON(dev, !linebytes)) + return ERR_PTR(-EINVAL); + } + + fb_size = linebytes * height; + + /* + * Try to figure out the address of the framebuffer. Unfortunately, Open + * Firmware doesn't provide a standard way to do so. All we can do is a + * dodgy heuristic that happens to work in practice. + * + * On most machines, the "address" property contains what we need, though + * not on Matrox cards found in IBM machines. What appears to give good + * results is to go through the PCI ranges and pick one that encloses the + * "address" property. If none match, we pick the largest. + */ + address = display_get_address_of(dev, of_node); + if (address != OF_BAD_ADDR) { + struct resource fb_res = DEFINE_RES_MEM(address, fb_size); + + res = ofdrm_find_fb_resource(odev, &fb_res); + if (!res) + return ERR_PTR(-EINVAL); + if (resource_contains(res, &fb_res)) + fb_base = address; + else + fb_base = res->start; + } else { + struct resource fb_res = DEFINE_RES_MEM(0u, fb_size); + + res = ofdrm_find_fb_resource(odev, &fb_res); + if (!res) + return ERR_PTR(-EINVAL); + fb_base = res->start; + } + + /* + * I/O resources + */ + + fb_pgbase = round_down(fb_base, PAGE_SIZE); + fb_pgsize = fb_base - fb_pgbase + round_up(fb_size, PAGE_SIZE); + + ret = devm_aperture_acquire_from_firmware(dev, fb_pgbase, fb_pgsize); + if (ret) { + drm_err(dev, "could not acquire memory range %pr: error %d\n", &res, ret); + return ERR_PTR(ret); + } + + mem = devm_request_mem_region(&pdev->dev, fb_pgbase, fb_pgsize, drv->name); + if (!mem) { + drm_warn(dev, "could not acquire memory region %pr\n", &res); + return ERR_PTR(-ENOMEM); + } + + screen_base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); + if (!screen_base) + return ERR_PTR(-ENOMEM); + + /* + * Firmware framebuffer + */ + + iosys_map_set_vaddr_iomem(&odev->screen_base, screen_base); + odev->mode = ofdrm_mode(width, height); + odev->format = format; + odev->pitch = linebytes; + + drm_dbg(dev, "display mode={" DRM_MODE_FMT "}\n", DRM_MODE_ARG(&odev->mode)); + drm_dbg(dev, "framebuffer format=%p4cc, size=%dx%d, linebytes=%d byte\n", + &format->format, width, height, linebytes); + + /* + * Mode-setting pipeline + */ + + ret = drmm_mode_config_init(dev); + if (ret) + return ERR_PTR(ret); + + max_width = max_t(unsigned long, width, DRM_SHADOW_PLANE_MAX_WIDTH); + max_height = max_t(unsigned long, height, DRM_SHADOW_PLANE_MAX_HEIGHT); + + dev->mode_config.min_width = width; + dev->mode_config.max_width = max_width; + dev->mode_config.min_height = height; + dev->mode_config.max_height = max_height; + dev->mode_config.funcs = &ofdrm_mode_config_funcs; + switch (depth) { + case 32: + dev->mode_config.preferred_depth = 24; + break; + default: + dev->mode_config.preferred_depth = depth; + break; + } + + /* Primary plane */ + + nformats = drm_fb_build_fourcc_list(dev, &format->format, 1, + ofdrm_primary_plane_formats, + ARRAY_SIZE(ofdrm_primary_plane_formats), + odev->formats, ARRAY_SIZE(odev->formats)); + + primary_plane = &odev->primary_plane; + ret = drm_universal_plane_init(dev, primary_plane, 0, &ofdrm_primary_plane_funcs, + odev->formats, nformats, + ofdrm_primary_plane_format_modifiers, + DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) + return ERR_PTR(ret); + drm_plane_helper_add(primary_plane, &ofdrm_primary_plane_helper_funcs); + drm_plane_enable_fb_damage_clips(primary_plane); + + /* CRTC */ + + crtc = &odev->crtc; + ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL, + &ofdrm_crtc_funcs, NULL); + if (ret) + return ERR_PTR(ret); + drm_crtc_helper_add(crtc, &ofdrm_crtc_helper_funcs); + + /* Encoder */ + + encoder = &odev->encoder; + ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_NONE); + if (ret) + return ERR_PTR(ret); + encoder->possible_crtcs = drm_crtc_mask(crtc); + + /* Connector */ + + connector = &odev->connector; + ret = drm_connector_init(dev, connector, &ofdrm_connector_funcs, + DRM_MODE_CONNECTOR_Unknown); + if (ret) + return ERR_PTR(ret); + drm_connector_helper_add(connector, &ofdrm_connector_helper_funcs); + drm_connector_set_panel_orientation_with_quirk(connector, + DRM_MODE_PANEL_ORIENTATION_UNKNOWN, + width, height); + + ret = drm_connector_attach_encoder(connector, encoder); + if (ret) + return ERR_PTR(ret); + + drm_mode_config_reset(dev); + + return odev; +} + +/* + * DRM driver + */ + +DEFINE_DRM_GEM_FOPS(ofdrm_fops); + +static struct drm_driver ofdrm_driver = { + DRM_GEM_SHMEM_DRIVER_OPS, + .name = DRIVER_NAME, + .desc = DRIVER_DESC, + .date = DRIVER_DATE, + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, + .driver_features = DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET, + .fops = &ofdrm_fops, +}; + +/* + * Platform driver + */ + +static int ofdrm_probe(struct platform_device *pdev) +{ + struct ofdrm_device *odev; + struct drm_device *dev; + int ret; + + odev = ofdrm_device_create(&ofdrm_driver, pdev); + if (IS_ERR(odev)) + return PTR_ERR(odev); + dev = &odev->dev; + + ret = drm_dev_register(dev, 0); + if (ret) + return ret; + + /* + * FIXME: 24-bit color depth does not work reliably with a 32-bpp + * value. Force the bpp value of the scanout buffer's format. + */ + drm_fbdev_generic_setup(dev, drm_format_info_bpp(odev->format, 0)); + + return 0; +} + +static int ofdrm_remove(struct platform_device *pdev) +{ + struct drm_device *dev = platform_get_drvdata(pdev); + + drm_dev_unplug(dev); + + return 0; +} + +static const struct of_device_id ofdrm_of_match_display[] = { + { .compatible = "display", }, + { }, +}; +MODULE_DEVICE_TABLE(of, ofdrm_of_match_display); + +static struct platform_driver ofdrm_platform_driver = { + .driver = { + .name = "of-display", + .of_match_table = ofdrm_of_match_display, + }, + .probe = ofdrm_probe, + .remove = ofdrm_remove, +}; + +module_platform_driver(ofdrm_platform_driver); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index cfc55273dc5d..a98987aa2784 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -455,6 +455,7 @@ config FB_ATARI config FB_OF bool "Open Firmware frame buffer device support" depends on (FB = y) && PPC && (!PPC_PSERIES || PCI) + depends on !DRM_OFDRM select APERTURE_HELPERS select FB_CFB_FILLRECT select FB_CFB_COPYAREA -- cgit From 4113744354b3bafe4e0355c967e4217605627b8b Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 11 Oct 2022 17:07:09 +0200 Subject: drm/ofdrm: Add CRTC state Add a dedicated CRTC state to ofdrm to later store information for palette updates. v3: * rework CRTC state helpers (Javier) Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20221011150712.3928-3-tzimmermann@suse.de --- drivers/gpu/drm/tiny/ofdrm.c | 59 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/tiny/ofdrm.c b/drivers/gpu/drm/tiny/ofdrm.c index 96a46078ade8..6782589ff9fa 100644 --- a/drivers/gpu/drm/tiny/ofdrm.c +++ b/drivers/gpu/drm/tiny/ofdrm.c @@ -278,6 +278,21 @@ static struct resource *ofdrm_find_fb_resource(struct ofdrm_device *odev, * Modesetting */ +struct ofdrm_crtc_state { + struct drm_crtc_state base; +}; + +static struct ofdrm_crtc_state *to_ofdrm_crtc_state(struct drm_crtc_state *base) +{ + return container_of(base, struct ofdrm_crtc_state, base); +} + +static void ofdrm_crtc_state_destroy(struct ofdrm_crtc_state *ofdrm_crtc_state) +{ + __drm_atomic_helper_crtc_destroy_state(&ofdrm_crtc_state->base); + kfree(ofdrm_crtc_state); +} + /* * Support all formats of OF display and maybe more; in order * of preference. The display's update function will do any @@ -431,13 +446,51 @@ static const struct drm_crtc_helper_funcs ofdrm_crtc_helper_funcs = { .atomic_check = ofdrm_crtc_helper_atomic_check, }; +static void ofdrm_crtc_reset(struct drm_crtc *crtc) +{ + struct ofdrm_crtc_state *ofdrm_crtc_state = + kzalloc(sizeof(*ofdrm_crtc_state), GFP_KERNEL); + + if (crtc->state) + ofdrm_crtc_state_destroy(to_ofdrm_crtc_state(crtc->state)); + + if (ofdrm_crtc_state) + __drm_atomic_helper_crtc_reset(crtc, &ofdrm_crtc_state->base); + else + __drm_atomic_helper_crtc_reset(crtc, NULL); +} + +static struct drm_crtc_state *ofdrm_crtc_atomic_duplicate_state(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_crtc_state *crtc_state = crtc->state; + struct ofdrm_crtc_state *new_ofdrm_crtc_state; + + if (drm_WARN_ON(dev, !crtc_state)) + return NULL; + + new_ofdrm_crtc_state = kzalloc(sizeof(*new_ofdrm_crtc_state), GFP_KERNEL); + if (!new_ofdrm_crtc_state) + return NULL; + + __drm_atomic_helper_crtc_duplicate_state(crtc, &new_ofdrm_crtc_state->base); + + return &new_ofdrm_crtc_state->base; +} + +static void ofdrm_crtc_atomic_destroy_state(struct drm_crtc *crtc, + struct drm_crtc_state *crtc_state) +{ + ofdrm_crtc_state_destroy(to_ofdrm_crtc_state(crtc_state)); +} + static const struct drm_crtc_funcs ofdrm_crtc_funcs = { - .reset = drm_atomic_helper_crtc_reset, + .reset = ofdrm_crtc_reset, .destroy = drm_crtc_cleanup, .set_config = drm_atomic_helper_set_config, .page_flip = drm_atomic_helper_page_flip, - .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, + .atomic_duplicate_state = ofdrm_crtc_atomic_duplicate_state, + .atomic_destroy_state = ofdrm_crtc_atomic_destroy_state, }; static int ofdrm_connector_helper_get_modes(struct drm_connector *connector) -- cgit From f496834e167451afc5f0c699ada143a7641b4e85 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 11 Oct 2022 17:07:10 +0200 Subject: drm/ofdrm: Add per-model device function Add a per-model device-function structure in preparation of adding color-management support. Detection of the individual models has been taken from fbdev's offb. v3: * define constants for PCI ids (Javier) Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20221011150712.3928-4-tzimmermann@suse.de --- drivers/gpu/drm/tiny/ofdrm.c | 125 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/drivers/gpu/drm/tiny/ofdrm.c b/drivers/gpu/drm/tiny/ofdrm.c index 6782589ff9fa..a0282a077238 100644 --- a/drivers/gpu/drm/tiny/ofdrm.c +++ b/drivers/gpu/drm/tiny/ofdrm.c @@ -28,6 +28,21 @@ #define DRIVER_MAJOR 1 #define DRIVER_MINOR 0 +#define PCI_VENDOR_ID_ATI_R520 0x7100 +#define PCI_VENDOR_ID_ATI_R600 0x9400 + +enum ofdrm_model { + OFDRM_MODEL_UNKNOWN, + OFDRM_MODEL_MACH64, /* ATI Mach64 */ + OFDRM_MODEL_RAGE128, /* ATI Rage128 */ + OFDRM_MODEL_RAGE_M3A, /* ATI Rage Mobility M3 Head A */ + OFDRM_MODEL_RAGE_M3B, /* ATI Rage Mobility M3 Head B */ + OFDRM_MODEL_RADEON, /* ATI Radeon */ + OFDRM_MODEL_GXT2000, /* IBM GXT2000 */ + OFDRM_MODEL_AVIVO, /* ATI R5xx */ + OFDRM_MODEL_QEMU, /* QEMU VGA */ +}; + /* * Helpers for display nodes */ @@ -148,14 +163,63 @@ static u64 display_get_address_of(struct drm_device *dev, struct device_node *of return address; } +static bool is_avivo(__be32 vendor, __be32 device) +{ + /* This will match most R5xx */ + return (vendor == PCI_VENDOR_ID_ATI) && + ((device >= PCI_VENDOR_ID_ATI_R520 && device < 0x7800) || + (PCI_VENDOR_ID_ATI_R600 >= 0x9400)); +} + +static enum ofdrm_model display_get_model_of(struct drm_device *dev, struct device_node *of_node) +{ + enum ofdrm_model model = OFDRM_MODEL_UNKNOWN; + + if (of_node_name_prefix(of_node, "ATY,Rage128")) { + model = OFDRM_MODEL_RAGE128; + } else if (of_node_name_prefix(of_node, "ATY,RageM3pA") || + of_node_name_prefix(of_node, "ATY,RageM3p12A")) { + model = OFDRM_MODEL_RAGE_M3A; + } else if (of_node_name_prefix(of_node, "ATY,RageM3pB")) { + model = OFDRM_MODEL_RAGE_M3B; + } else if (of_node_name_prefix(of_node, "ATY,Rage6")) { + model = OFDRM_MODEL_RADEON; + } else if (of_node_name_prefix(of_node, "ATY,")) { + return OFDRM_MODEL_MACH64; + } else if (of_device_is_compatible(of_node, "pci1014,b7") || + of_device_is_compatible(of_node, "pci1014,21c")) { + model = OFDRM_MODEL_GXT2000; + } else if (of_node_name_prefix(of_node, "vga,Display-")) { + struct device_node *of_parent; + const __be32 *vendor_p, *device_p; + + /* Look for AVIVO initialized by SLOF */ + of_parent = of_get_parent(of_node); + vendor_p = of_get_property(of_parent, "vendor-id", NULL); + device_p = of_get_property(of_parent, "device-id", NULL); + if (vendor_p && device_p && is_avivo(*vendor_p, *device_p)) + model = OFDRM_MODEL_AVIVO; + of_node_put(of_parent); + } else if (of_device_is_compatible(of_node, "qemu,std-vga")) { + model = OFDRM_MODEL_QEMU; + } + + return model; +} + /* * Open Firmware display device */ +struct ofdrm_device_funcs { +}; + struct ofdrm_device { struct drm_device dev; struct platform_device *pdev; + const struct ofdrm_device_funcs *funcs; + /* firmware-buffer settings */ struct iosys_map screen_base; struct drm_display_mode mode; @@ -522,6 +586,33 @@ static const struct drm_mode_config_funcs ofdrm_mode_config_funcs = { * Init / Cleanup */ +static const struct ofdrm_device_funcs ofdrm_unknown_device_funcs = { +}; + +static const struct ofdrm_device_funcs ofdrm_mach64_device_funcs = { +}; + +static const struct ofdrm_device_funcs ofdrm_rage128_device_funcs = { +}; + +static const struct ofdrm_device_funcs ofdrm_rage_m3a_device_funcs = { +}; + +static const struct ofdrm_device_funcs ofdrm_rage_m3b_device_funcs = { +}; + +static const struct ofdrm_device_funcs ofdrm_radeon_device_funcs = { +}; + +static const struct ofdrm_device_funcs ofdrm_gxt2000_device_funcs = { +}; + +static const struct ofdrm_device_funcs ofdrm_avivo_device_funcs = { +}; + +static const struct ofdrm_device_funcs ofdrm_qemu_device_funcs = { +}; + static struct drm_display_mode ofdrm_mode(unsigned int width, unsigned int height) { /* @@ -543,6 +634,7 @@ static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv, struct device_node *of_node = pdev->dev.of_node; struct ofdrm_device *odev; struct drm_device *dev; + enum ofdrm_model model; int width, height, depth, linebytes; const struct drm_format_info *format; u64 address; @@ -571,6 +663,39 @@ static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv, * OF display-node settings */ + model = display_get_model_of(dev, of_node); + drm_dbg(dev, "detected model %d\n", model); + + switch (model) { + case OFDRM_MODEL_UNKNOWN: + odev->funcs = &ofdrm_unknown_device_funcs; + break; + case OFDRM_MODEL_MACH64: + odev->funcs = &ofdrm_mach64_device_funcs; + break; + case OFDRM_MODEL_RAGE128: + odev->funcs = &ofdrm_rage128_device_funcs; + break; + case OFDRM_MODEL_RAGE_M3A: + odev->funcs = &ofdrm_rage_m3a_device_funcs; + break; + case OFDRM_MODEL_RAGE_M3B: + odev->funcs = &ofdrm_rage_m3b_device_funcs; + break; + case OFDRM_MODEL_RADEON: + odev->funcs = &ofdrm_radeon_device_funcs; + break; + case OFDRM_MODEL_GXT2000: + odev->funcs = &ofdrm_gxt2000_device_funcs; + break; + case OFDRM_MODEL_AVIVO: + odev->funcs = &ofdrm_avivo_device_funcs; + break; + case OFDRM_MODEL_QEMU: + odev->funcs = &ofdrm_qemu_device_funcs; + break; + } + width = display_get_width_of(dev, of_node); if (width < 0) return ERR_PTR(width); -- cgit From 4bbb9061081c49ded4908c7716a03f7faf4eb65d Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 11 Oct 2022 17:07:11 +0200 Subject: drm/ofdrm: Support color management Support the CRTC's color-management property and implement each model's palette support. The OF hardware has different methods of setting the palette. The respective code has been taken from fbdev's offb and refactored into per-model device functions. The device functions integrate this functionality into the overall modesetting. As palette handling is a CRTC property that depends on the primary plane's color format, the plane's atomic_check helper now updates the format field in ofdrm's custom CRTC state. The CRTC's atomic_flush helper updates the palette for the format as needed. v4: * use cpu_to_be32() (Geert) v3: * lookup CRTC state with drm_atomic_get_new_crtc_state() * access HW palette with writeb(), writel(), and readl() (Ben) * declare register values as u32 Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20221011150712.3928-5-tzimmermann@suse.de --- drivers/gpu/drm/tiny/ofdrm.c | 442 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 437 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/tiny/ofdrm.c b/drivers/gpu/drm/tiny/ofdrm.c index a0282a077238..3b0eaebd86f9 100644 --- a/drivers/gpu/drm/tiny/ofdrm.c +++ b/drivers/gpu/drm/tiny/ofdrm.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -31,6 +32,33 @@ #define PCI_VENDOR_ID_ATI_R520 0x7100 #define PCI_VENDOR_ID_ATI_R600 0x9400 +#define OFDRM_GAMMA_LUT_SIZE 256 + +/* Definitions used by the Avivo palette */ +#define AVIVO_DC_LUT_RW_SELECT 0x6480 +#define AVIVO_DC_LUT_RW_MODE 0x6484 +#define AVIVO_DC_LUT_RW_INDEX 0x6488 +#define AVIVO_DC_LUT_SEQ_COLOR 0x648c +#define AVIVO_DC_LUT_PWL_DATA 0x6490 +#define AVIVO_DC_LUT_30_COLOR 0x6494 +#define AVIVO_DC_LUT_READ_PIPE_SELECT 0x6498 +#define AVIVO_DC_LUT_WRITE_EN_MASK 0x649c +#define AVIVO_DC_LUT_AUTOFILL 0x64a0 +#define AVIVO_DC_LUTA_CONTROL 0x64c0 +#define AVIVO_DC_LUTA_BLACK_OFFSET_BLUE 0x64c4 +#define AVIVO_DC_LUTA_BLACK_OFFSET_GREEN 0x64c8 +#define AVIVO_DC_LUTA_BLACK_OFFSET_RED 0x64cc +#define AVIVO_DC_LUTA_WHITE_OFFSET_BLUE 0x64d0 +#define AVIVO_DC_LUTA_WHITE_OFFSET_GREEN 0x64d4 +#define AVIVO_DC_LUTA_WHITE_OFFSET_RED 0x64d8 +#define AVIVO_DC_LUTB_CONTROL 0x6cc0 +#define AVIVO_DC_LUTB_BLACK_OFFSET_BLUE 0x6cc4 +#define AVIVO_DC_LUTB_BLACK_OFFSET_GREEN 0x6cc8 +#define AVIVO_DC_LUTB_BLACK_OFFSET_RED 0x6ccc +#define AVIVO_DC_LUTB_WHITE_OFFSET_BLUE 0x6cd0 +#define AVIVO_DC_LUTB_WHITE_OFFSET_GREEN 0x6cd4 +#define AVIVO_DC_LUTB_WHITE_OFFSET_RED 0x6cd8 + enum ofdrm_model { OFDRM_MODEL_UNKNOWN, OFDRM_MODEL_MACH64, /* ATI Mach64 */ @@ -211,7 +239,14 @@ static enum ofdrm_model display_get_model_of(struct drm_device *dev, struct devi * Open Firmware display device */ +struct ofdrm_device; + struct ofdrm_device_funcs { + void __iomem *(*cmap_ioremap)(struct ofdrm_device *odev, + struct device_node *of_node, + u64 fb_bas); + void (*cmap_write)(struct ofdrm_device *odev, unsigned char index, + unsigned char r, unsigned char g, unsigned char b); }; struct ofdrm_device { @@ -226,6 +261,9 @@ struct ofdrm_device { const struct drm_format_info *format; unsigned int pitch; + /* colormap */ + void __iomem *cmap_base; + /* modesetting */ uint32_t formats[8]; struct drm_plane primary_plane; @@ -338,12 +376,322 @@ static struct resource *ofdrm_find_fb_resource(struct ofdrm_device *odev, return max_res; } +/* + * Colormap / Palette + */ + +static void __iomem *get_cmap_address_of(struct ofdrm_device *odev, struct device_node *of_node, + int bar_no, unsigned long offset, unsigned long size) +{ + struct drm_device *dev = &odev->dev; + const __be32 *addr_p; + u64 max_size, address; + unsigned int flags; + void __iomem *mem; + + addr_p = of_get_pci_address(of_node, bar_no, &max_size, &flags); + if (!addr_p) + addr_p = of_get_address(of_node, bar_no, &max_size, &flags); + if (!addr_p) + return ERR_PTR(-ENODEV); + + if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0) + return ERR_PTR(-ENODEV); + + if ((offset + size) >= max_size) + return ERR_PTR(-ENODEV); + + address = of_translate_address(of_node, addr_p); + if (address == OF_BAD_ADDR) + return ERR_PTR(-ENODEV); + + mem = devm_ioremap(dev->dev, address + offset, size); + if (!mem) + return ERR_PTR(-ENOMEM); + + return mem; +} + +static void __iomem *ofdrm_mach64_cmap_ioremap(struct ofdrm_device *odev, + struct device_node *of_node, + u64 fb_base) +{ + struct drm_device *dev = &odev->dev; + u64 address; + void __iomem *cmap_base; + + address = fb_base & 0xff000000ul; + address += 0x7ff000; + + cmap_base = devm_ioremap(dev->dev, address, 0x1000); + if (!cmap_base) + return ERR_PTR(-ENOMEM); + + return cmap_base; +} + +static void ofdrm_mach64_cmap_write(struct ofdrm_device *odev, unsigned char index, + unsigned char r, unsigned char g, unsigned char b) +{ + void __iomem *addr = odev->cmap_base + 0xcc0; + void __iomem *data = odev->cmap_base + 0xcc0 + 1; + + writeb(index, addr); + writeb(r, data); + writeb(g, data); + writeb(b, data); +} + +static void __iomem *ofdrm_rage128_cmap_ioremap(struct ofdrm_device *odev, + struct device_node *of_node, + u64 fb_base) +{ + return get_cmap_address_of(odev, of_node, 2, 0, 0x1fff); +} + +static void ofdrm_rage128_cmap_write(struct ofdrm_device *odev, unsigned char index, + unsigned char r, unsigned char g, unsigned char b) +{ + void __iomem *addr = odev->cmap_base + 0xb0; + void __iomem *data = odev->cmap_base + 0xb4; + u32 color = (r << 16) | (g << 8) | b; + + writeb(index, addr); + writel(color, data); +} + +static void __iomem *ofdrm_rage_m3a_cmap_ioremap(struct ofdrm_device *odev, + struct device_node *of_node, + u64 fb_base) +{ + return get_cmap_address_of(odev, of_node, 2, 0, 0x1fff); +} + +static void ofdrm_rage_m3a_cmap_write(struct ofdrm_device *odev, unsigned char index, + unsigned char r, unsigned char g, unsigned char b) +{ + void __iomem *dac_ctl = odev->cmap_base + 0x58; + void __iomem *addr = odev->cmap_base + 0xb0; + void __iomem *data = odev->cmap_base + 0xb4; + u32 color = (r << 16) | (g << 8) | b; + u32 val; + + /* Clear PALETTE_ACCESS_CNTL in DAC_CNTL */ + val = readl(dac_ctl); + val &= ~0x20; + writel(val, dac_ctl); + + /* Set color at palette index */ + writeb(index, addr); + writel(color, data); +} + +static void __iomem *ofdrm_rage_m3b_cmap_ioremap(struct ofdrm_device *odev, + struct device_node *of_node, + u64 fb_base) +{ + return get_cmap_address_of(odev, of_node, 2, 0, 0x1fff); +} + +static void ofdrm_rage_m3b_cmap_write(struct ofdrm_device *odev, unsigned char index, + unsigned char r, unsigned char g, unsigned char b) +{ + void __iomem *dac_ctl = odev->cmap_base + 0x58; + void __iomem *addr = odev->cmap_base + 0xb0; + void __iomem *data = odev->cmap_base + 0xb4; + u32 color = (r << 16) | (g << 8) | b; + u32 val; + + /* Set PALETTE_ACCESS_CNTL in DAC_CNTL */ + val = readl(dac_ctl); + val |= 0x20; + writel(val, dac_ctl); + + /* Set color at palette index */ + writeb(index, addr); + writel(color, data); +} + +static void __iomem *ofdrm_radeon_cmap_ioremap(struct ofdrm_device *odev, + struct device_node *of_node, + u64 fb_base) +{ + return get_cmap_address_of(odev, of_node, 1, 0, 0x1fff); +} + +static void __iomem *ofdrm_gxt2000_cmap_ioremap(struct ofdrm_device *odev, + struct device_node *of_node, + u64 fb_base) +{ + return get_cmap_address_of(odev, of_node, 0, 0x6000, 0x1000); +} + +static void ofdrm_gxt2000_cmap_write(struct ofdrm_device *odev, unsigned char index, + unsigned char r, unsigned char g, unsigned char b) +{ + void __iomem *data = ((unsigned int __iomem *)odev->cmap_base) + index; + u32 color = (r << 16) | (g << 8) | b; + + writel(color, data); +} + +static void __iomem *ofdrm_avivo_cmap_ioremap(struct ofdrm_device *odev, + struct device_node *of_node, + u64 fb_base) +{ + struct device_node *of_parent; + void __iomem *cmap_base; + + of_parent = of_get_parent(of_node); + cmap_base = get_cmap_address_of(odev, of_parent, 0, 0, 0x10000); + of_node_put(of_parent); + + return cmap_base; +} + +static void ofdrm_avivo_cmap_write(struct ofdrm_device *odev, unsigned char index, + unsigned char r, unsigned char g, unsigned char b) +{ + void __iomem *lutsel = odev->cmap_base + AVIVO_DC_LUT_RW_SELECT; + void __iomem *addr = odev->cmap_base + AVIVO_DC_LUT_RW_INDEX; + void __iomem *data = odev->cmap_base + AVIVO_DC_LUT_30_COLOR; + u32 color = (r << 22) | (g << 12) | (b << 2); + + /* Write to both LUTs for now */ + + writel(1, lutsel); + writeb(index, addr); + writel(color, data); + + writel(0, lutsel); + writeb(index, addr); + writel(color, data); +} + +static void __iomem *ofdrm_qemu_cmap_ioremap(struct ofdrm_device *odev, + struct device_node *of_node, + u64 fb_base) +{ + static const __be32 io_of_addr[3] = { + cpu_to_be32(0x01000000), + cpu_to_be32(0x00), + cpu_to_be32(0x00), + }; + + struct drm_device *dev = &odev->dev; + u64 address; + void __iomem *cmap_base; + + address = of_translate_address(of_node, io_of_addr); + if (address == OF_BAD_ADDR) + return ERR_PTR(-ENODEV); + + cmap_base = devm_ioremap(dev->dev, address + 0x3c8, 2); + if (!cmap_base) + return ERR_PTR(-ENOMEM); + + return cmap_base; +} + +static void ofdrm_qemu_cmap_write(struct ofdrm_device *odev, unsigned char index, + unsigned char r, unsigned char g, unsigned char b) +{ + void __iomem *addr = odev->cmap_base; + void __iomem *data = odev->cmap_base + 1; + + writeb(index, addr); + writeb(r, data); + writeb(g, data); + writeb(b, data); +} + +static void ofdrm_device_set_gamma_linear(struct ofdrm_device *odev, + const struct drm_format_info *format) +{ + struct drm_device *dev = &odev->dev; + int i; + + switch (format->format) { + case DRM_FORMAT_RGB565: + /* Use better interpolation, to take 32 values from 0 to 255 */ + for (i = 0; i < OFDRM_GAMMA_LUT_SIZE / 8; i++) { + unsigned char r = i * 8 + i / 4; + unsigned char g = i * 4 + i / 16; + unsigned char b = i * 8 + i / 4; + + odev->funcs->cmap_write(odev, i, r, g, b); + } + /* Green has one more bit, so add padding with 0 for red and blue. */ + for (i = OFDRM_GAMMA_LUT_SIZE / 8; i < OFDRM_GAMMA_LUT_SIZE / 4; i++) { + unsigned char r = 0; + unsigned char g = i * 4 + i / 16; + unsigned char b = 0; + + odev->funcs->cmap_write(odev, i, r, g, b); + } + break; + case DRM_FORMAT_XRGB8888: + for (i = 0; i < OFDRM_GAMMA_LUT_SIZE; i++) + odev->funcs->cmap_write(odev, i, i, i, i); + break; + default: + drm_warn_once(dev, "Unsupported format %p4cc for gamma correction\n", + &format->format); + break; + } +} + +static void ofdrm_device_set_gamma(struct ofdrm_device *odev, + const struct drm_format_info *format, + struct drm_color_lut *lut) +{ + struct drm_device *dev = &odev->dev; + int i; + + switch (format->format) { + case DRM_FORMAT_RGB565: + /* Use better interpolation, to take 32 values from lut[0] to lut[255] */ + for (i = 0; i < OFDRM_GAMMA_LUT_SIZE / 8; i++) { + unsigned char r = lut[i * 8 + i / 4].red >> 8; + unsigned char g = lut[i * 4 + i / 16].green >> 8; + unsigned char b = lut[i * 8 + i / 4].blue >> 8; + + odev->funcs->cmap_write(odev, i, r, g, b); + } + /* Green has one more bit, so add padding with 0 for red and blue. */ + for (i = OFDRM_GAMMA_LUT_SIZE / 8; i < OFDRM_GAMMA_LUT_SIZE / 4; i++) { + unsigned char r = 0; + unsigned char g = lut[i * 4 + i / 16].green >> 8; + unsigned char b = 0; + + odev->funcs->cmap_write(odev, i, r, g, b); + } + break; + case DRM_FORMAT_XRGB8888: + for (i = 0; i < OFDRM_GAMMA_LUT_SIZE; i++) { + unsigned char r = lut[i].red >> 8; + unsigned char g = lut[i].green >> 8; + unsigned char b = lut[i].blue >> 8; + + odev->funcs->cmap_write(odev, i, r, g, b); + } + break; + default: + drm_warn_once(dev, "Unsupported format %p4cc for gamma correction\n", + &format->format); + break; + } +} + /* * Modesetting */ struct ofdrm_crtc_state { struct drm_crtc_state base; + + /* Primary-plane format; required for color mgmt. */ + const struct drm_format_info *format; }; static struct ofdrm_crtc_state *to_ofdrm_crtc_state(struct drm_crtc_state *base) @@ -381,16 +729,30 @@ static int ofdrm_primary_plane_helper_atomic_check(struct drm_plane *plane, struct drm_atomic_state *new_state) { struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(new_state, plane); + struct drm_framebuffer *new_fb = new_plane_state->fb; struct drm_crtc *new_crtc = new_plane_state->crtc; struct drm_crtc_state *new_crtc_state = NULL; + struct ofdrm_crtc_state *new_ofdrm_crtc_state; + int ret; if (new_crtc) new_crtc_state = drm_atomic_get_new_crtc_state(new_state, new_plane_state->crtc); - return drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state, - DRM_PLANE_NO_SCALING, - DRM_PLANE_NO_SCALING, - false, false); + ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, + false, false); + if (ret) + return ret; + else if (!new_plane_state->visible) + return 0; + + new_crtc_state = drm_atomic_get_new_crtc_state(new_state, new_plane_state->crtc); + + new_ofdrm_crtc_state = to_ofdrm_crtc_state(new_crtc_state); + new_ofdrm_crtc_state->format = new_fb->format; + + return 0; } static void ofdrm_primary_plane_helper_atomic_update(struct drm_plane *plane, @@ -492,12 +854,45 @@ static enum drm_mode_status ofdrm_crtc_helper_mode_valid(struct drm_crtc *crtc, static int ofdrm_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *new_state) { + static const size_t gamma_lut_length = OFDRM_GAMMA_LUT_SIZE * sizeof(struct drm_color_lut); + + struct drm_device *dev = crtc->dev; struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc); + int ret; if (!new_crtc_state->enable) return 0; - return drm_atomic_helper_check_crtc_primary_plane(new_crtc_state); + ret = drm_atomic_helper_check_crtc_primary_plane(new_crtc_state); + if (ret) + return ret; + + if (new_crtc_state->color_mgmt_changed) { + struct drm_property_blob *gamma_lut = new_crtc_state->gamma_lut; + + if (gamma_lut && (gamma_lut->length != gamma_lut_length)) { + drm_dbg(dev, "Incorrect gamma_lut length %zu\n", gamma_lut->length); + return -EINVAL; + } + } + + return 0; +} + +static void ofdrm_crtc_helper_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *state) +{ + struct ofdrm_device *odev = ofdrm_device_of_dev(crtc->dev); + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + struct ofdrm_crtc_state *ofdrm_crtc_state = to_ofdrm_crtc_state(crtc_state); + + if (crtc_state->enable && crtc_state->color_mgmt_changed) { + const struct drm_format_info *format = ofdrm_crtc_state->format; + + if (crtc_state->gamma_lut) + ofdrm_device_set_gamma(odev, format, crtc_state->gamma_lut->data); + else + ofdrm_device_set_gamma_linear(odev, format); + } } /* @@ -508,6 +903,7 @@ static int ofdrm_crtc_helper_atomic_check(struct drm_crtc *crtc, static const struct drm_crtc_helper_funcs ofdrm_crtc_helper_funcs = { .mode_valid = ofdrm_crtc_helper_mode_valid, .atomic_check = ofdrm_crtc_helper_atomic_check, + .atomic_flush = ofdrm_crtc_helper_atomic_flush, }; static void ofdrm_crtc_reset(struct drm_crtc *crtc) @@ -529,6 +925,7 @@ static struct drm_crtc_state *ofdrm_crtc_atomic_duplicate_state(struct drm_crtc struct drm_device *dev = crtc->dev; struct drm_crtc_state *crtc_state = crtc->state; struct ofdrm_crtc_state *new_ofdrm_crtc_state; + struct ofdrm_crtc_state *ofdrm_crtc_state; if (drm_WARN_ON(dev, !crtc_state)) return NULL; @@ -537,7 +934,10 @@ static struct drm_crtc_state *ofdrm_crtc_atomic_duplicate_state(struct drm_crtc if (!new_ofdrm_crtc_state) return NULL; + ofdrm_crtc_state = to_ofdrm_crtc_state(crtc_state); + __drm_atomic_helper_crtc_duplicate_state(crtc, &new_ofdrm_crtc_state->base); + new_ofdrm_crtc_state->format = ofdrm_crtc_state->format; return &new_ofdrm_crtc_state->base; } @@ -590,27 +990,43 @@ static const struct ofdrm_device_funcs ofdrm_unknown_device_funcs = { }; static const struct ofdrm_device_funcs ofdrm_mach64_device_funcs = { + .cmap_ioremap = ofdrm_mach64_cmap_ioremap, + .cmap_write = ofdrm_mach64_cmap_write, }; static const struct ofdrm_device_funcs ofdrm_rage128_device_funcs = { + .cmap_ioremap = ofdrm_rage128_cmap_ioremap, + .cmap_write = ofdrm_rage128_cmap_write, }; static const struct ofdrm_device_funcs ofdrm_rage_m3a_device_funcs = { + .cmap_ioremap = ofdrm_rage_m3a_cmap_ioremap, + .cmap_write = ofdrm_rage_m3a_cmap_write, }; static const struct ofdrm_device_funcs ofdrm_rage_m3b_device_funcs = { + .cmap_ioremap = ofdrm_rage_m3b_cmap_ioremap, + .cmap_write = ofdrm_rage_m3b_cmap_write, }; static const struct ofdrm_device_funcs ofdrm_radeon_device_funcs = { + .cmap_ioremap = ofdrm_radeon_cmap_ioremap, + .cmap_write = ofdrm_rage128_cmap_write, /* same as Rage128 */ }; static const struct ofdrm_device_funcs ofdrm_gxt2000_device_funcs = { + .cmap_ioremap = ofdrm_gxt2000_cmap_ioremap, + .cmap_write = ofdrm_gxt2000_cmap_write, }; static const struct ofdrm_device_funcs ofdrm_avivo_device_funcs = { + .cmap_ioremap = ofdrm_avivo_cmap_ioremap, + .cmap_write = ofdrm_avivo_cmap_write, }; static const struct ofdrm_device_funcs ofdrm_qemu_device_funcs = { + .cmap_ioremap = ofdrm_qemu_cmap_ioremap, + .cmap_write = ofdrm_qemu_cmap_write, }; static struct drm_display_mode ofdrm_mode(unsigned int width, unsigned int height) @@ -773,6 +1189,17 @@ static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv, if (!screen_base) return ERR_PTR(-ENOMEM); + if (odev->funcs->cmap_ioremap) { + void __iomem *cmap_base = odev->funcs->cmap_ioremap(odev, of_node, fb_base); + + if (IS_ERR(cmap_base)) { + /* Don't fail; continue without colormap */ + drm_warn(dev, "could not find colormap: error %ld\n", PTR_ERR(cmap_base)); + } else { + odev->cmap_base = cmap_base; + } + } + /* * Firmware framebuffer */ @@ -837,6 +1264,11 @@ static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv, return ERR_PTR(ret); drm_crtc_helper_add(crtc, &ofdrm_crtc_helper_funcs); + if (odev->cmap_base) { + drm_mode_crtc_set_gamma_size(crtc, OFDRM_GAMMA_LUT_SIZE); + drm_crtc_enable_color_mgmt(crtc, 0, false, OFDRM_GAMMA_LUT_SIZE); + } + /* Encoder */ encoder = &odev->encoder; -- cgit From d405bc2c3d82126f58e143708af55105876cf6af Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 11 Oct 2022 17:07:12 +0200 Subject: drm/ofdrm: Support big-endian scanout buffers All DRM formats assume little-endian byte order. On big-endian systems, it is likely that the scanout buffer is in big endian as well. Update the format accordingly and add endianness conversion to the format-helper library. Also opt-in to allocated buffers in host format by default. Suggested-by: Geert Uytterhoeven Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20221011150712.3928-6-tzimmermann@suse.de --- drivers/gpu/drm/drm_format_helper.c | 10 +++++++ drivers/gpu/drm/tiny/ofdrm.c | 55 +++++++++++++++++++++++++++++++++++-- 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c index e2f76621453c..653a5821dd53 100644 --- a/drivers/gpu/drm/drm_format_helper.c +++ b/drivers/gpu/drm/drm_format_helper.c @@ -660,6 +660,11 @@ int drm_fb_blit(struct iosys_map *dst, const unsigned int *dst_pitch, uint32_t d drm_fb_xrgb8888_to_rgb565(dst, dst_pitch, src, fb, clip, false); return 0; } + } else if (dst_format == (DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN)) { + if (fb_format == DRM_FORMAT_RGB565) { + drm_fb_swab(dst, dst_pitch, src, fb, clip, false); + return 0; + } } else if (dst_format == DRM_FORMAT_RGB888) { if (fb_format == DRM_FORMAT_XRGB8888) { drm_fb_xrgb8888_to_rgb888(dst, dst_pitch, src, fb, clip); @@ -678,6 +683,11 @@ int drm_fb_blit(struct iosys_map *dst, const unsigned int *dst_pitch, uint32_t d drm_fb_xrgb8888_to_xrgb2101010(dst, dst_pitch, src, fb, clip); return 0; } + } else if (dst_format == DRM_FORMAT_BGRX8888) { + if (fb_format == DRM_FORMAT_XRGB8888) { + drm_fb_swab(dst, dst_pitch, src, fb, clip, false); + return 0; + } } drm_warn_once(fb->dev, "No conversion helper from %p4cc to %p4cc found.\n", diff --git a/drivers/gpu/drm/tiny/ofdrm.c b/drivers/gpu/drm/tiny/ofdrm.c index 3b0eaebd86f9..0e1cc2369afc 100644 --- a/drivers/gpu/drm/tiny/ofdrm.c +++ b/drivers/gpu/drm/tiny/ofdrm.c @@ -94,7 +94,7 @@ static int display_get_validated_int0(struct drm_device *dev, const char *name, } static const struct drm_format_info *display_get_validated_format(struct drm_device *dev, - u32 depth) + u32 depth, bool big_endian) { const struct drm_format_info *info; u32 format; @@ -115,6 +115,29 @@ static const struct drm_format_info *display_get_validated_format(struct drm_dev return ERR_PTR(-EINVAL); } + /* + * DRM formats assume little-endian byte order. Update the format + * if the scanout buffer uses big-endian ordering. + */ + if (big_endian) { + switch (format) { + case DRM_FORMAT_XRGB8888: + format = DRM_FORMAT_BGRX8888; + break; + case DRM_FORMAT_ARGB8888: + format = DRM_FORMAT_BGRA8888; + break; + case DRM_FORMAT_RGB565: + format = DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN; + break; + case DRM_FORMAT_XRGB1555: + format = DRM_FORMAT_XRGB1555 | DRM_FORMAT_BIG_ENDIAN; + break; + default: + break; + } + } + info = drm_format_info(format); if (!info) { drm_err(dev, "cannot find framebuffer format for depth %u\n", depth); @@ -134,6 +157,23 @@ static int display_read_u32_of(struct drm_device *dev, struct device_node *of_no return ret; } +static bool display_get_big_endian_of(struct drm_device *dev, struct device_node *of_node) +{ + bool big_endian; + +#ifdef __BIG_ENDIAN + big_endian = true; + if (of_get_property(of_node, "little-endian", NULL)) + big_endian = false; +#else + big_endian = false; + if (of_get_property(of_node, "big-endian", NULL)) + big_endian = true; +#endif + + return big_endian; +} + static int display_get_width_of(struct drm_device *dev, struct device_node *of_node) { u32 width; @@ -613,6 +653,7 @@ static void ofdrm_device_set_gamma_linear(struct ofdrm_device *odev, switch (format->format) { case DRM_FORMAT_RGB565: + case DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN: /* Use better interpolation, to take 32 values from 0 to 255 */ for (i = 0; i < OFDRM_GAMMA_LUT_SIZE / 8; i++) { unsigned char r = i * 8 + i / 4; @@ -631,6 +672,7 @@ static void ofdrm_device_set_gamma_linear(struct ofdrm_device *odev, } break; case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_BGRX8888: for (i = 0; i < OFDRM_GAMMA_LUT_SIZE; i++) odev->funcs->cmap_write(odev, i, i, i, i); break; @@ -650,6 +692,7 @@ static void ofdrm_device_set_gamma(struct ofdrm_device *odev, switch (format->format) { case DRM_FORMAT_RGB565: + case DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN: /* Use better interpolation, to take 32 values from lut[0] to lut[255] */ for (i = 0; i < OFDRM_GAMMA_LUT_SIZE / 8; i++) { unsigned char r = lut[i * 8 + i / 4].red >> 8; @@ -668,6 +711,7 @@ static void ofdrm_device_set_gamma(struct ofdrm_device *odev, } break; case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_BGRX8888: for (i = 0; i < OFDRM_GAMMA_LUT_SIZE; i++) { unsigned char r = lut[i].red >> 8; unsigned char g = lut[i].green >> 8; @@ -718,6 +762,9 @@ static const uint32_t ofdrm_primary_plane_formats[] = { DRM_FORMAT_RGB565, //DRM_FORMAT_XRGB1555, //DRM_FORMAT_C8, + /* Big-endian formats below */ + DRM_FORMAT_BGRX8888, + DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN, }; static const uint64_t ofdrm_primary_plane_format_modifiers[] = { @@ -1051,6 +1098,7 @@ static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv, struct ofdrm_device *odev; struct drm_device *dev; enum ofdrm_model model; + bool big_endian; int width, height, depth, linebytes; const struct drm_format_info *format; u64 address; @@ -1112,6 +1160,8 @@ static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv, break; } + big_endian = display_get_big_endian_of(dev, of_node); + width = display_get_width_of(dev, of_node); if (width < 0) return ERR_PTR(width); @@ -1125,7 +1175,7 @@ static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv, if (linebytes < 0) return ERR_PTR(linebytes); - format = display_get_validated_format(dev, depth); + format = display_get_validated_format(dev, depth, big_endian); if (IS_ERR(format)) return ERR_CAST(format); if (!linebytes) { @@ -1237,6 +1287,7 @@ static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv, dev->mode_config.preferred_depth = depth; break; } + dev->mode_config.quirk_addfb_prefer_host_byte_order = true; /* Primary plane */ -- cgit From e8162192636577dcfd87a530b7e6ab10559d6089 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Fri, 7 Oct 2022 16:33:07 +0300 Subject: drm/i915: Fix simulated GPU reset wrt. encoder HW readout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The GPU reset involves a display suspend/resume sequence, but this is done without suspending/resuming the encoders. The encoder HW readout code during resume however assumes that the encoders were suspended/resumed, at least on TypeC platforms where the TC PHYs must be left in a disconnected state during encoder-suspend, and the PHY's TypeC mode must be initialized already during encoder-resume. Since the above issue occurs only in case the display recovery during GPU reset is simulated in CI tests (on new platforms w/o the GPU reset clobbering the display), this patch fixes the issue by simply restoring the saved display state in this case w/o doing a display HW state readout / sanitization first. This also fixes the WARN below introduced by commit a82796a2e332 ("drm/i915: Fix TypeC mode initialization during system resume") <4> [319.983309] ------------[ cut here ]------------ <4> [319.983313] i915 0000:00:02.0: drm_WARN_ON(dig_port->tc_link_refcount != 1) <4> [319.983341] WARNING: CPU: 10 PID: 268 at drivers/gpu/drm/i915/display/intel_tc.c:751 intel_tc_port_sanitize_mode+0x239/0x290 [i915] <4> [319.983407] Modules linked in: fuse snd_hda_codec_hdmi i915 x86_pkg_temp_thermal mei_hdcp coretemp wmi_bmof r8153_ecm cdc_ether kvm_intel usbnet r8152 mii kvm prime_numbers snd_hda_intel ttm snd_intel_dspcfg irqbypass drm_buddy e1000e crct10dif_pclmul snd_hda_codec crc32_pclmul drm_display_helper ptp snd_hwdep ghash_clmulni_intel snd_hda_core drm_kms_helper pps_core mei_me syscopyarea video i2c_i801 snd_pcm sysfillrect i2c_smbus sysimgblt mei fb_sys_fops intel_lpss_pci wmi <4> [319.983483] CPU: 10 PID: 268 Comm: kworker/10:1H Not tainted 6.0.0-rc7-CI_DRM_12200-g394e575b57e9+ #1 <4> [319.983486] Hardware name: Intel Corporation Alder Lake Client Platform/AlderLake-P LP5 RVP, BIOS ADLPFWI1.R00.2313.A00.2107301001 07/30/2021 <4> [319.983488] Workqueue: events_highpri heartbeat [i915] <4> [319.983536] RIP: 0010:intel_tc_port_sanitize_mode+0x239/0x290 [i915] <4> [319.983600] Code: 85 d2 75 03 48 8b 17 48 89 14 24 e8 e1 dc 2d e1 48 8b 14 24 48 c7 c1 f8 db 5b a0 48 c7 c7 3e 3c 5e a0 48 89 c6 e8 45 d7 66 e1 <0f> 0b e9 20 fe ff ff 0f 0b 49 c7 c0 8b 3c 5e a0 e9 9e fe ff ff 48 <4> [319.983601] RSP: 0018:ffffc90001617a30 EFLAGS: 00010286 <4> [319.983604] RAX: 0000000000000000 RBX: ffff88811f9d2000 RCX: 0000000000000001 <4> [319.983606] RDX: 0000000080000001 RSI: ffffffff8231e8cd RDI: 00000000ffffffff <4> [319.983607] RBP: ffff888121e98000 R08: 0000000000000000 R09: c0000000ffffc134 <4> [319.983608] R10: 00000000000d6078 R11: ffffc900016178c8 R12: ffff88811f9d3838 <4> [319.983609] R13: ffff88811f9d397d R14: ffff888121e98000 R15: 0000000000000000 <4> [319.983611] FS: 0000000000000000(0000) GS:ffff8882a7300000(0000) knlGS:0000000000000000 <4> [319.983612] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 <4> [319.983613] CR2: 00007fe7397f1e18 CR3: 0000000006612003 CR4: 0000000000770ee0 <4> [319.983615] PKRU: 55555554 <4> [319.983616] Call Trace: <4> [319.983617] <4> [319.983621] intel_ddi_sync_state+0x3f/0x90 [i915] <4> [319.983698] intel_modeset_setup_hw_state+0x3a3/0x1440 [i915] <4> [319.983777] ? intel_gt_reset_global+0xeb/0x160 [i915] <4> [319.983839] ? __intel_display_resume+0x15/0xe0 [i915] <4> [319.983909] __intel_display_resume+0x15/0xe0 [i915] <4> [319.983979] intel_display_finish_reset+0x58/0x130 [i915] <4> [319.984048] intel_gt_reset_global+0xf3/0x160 [i915] <4> [319.984107] ? intel_reset_guc.cold.62+0x5d/0x5d [i915] <4> [319.984189] ? 0xffffffff81000000 <4> [319.984192] ? queue_work_node+0x90/0x90 <4> [319.984202] intel_gt_handle_error+0x2c2/0x410 [i915] <4> [319.984267] ? _raw_spin_unlock_irqrestore+0x54/0x70 <4> [319.984271] ? lockdep_hardirqs_on+0xbf/0x140 <4> [319.984276] ? intel_guc_find_hung_context+0x19e/0x1d0 [i915] <4> [319.984352] reset_engine+0x99/0xd0 [i915] <4> [319.984399] ? __drm_printfn_seq_file+0x20/0x20 <4> [319.984406] heartbeat+0x4cd/0x4f0 [i915] <4> [319.984454] process_one_work+0x272/0x5b0 <4> [319.984461] worker_thread+0x37/0x370 <4> [319.984465] ? process_one_work+0x5b0/0x5b0 <4> [319.984467] kthread+0xed/0x120 <4> [319.984470] ? kthread_complete_and_exit+0x20/0x20 <4> [319.984474] ret_from_fork+0x1f/0x30 <4> [319.984484] <4> [319.984485] irq event stamp: 36107 <4> [319.984487] hardirqs last enabled at (36113): [] __up_console_sem+0x66/0x70 <4> [319.984492] hardirqs last disabled at (36118): [] __up_console_sem+0x4b/0x70 <4> [319.984494] softirqs last enabled at (34316): [] __do_softirq+0x323/0x48e <4> [319.984497] softirqs last disabled at (34309): [] irq_exit_rcu+0xb8/0xe0 <4> [319.984499] ---[ end trace 0000000000000000 ]--- v2: - Instead of trying to fix the suspend/resume sequence, restore simply the state w/o the HW readout/sanitization step. (Ville) References: https://lore.kernel.org/intel-gfx/20221005175251.3586272-1-imre.deak@intel.com/T/#mcfac180a67f6048096d09fa04347aa088291fafb Closes: https://gitlab.freedesktop.org/drm/intel/issues/7021 Cc: Mika Kahola Cc: Ville Syrjälä Signed-off-by: Imre Deak Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221007133307.3805735-1-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index a31d7e890f61..d014d3ef35e4 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -830,6 +830,20 @@ intel_plane_fence_y_offset(const struct intel_plane_state *plane_state) return y; } +static int +intel_display_commit_duplicated_state(struct intel_atomic_state *state, + struct drm_modeset_acquire_ctx *ctx) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); + int ret; + + ret = drm_atomic_helper_commit_duplicated_state(&state->base, ctx); + + drm_WARN_ON(&i915->drm, ret == -EDEADLK); + + return ret; +} + static int __intel_display_resume(struct drm_i915_private *i915, struct drm_atomic_state *state, @@ -837,7 +851,7 @@ __intel_display_resume(struct drm_i915_private *i915, { struct drm_crtc_state *crtc_state; struct drm_crtc *crtc; - int i, ret; + int i; intel_modeset_setup_hw_state(i915, ctx); intel_vga_redisable(i915); @@ -863,11 +877,7 @@ __intel_display_resume(struct drm_i915_private *i915, if (!HAS_GMCH(i915)) to_intel_atomic_state(state)->skip_intermediate_wm = true; - ret = drm_atomic_helper_commit_duplicated_state(state, ctx); - - drm_WARN_ON(&i915->drm, ret == -EDEADLK); - - return ret; + return intel_display_commit_duplicated_state(to_intel_atomic_state(state), ctx); } static bool gpu_reset_clobbers_display(struct drm_i915_private *dev_priv) @@ -958,7 +968,7 @@ void intel_display_finish_reset(struct drm_i915_private *i915) /* reset doesn't touch the display */ if (!gpu_reset_clobbers_display(i915)) { /* for testing only restore the display */ - ret = __intel_display_resume(i915, state, ctx); + ret = intel_display_commit_duplicated_state(to_intel_atomic_state(state), ctx); if (ret) drm_err(&i915->drm, "Restoring old state failed with %i\n", ret); -- cgit From 8133a6daad4e72748e239a02775a853ca7ed798b Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Tue, 4 Oct 2022 12:49:14 +0100 Subject: drm/i915: enable PS64 support for DG2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It turns out that on production DG2/ATS HW we should have support for PS64. This feature allows to provide a 64K TLB hint at the PTE level, which is a lot more flexible than the current method of enabling 64K GTT pages for the entire page-table, since that leads to all kinds of annoying restrictions, as documented in: commit caa574ffc4aaf4f29b890223878c63e2e7772f62 Author: Matthew Auld Date: Sat Feb 19 00:17:49 2022 +0530 drm/i915/uapi: document behaviour for DG2 64K support On discrete platforms like DG2, we need to support a minimum page size of 64K when dealing with device local-memory. This is quite tricky for various reasons, so try to document the new implicit uapi for this. With PS64, we can now drop the 2M GTT alignment restriction, and instead only require 64K or larger when dealing with lmem. We still use the compact-pt layout when possible, but only when we are certain that this doesn't interfere with userspace. Note that this is a change in uAPI behaviour, but hopefully shouldn't be a concern (IGT is at least able to autodetect the alignment), since we are only making the GTT alignment constraint less restrictive. Based on a patch from CQ Tang. v2: update the comment wrt scratch page v3: (Nirmoy) - Fix the selftest to actually use the random size, plus some comment improvements, also drop the rem stuff. Reported-by: Michal Mrozek Signed-off-by: Matthew Auld Cc: Lionel Landwerlin Cc: Thomas Hellström Cc: Stuart Summers Cc: Jordan Justen Cc: Yang A Shi Cc: Nirmoy Das Cc: Niranjana Vishwanathapura Reviewed-by: Nirmoy Das Acked-by: Michal Mrozek Link: https://patchwork.freedesktop.org/patch/msgid/20221004114915.221708-1-matthew.auld@intel.com --- drivers/gpu/drm/i915/gem/selftests/huge_pages.c | 157 +++++++++++++++++++++++- drivers/gpu/drm/i915/gt/gen8_ppgtt.c | 81 ++++++------ drivers/gpu/drm/i915/gt/intel_gtt.c | 21 +--- drivers/gpu/drm/i915/gt/intel_gtt.h | 1 + drivers/gpu/drm/i915/i915_drv.h | 7 -- drivers/gpu/drm/i915/i915_pci.c | 2 - drivers/gpu/drm/i915/i915_vma.c | 9 +- drivers/gpu/drm/i915/intel_device_info.h | 1 - drivers/gpu/drm/i915/selftests/i915_gem_gtt.c | 9 +- include/uapi/drm/i915_drm.h | 36 ++---- 10 files changed, 218 insertions(+), 106 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/selftests/huge_pages.c b/drivers/gpu/drm/i915/gem/selftests/huge_pages.c index c570cf780079..0cb99e75b0bc 100644 --- a/drivers/gpu/drm/i915/gem/selftests/huge_pages.c +++ b/drivers/gpu/drm/i915/gem/selftests/huge_pages.c @@ -1161,7 +1161,8 @@ static int igt_write_huge(struct drm_i915_private *i915, GEM_BUG_ON(!i915_gem_object_has_pinned_pages(obj)); size = obj->base.size; - if (obj->mm.page_sizes.sg & I915_GTT_PAGE_SIZE_64K) + if (obj->mm.page_sizes.sg & I915_GTT_PAGE_SIZE_64K && + !HAS_64K_PAGES(i915)) size = round_up(size, I915_GTT_PAGE_SIZE_2M); n = 0; @@ -1214,6 +1215,10 @@ static int igt_write_huge(struct drm_i915_private *i915, * size and ensure the vma offset is at the start of the pt * boundary, however to improve coverage we opt for testing both * aligned and unaligned offsets. + * + * With PS64 this is no longer the case, but to ensure we + * sometimes get the compact layout for smaller objects, apply + * the round_up anyway. */ if (obj->mm.page_sizes.sg & I915_GTT_PAGE_SIZE_64K) offset_low = round_down(offset_low, @@ -1411,6 +1416,7 @@ static int igt_ppgtt_sanity_check(void *arg) { SZ_2M + SZ_4K, SZ_64K | SZ_4K }, { SZ_2M + SZ_4K, SZ_2M | SZ_4K }, { SZ_2M + SZ_64K, SZ_2M | SZ_64K }, + { SZ_2M + SZ_64K, SZ_64K }, }; int i, j; int err; @@ -1540,6 +1546,154 @@ out_put: return err; } +static int igt_ppgtt_mixed(void *arg) +{ + struct drm_i915_private *i915 = arg; + const unsigned long flags = PIN_OFFSET_FIXED | PIN_USER; + struct drm_i915_gem_object *obj, *on; + struct i915_gem_engines *engines; + struct i915_gem_engines_iter it; + struct i915_address_space *vm; + struct i915_gem_context *ctx; + struct intel_context *ce; + struct file *file; + I915_RND_STATE(prng); + LIST_HEAD(objects); + struct intel_memory_region *mr; + struct i915_vma *vma; + unsigned int count; + u32 i, addr; + int *order; + int n, err; + + /* + * Sanity check mixing 4K and 64K pages within the same page-table via + * the new PS64 TLB hint. + */ + + if (!HAS_64K_PAGES(i915)) { + pr_info("device lacks PS64, skipping\n"); + return 0; + } + + file = mock_file(i915); + if (IS_ERR(file)) + return PTR_ERR(file); + + ctx = hugepage_ctx(i915, file); + if (IS_ERR(ctx)) { + err = PTR_ERR(ctx); + goto out; + } + vm = i915_gem_context_get_eb_vm(ctx); + + i = 0; + addr = 0; + do { + u32 sz; + + sz = i915_prandom_u32_max_state(SZ_4M, &prng); + sz = max_t(u32, sz, SZ_4K); + + mr = i915->mm.regions[INTEL_REGION_LMEM_0]; + if (i & 1) + mr = i915->mm.regions[INTEL_REGION_SMEM]; + + obj = i915_gem_object_create_region(mr, sz, 0, 0); + if (IS_ERR(obj)) { + err = PTR_ERR(obj); + goto out_vm; + } + + list_add_tail(&obj->st_link, &objects); + + vma = i915_vma_instance(obj, vm, NULL); + if (IS_ERR(vma)) { + err = PTR_ERR(vma); + goto err_put; + } + + addr = round_up(addr, mr->min_page_size); + err = i915_vma_pin(vma, 0, 0, addr | flags); + if (err) + goto err_put; + + if (mr->type == INTEL_MEMORY_LOCAL && + (vma->resource->page_sizes_gtt & I915_GTT_PAGE_SIZE_4K)) { + err = -EINVAL; + goto err_put; + } + + addr += obj->base.size; + i++; + } while (addr <= SZ_16M); + + n = 0; + count = 0; + for_each_gem_engine(ce, i915_gem_context_lock_engines(ctx), it) { + count++; + if (!intel_engine_can_store_dword(ce->engine)) + continue; + + n++; + } + i915_gem_context_unlock_engines(ctx); + if (!n) + goto err_put; + + order = i915_random_order(count * count, &prng); + if (!order) { + err = -ENOMEM; + goto err_put; + } + + i = 0; + addr = 0; + engines = i915_gem_context_lock_engines(ctx); + list_for_each_entry(obj, &objects, st_link) { + u32 rnd = i915_prandom_u32_max_state(UINT_MAX, &prng); + + addr = round_up(addr, obj->mm.region->min_page_size); + + ce = engines->engines[order[i] % engines->num_engines]; + i = (i + 1) % (count * count); + if (!ce || !intel_engine_can_store_dword(ce->engine)) + continue; + + err = __igt_write_huge(ce, obj, obj->base.size, addr, 0, rnd); + if (err) + break; + + err = __igt_write_huge(ce, obj, obj->base.size, addr, + offset_in_page(rnd) / sizeof(u32), rnd + 1); + if (err) + break; + + err = __igt_write_huge(ce, obj, obj->base.size, addr, + (PAGE_SIZE / sizeof(u32)) - 1, + rnd + 2); + if (err) + break; + + addr += obj->base.size; + + cond_resched(); + } + + i915_gem_context_unlock_engines(ctx); + kfree(order); +err_put: + list_for_each_entry_safe(obj, on, &objects, st_link) { + list_del(&obj->st_link); + i915_gem_object_put(obj); + } +out_vm: + i915_vm_put(vm); +out: + fput(file); + return err; +} + static int igt_tmpfs_fallback(void *arg) { struct drm_i915_private *i915 = arg; @@ -1803,6 +1957,7 @@ int i915_gem_huge_page_live_selftests(struct drm_i915_private *i915) SUBTEST(igt_ppgtt_smoke_huge), SUBTEST(igt_ppgtt_sanity_check), SUBTEST(igt_ppgtt_compact), + SUBTEST(igt_ppgtt_mixed), }; if (!HAS_PPGTT(i915)) { diff --git a/drivers/gpu/drm/i915/gt/gen8_ppgtt.c b/drivers/gpu/drm/i915/gt/gen8_ppgtt.c index 8dd60d5ef905..4daaa6f55668 100644 --- a/drivers/gpu/drm/i915/gt/gen8_ppgtt.c +++ b/drivers/gpu/drm/i915/gt/gen8_ppgtt.c @@ -476,6 +476,7 @@ xehpsdv_ppgtt_insert_huge(struct i915_address_space *vm, const gen8_pte_t pte_encode = vm->pte_encode(0, cache_level, flags); unsigned int rem = sg_dma_len(iter->sg); u64 start = vma_res->start; + u64 end = start + vma_res->vma_size; GEM_BUG_ON(!i915_vm_is_4lvl(vm)); @@ -489,9 +490,10 @@ xehpsdv_ppgtt_insert_huge(struct i915_address_space *vm, gen8_pte_t encode = pte_encode; unsigned int page_size; gen8_pte_t *vaddr; - u16 index, max; + u16 index, max, nent, i; max = I915_PDES; + nent = 1; if (vma_res->bi.page_sizes.sg & I915_GTT_PAGE_SIZE_2M && IS_ALIGNED(iter->dma, I915_GTT_PAGE_SIZE_2M) && @@ -503,25 +505,37 @@ xehpsdv_ppgtt_insert_huge(struct i915_address_space *vm, vaddr = px_vaddr(pd); } else { - if (encode & GEN12_PPGTT_PTE_LM) { - GEM_BUG_ON(__gen8_pte_index(start, 0) % 16); - GEM_BUG_ON(rem < I915_GTT_PAGE_SIZE_64K); - GEM_BUG_ON(!IS_ALIGNED(iter->dma, - I915_GTT_PAGE_SIZE_64K)); - - index = __gen8_pte_index(start, 0) / 16; - page_size = I915_GTT_PAGE_SIZE_64K; - - max /= 16; - - vaddr = px_vaddr(pd); - vaddr[__gen8_pte_index(start, 1)] |= GEN12_PDE_64K; + index = __gen8_pte_index(start, 0); + page_size = I915_GTT_PAGE_SIZE; - pt->is_compact = true; - } else { - GEM_BUG_ON(pt->is_compact); - index = __gen8_pte_index(start, 0); - page_size = I915_GTT_PAGE_SIZE; + if (vma_res->bi.page_sizes.sg & I915_GTT_PAGE_SIZE_64K) { + /* + * Device local-memory on these platforms should + * always use 64K pages or larger (including GTT + * alignment), therefore if we know the whole + * page-table needs to be filled we can always + * safely use the compact-layout. Otherwise fall + * back to the TLB hint with PS64. If this is + * system memory we only bother with PS64. + */ + if ((encode & GEN12_PPGTT_PTE_LM) && + end - start >= SZ_2M && !index) { + index = __gen8_pte_index(start, 0) / 16; + page_size = I915_GTT_PAGE_SIZE_64K; + + max /= 16; + + vaddr = px_vaddr(pd); + vaddr[__gen8_pte_index(start, 1)] |= GEN12_PDE_64K; + + pt->is_compact = true; + } else if (IS_ALIGNED(iter->dma, I915_GTT_PAGE_SIZE_64K) && + rem >= I915_GTT_PAGE_SIZE_64K && + !(index % 16)) { + encode |= GEN12_PTE_PS64; + page_size = I915_GTT_PAGE_SIZE_64K; + nent = 16; + } } vaddr = px_vaddr(pt); @@ -529,7 +543,12 @@ xehpsdv_ppgtt_insert_huge(struct i915_address_space *vm, do { GEM_BUG_ON(rem < page_size); - vaddr[index++] = encode | iter->dma; + + for (i = 0; i < nent; i++) { + vaddr[index++] = + encode | (iter->dma + i * + I915_GTT_PAGE_SIZE); + } start += page_size; iter->dma += page_size; @@ -745,6 +764,8 @@ static void __xehpsdv_ppgtt_insert_entry_lm(struct i915_address_space *vm, GEM_BUG_ON(!IS_ALIGNED(addr, SZ_64K)); GEM_BUG_ON(!IS_ALIGNED(offset, SZ_64K)); + /* XXX: we don't strictly need to use this layout */ + if (!pt->is_compact) { vaddr = px_vaddr(pd); vaddr[gen8_pd_index(idx, 1)] |= GEN12_PDE_64K; @@ -935,22 +956,10 @@ struct i915_ppgtt *gen8_ppgtt_create(struct intel_gt *gt, ppgtt->vm.alloc_pt_dma = alloc_pt_dma; /* - * On some platforms the hw has dropped support for 4K GTT pages - * when dealing with LMEM, and due to the design of 64K GTT - * pages in the hw, we can only mark the *entire* page-table as - * operating in 64K GTT mode, since the enable bit is still on - * the pde, and not the pte. And since we still need to allow - * 4K GTT pages for SMEM objects, we can't have a "normal" 4K - * page-table with scratch pointing to LMEM, since that's - * undefined from the hw pov. The simplest solution is to just - * move the 64K scratch page to SMEM on all platforms and call - * it a day, since that should work for all configurations. - * - * Using SMEM instead of LMEM has the additional advantage of - * not reserving high performance memory for a "never" used - * filler page. It also removes the device access that would - * be required to initialise the scratch page, reducing pressure - * on an even scarcer resource. + * Using SMEM here instead of LMEM has the advantage of not reserving + * high performance memory for a "never" used filler page. It also + * removes the device access that would be required to initialise the + * scratch page, reducing pressure on an even scarcer resource. */ ppgtt->vm.alloc_scratch_dma = alloc_pt_dma; diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.c b/drivers/gpu/drm/i915/gt/intel_gtt.c index 2eaeba14319e..13e411187fd5 100644 --- a/drivers/gpu/drm/i915/gt/intel_gtt.c +++ b/drivers/gpu/drm/i915/gt/intel_gtt.c @@ -269,11 +269,7 @@ void i915_address_space_init(struct i915_address_space *vm, int subclass) memset64(vm->min_alignment, I915_GTT_MIN_ALIGNMENT, ARRAY_SIZE(vm->min_alignment)); - if (HAS_64K_PAGES(vm->i915) && NEEDS_COMPACT_PT(vm->i915) && - subclass == VM_CLASS_PPGTT) { - vm->min_alignment[INTEL_MEMORY_LOCAL] = I915_GTT_PAGE_SIZE_2M; - vm->min_alignment[INTEL_MEMORY_STOLEN_LOCAL] = I915_GTT_PAGE_SIZE_2M; - } else if (HAS_64K_PAGES(vm->i915)) { + if (HAS_64K_PAGES(vm->i915)) { vm->min_alignment[INTEL_MEMORY_LOCAL] = I915_GTT_PAGE_SIZE_64K; vm->min_alignment[INTEL_MEMORY_STOLEN_LOCAL] = I915_GTT_PAGE_SIZE_64K; } @@ -343,7 +339,8 @@ int setup_scratch_page(struct i915_address_space *vm) */ size = I915_GTT_PAGE_SIZE_4K; if (i915_vm_is_4lvl(vm) && - HAS_PAGE_SIZES(vm->i915, I915_GTT_PAGE_SIZE_64K)) + HAS_PAGE_SIZES(vm->i915, I915_GTT_PAGE_SIZE_64K) && + !HAS_64K_PAGES(vm->i915)) size = I915_GTT_PAGE_SIZE_64K; do { @@ -385,18 +382,6 @@ skip: if (size == I915_GTT_PAGE_SIZE_4K) return -ENOMEM; - /* - * If we need 64K minimum GTT pages for device local-memory, - * like on XEHPSDV, then we need to fail the allocation here, - * otherwise we can't safely support the insertion of - * local-memory pages for this vm, since the HW expects the - * correct physical alignment and size when the page-table is - * operating in 64K GTT mode, which includes any scratch PTEs, - * since userspace can still touch them. - */ - if (HAS_64K_PAGES(vm->i915)) - return -ENOMEM; - size = I915_GTT_PAGE_SIZE_4K; } while (1); } diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.h b/drivers/gpu/drm/i915/gt/intel_gtt.h index c0ca53cba9f0..062b78333fb2 100644 --- a/drivers/gpu/drm/i915/gt/intel_gtt.h +++ b/drivers/gpu/drm/i915/gt/intel_gtt.h @@ -93,6 +93,7 @@ typedef u64 gen8_pte_t; #define GEN12_GGTT_PTE_LM BIT_ULL(1) #define GEN12_PDE_64K BIT(6) +#define GEN12_PTE_PS64 BIT(8) /* * Cacheability Control is a 4-bit value. The low three bits are stored in bits diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ca0609dc5fb0..e390da969be5 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -905,13 +905,6 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915, */ #define HAS_64K_PAGES(dev_priv) (INTEL_INFO(dev_priv)->has_64k_pages) -/* - * Set this flag when platform doesn't allow both 64k pages and 4k pages in - * the same PT. this flag means we need to support compact PT layout for the - * ppGTT when using the 64K GTT pages. - */ -#define NEEDS_COMPACT_PT(dev_priv) (INTEL_INFO(dev_priv)->needs_compact_pt) - #define HAS_IPC(dev_priv) (INTEL_INFO(dev_priv)->display.has_ipc) #define HAS_REGION(i915, i) (RUNTIME_INFO(i915)->memory_regions & (i)) diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c index cd4487a1d3be..f1344db626f5 100644 --- a/drivers/gpu/drm/i915/i915_pci.c +++ b/drivers/gpu/drm/i915/i915_pci.c @@ -1042,7 +1042,6 @@ static const struct intel_device_info xehpsdv_info = { PLATFORM(INTEL_XEHPSDV), NO_DISPLAY, .has_64k_pages = 1, - .needs_compact_pt = 1, .has_media_ratio_mode = 1, .__runtime.platform_engine_mask = BIT(RCS0) | BIT(BCS0) | @@ -1064,7 +1063,6 @@ static const struct intel_device_info xehpsdv_info = { .has_64k_pages = 1, \ .has_guc_deprivilege = 1, \ .has_heci_pxp = 1, \ - .needs_compact_pt = 1, \ .has_media_ratio_mode = 1, \ .__runtime.platform_engine_mask = \ BIT(RCS0) | BIT(BCS0) | \ diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c index f17c09ead7d7..c39488eb9eeb 100644 --- a/drivers/gpu/drm/i915/i915_vma.c +++ b/drivers/gpu/drm/i915/i915_vma.c @@ -776,12 +776,6 @@ i915_vma_insert(struct i915_vma *vma, struct i915_gem_ww_ctx *ww, GEM_BUG_ON(!IS_ALIGNED(end, I915_GTT_PAGE_SIZE)); alignment = max(alignment, i915_vm_obj_min_alignment(vma->vm, vma->obj)); - /* - * for compact-pt we round up the reservation to prevent - * any smaller pages being used within the same PDE - */ - if (NEEDS_COMPACT_PT(vma->vm->i915)) - size = round_up(size, alignment); /* If binding the object/GGTT view requires more space than the entire * aperture has, reject it early before evicting everything in a vain @@ -820,7 +814,8 @@ i915_vma_insert(struct i915_vma *vma, struct i915_gem_ww_ctx *ww, * forseeable future. See also i915_ggtt_offset(). */ if (upper_32_bits(end - 1) && - vma->page_sizes.sg > I915_GTT_PAGE_SIZE) { + vma->page_sizes.sg > I915_GTT_PAGE_SIZE && + !HAS_64K_PAGES(vma->vm->i915)) { /* * We can't mix 64K and 4K PTEs in the same page-table * (2M block), and so to avoid the ugliness and diff --git a/drivers/gpu/drm/i915/intel_device_info.h b/drivers/gpu/drm/i915/intel_device_info.h index d638235e1d26..da833267a782 100644 --- a/drivers/gpu/drm/i915/intel_device_info.h +++ b/drivers/gpu/drm/i915/intel_device_info.h @@ -146,7 +146,6 @@ enum intel_ppgtt_type { /* Keep has_* in alphabetical order */ \ func(has_64bit_reloc); \ func(has_64k_pages); \ - func(needs_compact_pt); \ func(gpu_reset_clobbers_display); \ func(has_reset_engine); \ func(has_3d_pipeline); \ diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c index ea2cf1080979..27c733b00976 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c @@ -1114,15 +1114,8 @@ static int misaligned_case(struct i915_address_space *vm, struct intel_memory_re expected_node_size = expected_vma_size; if (HAS_64K_PAGES(vm->i915) && i915_gem_object_is_lmem(obj)) { - /* - * The compact-pt should expand lmem node to 2MB for the ppGTT, - * for all other cases we should only expect 64K. - */ expected_vma_size = round_up(size, I915_GTT_PAGE_SIZE_64K); - if (NEEDS_COMPACT_PT(vm->i915) && !i915_is_ggtt(vm)) - expected_node_size = round_up(size, I915_GTT_PAGE_SIZE_2M); - else - expected_node_size = round_up(size, I915_GTT_PAGE_SIZE_64K); + expected_node_size = round_up(size, I915_GTT_PAGE_SIZE_64K); } if (vma->size != expected_vma_size || vma->node.size != expected_node_size) { diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index 629198f1d8d8..08d69e36fb66 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -3509,27 +3509,13 @@ struct drm_i915_gem_create_ext { * * The (page-aligned) allocated size for the object will be returned. * - * DG2 64K min page size implications: + * On platforms like DG2/ATS the kernel will always use 64K or larger + * pages for I915_MEMORY_CLASS_DEVICE. The kernel also requires a + * minimum of 64K GTT alignment for such objects. * - * On discrete platforms, starting from DG2, we have to contend with GTT - * page size restrictions when dealing with I915_MEMORY_CLASS_DEVICE - * objects. Specifically the hardware only supports 64K or larger GTT - * page sizes for such memory. The kernel will already ensure that all - * I915_MEMORY_CLASS_DEVICE memory is allocated using 64K or larger page - * sizes underneath. - * - * Note that the returned size here will always reflect any required - * rounding up done by the kernel, i.e 4K will now become 64K on devices - * such as DG2. The kernel will always select the largest minimum - * page-size for the set of possible placements as the value to use when - * rounding up the @size. - * - * Special DG2 GTT address alignment requirement: - * - * The GTT alignment will also need to be at least 2M for such objects. - * - * Note that due to how the hardware implements 64K GTT page support, we - * have some further complications: + * NOTE: Previously the ABI here required a minimum GTT alignment of 2M + * on DG2/ATS, due to how the hardware implemented 64K GTT page support, + * where we had the following complications: * * 1) The entire PDE (which covers a 2MB virtual address range), must * contain only 64K PTEs, i.e mixing 4K and 64K PTEs in the same @@ -3538,12 +3524,10 @@ struct drm_i915_gem_create_ext { * 2) We still need to support 4K PTEs for I915_MEMORY_CLASS_SYSTEM * objects. * - * To keep things simple for userland, we mandate that any GTT mappings - * must be aligned to and rounded up to 2MB. The kernel will internally - * pad them out to the next 2MB boundary. As this only wastes virtual - * address space and avoids userland having to copy any needlessly - * complicated PDE sharing scheme (coloring) and only affects DG2, this - * is deemed to be a good compromise. + * However on actual production HW this was completely changed to now + * allow setting a TLB hint at the PTE level (see PS64), which is a lot + * more flexible than the above. With this the 2M restriction was + * dropped where we now only require 64K. */ __u64 size; -- cgit From d54576a074a29d4901d0a693cd84e1a89057f694 Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Tue, 4 Oct 2022 12:49:15 +0100 Subject: drm/i915/uapi: expose GTT alignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On some platforms we potentially have different alignment restrictions depending on the memory type. We also now have different alignment restrictions for the same region across different kernel versions. Extend the region query to return the minimum required GTT alignment. Testcase: igt@gem_create@create-ext-placement-alignment Testcase: igt@i915_query@query-regions-sanity-check Suggested-by: Lionel Landwerlin Signed-off-by: Matthew Auld Cc: Michal Mrozek Cc: Thomas Hellström Cc: Stuart Summers Cc: Jordan Justen Cc: Yang A Shi Cc: Nirmoy Das Cc: Niranjana Vishwanathapura Reviewed-by: Nirmoy Das Acked-by: Jordan Justen Link: https://patchwork.freedesktop.org/patch/msgid/20221004114915.221708-2-matthew.auld@intel.com --- drivers/gpu/drm/i915/i915_query.c | 1 + include/uapi/drm/i915_drm.h | 29 +++++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_query.c b/drivers/gpu/drm/i915/i915_query.c index 6ec9c9fb7b0d..111377f210ed 100644 --- a/drivers/gpu/drm/i915/i915_query.c +++ b/drivers/gpu/drm/i915/i915_query.c @@ -498,6 +498,7 @@ static int query_memregion_info(struct drm_i915_private *i915, info.region.memory_class = mr->type; info.region.memory_instance = mr->instance; info.probed_size = mr->total; + info.gtt_alignment = mr->min_page_size; if (mr->type == INTEL_MEMORY_LOCAL) info.probed_cpu_visible_size = mr->io_size; diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index 08d69e36fb66..2e613109356b 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -3346,8 +3346,33 @@ struct drm_i915_memory_region_info { /** @region: The class:instance pair encoding */ struct drm_i915_gem_memory_class_instance region; - /** @rsvd0: MBZ */ - __u32 rsvd0; + union { + /** @rsvd0: MBZ */ + __u32 rsvd0; + /** + * @gtt_alignment: + * + * The minimum required GTT alignment for this type of memory. + * When allocating a GTT address it must be aligned to this + * value or larger. On some platforms the kernel might opt to + * using 64K pages for I915_MEMORY_CLASS_DEVICE, where 64K GTT + * pages can then be used if we also use 64K GTT alignment. + * + * NOTE: If this is zero then this must be an older + * kernel which lacks support for this field. + * + * Side note: For larger objects (especially for + * I915_MEMORY_CLASS_DEVICE), like 2M+ in size, userspace should + * consider potentially bumping the GTT alignment to say 2M, + * which could potentially increase the likelihood of the kernel + * being able to utilise 2M GTT pages underneath, if the layout + * of the physical pages allows it. On some configurations we + * can then also use a more efficient page-table layout, if we + * can't use the more desirable 2M GTT page, so long as we know + * that the entire page-table will be used by this object. + */ + __u32 gtt_alignment; + }; /** * @probed_size: Memory probed by the driver -- cgit From a5552dd9c2455685c76971e46578c59c069a7923 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 30 Sep 2022 11:39:52 +0300 Subject: drm: lcdif: Fix indentation in lcdif_regs.h A couple of the register macro values are incorrectly indented. Fix them. Signed-off-by: Laurent Pinchart Reviewed-by: Marek Vasut Reviewed-by: Kieran Bingham Reviewed-by: Liu Ying Signed-off-by: Marek Vasut Link: https://patchwork.freedesktop.org/patch/msgid/20220930083955.31580-2-laurent.pinchart@ideasonboard.com --- drivers/gpu/drm/mxsfb/lcdif_regs.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/mxsfb/lcdif_regs.h b/drivers/gpu/drm/mxsfb/lcdif_regs.h index c70220651e3a..99171d0190eb 100644 --- a/drivers/gpu/drm/mxsfb/lcdif_regs.h +++ b/drivers/gpu/drm/mxsfb/lcdif_regs.h @@ -130,7 +130,7 @@ #define CTRL_FETCH_START_OPTION_BPV BIT(9) #define CTRL_FETCH_START_OPTION_RESV GENMASK(9, 8) #define CTRL_FETCH_START_OPTION_MASK GENMASK(9, 8) -#define CTRL_NEG BIT(4) +#define CTRL_NEG BIT(4) #define CTRL_INV_PXCK BIT(3) #define CTRL_INV_DE BIT(2) #define CTRL_INV_VS BIT(1) @@ -186,7 +186,7 @@ #define INT_ENABLE_D1_PLANE_PANIC_EN BIT(0) #define CTRLDESCL0_1_HEIGHT(n) (((n) & 0xffff) << 16) -#define CTRLDESCL0_1_HEIGHT_MASK GENMASK(31, 16) +#define CTRLDESCL0_1_HEIGHT_MASK GENMASK(31, 16) #define CTRLDESCL0_1_WIDTH(n) ((n) & 0xffff) #define CTRLDESCL0_1_WIDTH_MASK GENMASK(15, 0) -- cgit From 664a7eca9bfa73b9cd2e48a4668f159f65c1d74e Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 30 Sep 2022 11:39:53 +0300 Subject: drm: lcdif: Don't use BIT() for multi-bit register fields The BIT() macro is meant to represent a single bit. Don't use it for values of register fields that span multiple bits. Signed-off-by: Laurent Pinchart Reviewed-by: Marek Vasut Reviewed-by: Kieran Bingham Reviewed-by: Liu Ying Signed-off-by: Marek Vasut Link: https://patchwork.freedesktop.org/patch/msgid/20220930083955.31580-3-laurent.pinchart@ideasonboard.com --- drivers/gpu/drm/mxsfb/lcdif_regs.h | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/mxsfb/lcdif_regs.h b/drivers/gpu/drm/mxsfb/lcdif_regs.h index 99171d0190eb..03c7827bdf5a 100644 --- a/drivers/gpu/drm/mxsfb/lcdif_regs.h +++ b/drivers/gpu/drm/mxsfb/lcdif_regs.h @@ -138,9 +138,9 @@ #define DISP_PARA_DISP_ON BIT(31) #define DISP_PARA_SWAP_EN BIT(30) -#define DISP_PARA_LINE_PATTERN_UYVY_H (GENMASK(29, 28) | BIT(26)) -#define DISP_PARA_LINE_PATTERN_RGB565 GENMASK(28, 26) -#define DISP_PARA_LINE_PATTERN_RGB888 0 +#define DISP_PARA_LINE_PATTERN_UYVY_H (0xd << 26) +#define DISP_PARA_LINE_PATTERN_RGB565 (0x7 << 26) +#define DISP_PARA_LINE_PATTERN_RGB888 (0x0 << 26) #define DISP_PARA_LINE_PATTERN_MASK GENMASK(29, 26) #define DISP_PARA_DISP_MODE_MASK GENMASK(25, 24) #define DISP_PARA_BGND_R_MASK GENMASK(23, 16) @@ -198,18 +198,18 @@ #define CTRLDESCL0_5_EN BIT(31) #define CTRLDESCL0_5_SHADOW_LOAD_EN BIT(30) -#define CTRLDESCL0_5_BPP_16_RGB565 BIT(26) -#define CTRLDESCL0_5_BPP_16_ARGB1555 (BIT(26) | BIT(24)) -#define CTRLDESCL0_5_BPP_16_ARGB4444 (BIT(26) | BIT(25)) -#define CTRLDESCL0_5_BPP_YCbCr422 (BIT(26) | BIT(25) | BIT(24)) -#define CTRLDESCL0_5_BPP_24_RGB888 BIT(27) -#define CTRLDESCL0_5_BPP_32_ARGB8888 (BIT(27) | BIT(24)) -#define CTRLDESCL0_5_BPP_32_ABGR8888 (BIT(27) | BIT(25)) +#define CTRLDESCL0_5_BPP_16_RGB565 (0x4 << 24) +#define CTRLDESCL0_5_BPP_16_ARGB1555 (0x5 << 24) +#define CTRLDESCL0_5_BPP_16_ARGB4444 (0x6 << 24) +#define CTRLDESCL0_5_BPP_YCbCr422 (0x7 << 24) +#define CTRLDESCL0_5_BPP_24_RGB888 (0x8 << 24) +#define CTRLDESCL0_5_BPP_32_ARGB8888 (0x9 << 24) +#define CTRLDESCL0_5_BPP_32_ABGR8888 (0xa << 24) #define CTRLDESCL0_5_BPP_MASK GENMASK(27, 24) -#define CTRLDESCL0_5_YUV_FORMAT_Y2VY1U 0 -#define CTRLDESCL0_5_YUV_FORMAT_Y2UY1V BIT(14) -#define CTRLDESCL0_5_YUV_FORMAT_VY2UY1 BIT(15) -#define CTRLDESCL0_5_YUV_FORMAT_UY2VY1 (BIT(15) | BIT(14)) +#define CTRLDESCL0_5_YUV_FORMAT_Y2VY1U (0x0 << 14) +#define CTRLDESCL0_5_YUV_FORMAT_Y2UY1V (0x1 << 14) +#define CTRLDESCL0_5_YUV_FORMAT_VY2UY1 (0x2 << 14) +#define CTRLDESCL0_5_YUV_FORMAT_UY2VY1 (0x3 << 14) #define CTRLDESCL0_5_YUV_FORMAT_MASK GENMASK(15, 14) #define CSC0_CTRL_CSC_MODE_RGB2YCbCr GENMASK(2, 1) -- cgit From ec39dee8b25229a646271815cc86a8fc865525cf Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 30 Sep 2022 11:39:54 +0300 Subject: drm: lcdif: Switch to limited range for RGB to YUV conversion Up to and including v1.3, HDMI supported limited quantization range only for YCbCr. HDMI v1.4 introduced selectable quantization ranges, but this feature isn't supported in the dw-hdmi driver that is used in conjunction with the LCDIF in the i.MX8MP. The HDMI YCbCr output is thus always advertised in the AVI infoframe as limited range. The LCDIF driver, on the other hand, configures the CSC to produce full range YCbCr. This mismatch results in loss of details and incorrect colours. Fix it by switching to limited range YCbCr. The coefficients are copied from drivers/media/platforms/nxp/imx-pxp.c for coherency, as the hardware is most likely identical. Fixes: 9db35bb349a0 ("drm: lcdif: Add support for i.MX8MP LCDIF variant") Signed-off-by: Laurent Pinchart Reviewed-by: Marek Vasut Reviewed-by: Kieran Bingham Reviewed-by: Liu Ying Signed-off-by: Marek Vasut Link: https://patchwork.freedesktop.org/patch/msgid/20220930083955.31580-4-laurent.pinchart@ideasonboard.com --- drivers/gpu/drm/mxsfb/lcdif_kms.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/mxsfb/lcdif_kms.c b/drivers/gpu/drm/mxsfb/lcdif_kms.c index b1092aab1423..9f212e29059b 100644 --- a/drivers/gpu/drm/mxsfb/lcdif_kms.c +++ b/drivers/gpu/drm/mxsfb/lcdif_kms.c @@ -52,16 +52,22 @@ static void lcdif_set_formats(struct lcdif_drm_private *lcdif, writel(DISP_PARA_LINE_PATTERN_UYVY_H, lcdif->base + LCDC_V8_DISP_PARA); - /* CSC: BT.601 Full Range RGB to YCbCr coefficients. */ - writel(CSC0_COEF0_A2(0x096) | CSC0_COEF0_A1(0x04c), + /* + * CSC: BT.601 Limited Range RGB to YCbCr coefficients. + * + * |Y | | 0.2568 0.5041 0.0979| |R| |16 | + * |Cb| = |-0.1482 -0.2910 0.4392| * |G| + |128| + * |Cr| | 0.4392 0.4392 -0.3678| |B| |128| + */ + writel(CSC0_COEF0_A2(0x081) | CSC0_COEF0_A1(0x041), lcdif->base + LCDC_V8_CSC0_COEF0); - writel(CSC0_COEF1_B1(0x7d5) | CSC0_COEF1_A3(0x01d), + writel(CSC0_COEF1_B1(0x7db) | CSC0_COEF1_A3(0x019), lcdif->base + LCDC_V8_CSC0_COEF1); - writel(CSC0_COEF2_B3(0x080) | CSC0_COEF2_B2(0x7ac), + writel(CSC0_COEF2_B3(0x070) | CSC0_COEF2_B2(0x7b6), lcdif->base + LCDC_V8_CSC0_COEF2); - writel(CSC0_COEF3_C2(0x795) | CSC0_COEF3_C1(0x080), + writel(CSC0_COEF3_C2(0x7a2) | CSC0_COEF3_C1(0x070), lcdif->base + LCDC_V8_CSC0_COEF3); - writel(CSC0_COEF4_D1(0x000) | CSC0_COEF4_C3(0x7ec), + writel(CSC0_COEF4_D1(0x010) | CSC0_COEF4_C3(0x7ee), lcdif->base + LCDC_V8_CSC0_COEF4); writel(CSC0_COEF5_D3(0x080) | CSC0_COEF5_D2(0x080), lcdif->base + LCDC_V8_CSC0_COEF5); -- cgit From 6cba31e33e770d9b5e9973278573cfef90583fcc Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Fri, 30 Sep 2022 11:39:55 +0300 Subject: drm: lcdif: Add support for YUV planes The LCDIF includes a color space converter that supports YUV input. Use it to support YUV planes, either through the converter if the output format is RGB, or in conversion bypass mode otherwise. Signed-off-by: Kieran Bingham Signed-off-by: Laurent Pinchart Reviewed-by: Marek Vasut Reviewed-by: Kieran Bingham Reviewed-by: Liu Ying Signed-off-by: Marek Vasut Link: https://patchwork.freedesktop.org/patch/msgid/20220930083955.31580-5-laurent.pinchart@ideasonboard.com --- drivers/gpu/drm/mxsfb/lcdif_kms.c | 245 ++++++++++++++++++++++++++++++++----- drivers/gpu/drm/mxsfb/lcdif_regs.h | 5 +- 2 files changed, 220 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/mxsfb/lcdif_kms.c b/drivers/gpu/drm/mxsfb/lcdif_kms.c index 9f212e29059b..33ee40876994 100644 --- a/drivers/gpu/drm/mxsfb/lcdif_kms.c +++ b/drivers/gpu/drm/mxsfb/lcdif_kms.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -31,13 +32,126 @@ /* ----------------------------------------------------------------------------- * CRTC */ + +/* + * For conversion from YCbCr to RGB, the CSC operates as follows: + * + * |R| |A1 A2 A3| |Y + D1| + * |G| = |B1 B2 B3| * |Cb + D2| + * |B| |C1 C2 C3| |Cr + D3| + * + * The A, B and C coefficients are expressed as Q2.8 fixed point values, and + * the D coefficients as Q0.8. Despite the reference manual stating the + * opposite, the D1, D2 and D3 offset values are added to Y, Cb and Cr, not + * subtracted. They must thus be programmed with negative values. + */ +static const u32 lcdif_yuv2rgb_coeffs[3][2][6] = { + [DRM_COLOR_YCBCR_BT601] = { + [DRM_COLOR_YCBCR_LIMITED_RANGE] = { + /* + * BT.601 limited range: + * + * |R| |1.1644 0.0000 1.5960| |Y - 16 | + * |G| = |1.1644 -0.3917 -0.8129| * |Cb - 128| + * |B| |1.1644 2.0172 0.0000| |Cr - 128| + */ + CSC0_COEF0_A1(0x12a) | CSC0_COEF0_A2(0x000), + CSC0_COEF1_A3(0x199) | CSC0_COEF1_B1(0x12a), + CSC0_COEF2_B2(0x79c) | CSC0_COEF2_B3(0x730), + CSC0_COEF3_C1(0x12a) | CSC0_COEF3_C2(0x204), + CSC0_COEF4_C3(0x000) | CSC0_COEF4_D1(0x1f0), + CSC0_COEF5_D2(0x180) | CSC0_COEF5_D3(0x180), + }, + [DRM_COLOR_YCBCR_FULL_RANGE] = { + /* + * BT.601 full range: + * + * |R| |1.0000 0.0000 1.4020| |Y - 0 | + * |G| = |1.0000 -0.3441 -0.7141| * |Cb - 128| + * |B| |1.0000 1.7720 0.0000| |Cr - 128| + */ + CSC0_COEF0_A1(0x100) | CSC0_COEF0_A2(0x000), + CSC0_COEF1_A3(0x167) | CSC0_COEF1_B1(0x100), + CSC0_COEF2_B2(0x7a8) | CSC0_COEF2_B3(0x749), + CSC0_COEF3_C1(0x100) | CSC0_COEF3_C2(0x1c6), + CSC0_COEF4_C3(0x000) | CSC0_COEF4_D1(0x000), + CSC0_COEF5_D2(0x180) | CSC0_COEF5_D3(0x180), + }, + }, + [DRM_COLOR_YCBCR_BT709] = { + [DRM_COLOR_YCBCR_LIMITED_RANGE] = { + /* + * Rec.709 limited range: + * + * |R| |1.1644 0.0000 1.7927| |Y - 16 | + * |G| = |1.1644 -0.2132 -0.5329| * |Cb - 128| + * |B| |1.1644 2.1124 0.0000| |Cr - 128| + */ + CSC0_COEF0_A1(0x12a) | CSC0_COEF0_A2(0x000), + CSC0_COEF1_A3(0x1cb) | CSC0_COEF1_B1(0x12a), + CSC0_COEF2_B2(0x7c9) | CSC0_COEF2_B3(0x778), + CSC0_COEF3_C1(0x12a) | CSC0_COEF3_C2(0x21d), + CSC0_COEF4_C3(0x000) | CSC0_COEF4_D1(0x1f0), + CSC0_COEF5_D2(0x180) | CSC0_COEF5_D3(0x180), + }, + [DRM_COLOR_YCBCR_FULL_RANGE] = { + /* + * Rec.709 full range: + * + * |R| |1.0000 0.0000 1.5748| |Y - 0 | + * |G| = |1.0000 -0.1873 -0.4681| * |Cb - 128| + * |B| |1.0000 1.8556 0.0000| |Cr - 128| + */ + CSC0_COEF0_A1(0x100) | CSC0_COEF0_A2(0x000), + CSC0_COEF1_A3(0x193) | CSC0_COEF1_B1(0x100), + CSC0_COEF2_B2(0x7d0) | CSC0_COEF2_B3(0x788), + CSC0_COEF3_C1(0x100) | CSC0_COEF3_C2(0x1db), + CSC0_COEF4_C3(0x000) | CSC0_COEF4_D1(0x000), + CSC0_COEF5_D2(0x180) | CSC0_COEF5_D3(0x180), + }, + }, + [DRM_COLOR_YCBCR_BT2020] = { + [DRM_COLOR_YCBCR_LIMITED_RANGE] = { + /* + * BT.2020 limited range: + * + * |R| |1.1644 0.0000 1.6787| |Y - 16 | + * |G| = |1.1644 -0.1874 -0.6505| * |Cb - 128| + * |B| |1.1644 2.1418 0.0000| |Cr - 128| + */ + CSC0_COEF0_A1(0x12a) | CSC0_COEF0_A2(0x000), + CSC0_COEF1_A3(0x1ae) | CSC0_COEF1_B1(0x12a), + CSC0_COEF2_B2(0x7d0) | CSC0_COEF2_B3(0x759), + CSC0_COEF3_C1(0x12a) | CSC0_COEF3_C2(0x224), + CSC0_COEF4_C3(0x000) | CSC0_COEF4_D1(0x1f0), + CSC0_COEF5_D2(0x180) | CSC0_COEF5_D3(0x180), + }, + [DRM_COLOR_YCBCR_FULL_RANGE] = { + /* + * BT.2020 full range: + * + * |R| |1.0000 0.0000 1.4746| |Y - 0 | + * |G| = |1.0000 -0.1646 -0.5714| * |Cb - 128| + * |B| |1.0000 1.8814 0.0000| |Cr - 128| + */ + CSC0_COEF0_A1(0x100) | CSC0_COEF0_A2(0x000), + CSC0_COEF1_A3(0x179) | CSC0_COEF1_B1(0x100), + CSC0_COEF2_B2(0x7d6) | CSC0_COEF2_B3(0x76e), + CSC0_COEF3_C1(0x100) | CSC0_COEF3_C2(0x1e2), + CSC0_COEF4_C3(0x000) | CSC0_COEF4_D1(0x000), + CSC0_COEF5_D2(0x180) | CSC0_COEF5_D3(0x180), + }, + }, +}; + static void lcdif_set_formats(struct lcdif_drm_private *lcdif, + struct drm_plane_state *plane_state, const u32 bus_format) { struct drm_device *drm = lcdif->drm; - const u32 format = lcdif->crtc.primary->state->fb->format->format; - - writel(CSC0_CTRL_BYPASS, lcdif->base + LCDC_V8_CSC0_CTRL); + const u32 format = plane_state->fb->format->format; + bool in_yuv = false; + bool out_yuv = false; switch (bus_format) { case MEDIA_BUS_FMT_RGB565_1X16: @@ -51,30 +165,7 @@ static void lcdif_set_formats(struct lcdif_drm_private *lcdif, case MEDIA_BUS_FMT_UYVY8_1X16: writel(DISP_PARA_LINE_PATTERN_UYVY_H, lcdif->base + LCDC_V8_DISP_PARA); - - /* - * CSC: BT.601 Limited Range RGB to YCbCr coefficients. - * - * |Y | | 0.2568 0.5041 0.0979| |R| |16 | - * |Cb| = |-0.1482 -0.2910 0.4392| * |G| + |128| - * |Cr| | 0.4392 0.4392 -0.3678| |B| |128| - */ - writel(CSC0_COEF0_A2(0x081) | CSC0_COEF0_A1(0x041), - lcdif->base + LCDC_V8_CSC0_COEF0); - writel(CSC0_COEF1_B1(0x7db) | CSC0_COEF1_A3(0x019), - lcdif->base + LCDC_V8_CSC0_COEF1); - writel(CSC0_COEF2_B3(0x070) | CSC0_COEF2_B2(0x7b6), - lcdif->base + LCDC_V8_CSC0_COEF2); - writel(CSC0_COEF3_C2(0x7a2) | CSC0_COEF3_C1(0x070), - lcdif->base + LCDC_V8_CSC0_COEF3); - writel(CSC0_COEF4_D1(0x010) | CSC0_COEF4_C3(0x7ee), - lcdif->base + LCDC_V8_CSC0_COEF4); - writel(CSC0_COEF5_D3(0x080) | CSC0_COEF5_D2(0x080), - lcdif->base + LCDC_V8_CSC0_COEF5); - - writel(CSC0_CTRL_CSC_MODE_RGB2YCbCr, - lcdif->base + LCDC_V8_CSC0_CTRL); - + out_yuv = true; break; default: dev_err(drm->dev, "Unknown media bus format 0x%x\n", bus_format); @@ -82,6 +173,7 @@ static void lcdif_set_formats(struct lcdif_drm_private *lcdif, } switch (format) { + /* RGB Formats */ case DRM_FORMAT_RGB565: writel(CTRLDESCL0_5_BPP_16_RGB565, lcdif->base + LCDC_V8_CTRLDESCL0_5); @@ -106,10 +198,84 @@ static void lcdif_set_formats(struct lcdif_drm_private *lcdif, writel(CTRLDESCL0_5_BPP_32_ARGB8888, lcdif->base + LCDC_V8_CTRLDESCL0_5); break; + + /* YUV Formats */ + case DRM_FORMAT_YUYV: + writel(CTRLDESCL0_5_BPP_YCbCr422 | CTRLDESCL0_5_YUV_FORMAT_VY2UY1, + lcdif->base + LCDC_V8_CTRLDESCL0_5); + in_yuv = true; + break; + case DRM_FORMAT_YVYU: + writel(CTRLDESCL0_5_BPP_YCbCr422 | CTRLDESCL0_5_YUV_FORMAT_UY2VY1, + lcdif->base + LCDC_V8_CTRLDESCL0_5); + in_yuv = true; + break; + case DRM_FORMAT_UYVY: + writel(CTRLDESCL0_5_BPP_YCbCr422 | CTRLDESCL0_5_YUV_FORMAT_Y2VY1U, + lcdif->base + LCDC_V8_CTRLDESCL0_5); + in_yuv = true; + break; + case DRM_FORMAT_VYUY: + writel(CTRLDESCL0_5_BPP_YCbCr422 | CTRLDESCL0_5_YUV_FORMAT_Y2UY1V, + lcdif->base + LCDC_V8_CTRLDESCL0_5); + in_yuv = true; + break; + default: dev_err(drm->dev, "Unknown pixel format 0x%x\n", format); break; } + + /* + * The CSC differentiates between "YCbCr" and "YUV", but the reference + * manual doesn't detail how they differ. Experiments showed that the + * luminance value is unaffected, only the calculations involving chroma + * values differ. The YCbCr mode behaves as expected, with chroma values + * being offset by 128. The YUV mode isn't fully understood. + */ + if (!in_yuv && out_yuv) { + /* RGB -> YCbCr */ + writel(CSC0_CTRL_CSC_MODE_RGB2YCbCr, + lcdif->base + LCDC_V8_CSC0_CTRL); + + /* + * CSC: BT.601 Limited Range RGB to YCbCr coefficients. + * + * |Y | | 0.2568 0.5041 0.0979| |R| |16 | + * |Cb| = |-0.1482 -0.2910 0.4392| * |G| + |128| + * |Cr| | 0.4392 0.4392 -0.3678| |B| |128| + */ + writel(CSC0_COEF0_A2(0x081) | CSC0_COEF0_A1(0x041), + lcdif->base + LCDC_V8_CSC0_COEF0); + writel(CSC0_COEF1_B1(0x7db) | CSC0_COEF1_A3(0x019), + lcdif->base + LCDC_V8_CSC0_COEF1); + writel(CSC0_COEF2_B3(0x070) | CSC0_COEF2_B2(0x7b6), + lcdif->base + LCDC_V8_CSC0_COEF2); + writel(CSC0_COEF3_C2(0x7a2) | CSC0_COEF3_C1(0x070), + lcdif->base + LCDC_V8_CSC0_COEF3); + writel(CSC0_COEF4_D1(0x010) | CSC0_COEF4_C3(0x7ee), + lcdif->base + LCDC_V8_CSC0_COEF4); + writel(CSC0_COEF5_D3(0x080) | CSC0_COEF5_D2(0x080), + lcdif->base + LCDC_V8_CSC0_COEF5); + } else if (in_yuv && !out_yuv) { + /* YCbCr -> RGB */ + const u32 *coeffs = + lcdif_yuv2rgb_coeffs[plane_state->color_encoding] + [plane_state->color_range]; + + writel(CSC0_CTRL_CSC_MODE_YCbCr2RGB, + lcdif->base + LCDC_V8_CSC0_CTRL); + + writel(coeffs[0], lcdif->base + LCDC_V8_CSC0_COEF0); + writel(coeffs[1], lcdif->base + LCDC_V8_CSC0_COEF1); + writel(coeffs[2], lcdif->base + LCDC_V8_CSC0_COEF2); + writel(coeffs[3], lcdif->base + LCDC_V8_CSC0_COEF3); + writel(coeffs[4], lcdif->base + LCDC_V8_CSC0_COEF4); + writel(coeffs[5], lcdif->base + LCDC_V8_CSC0_COEF5); + } else { + /* RGB -> RGB, YCbCr -> YCbCr: bypass colorspace converter. */ + writel(CSC0_CTRL_BYPASS, lcdif->base + LCDC_V8_CSC0_CTRL); + } } static void lcdif_set_mode(struct lcdif_drm_private *lcdif, u32 bus_flags) @@ -194,6 +360,7 @@ static void lcdif_reset_block(struct lcdif_drm_private *lcdif) } static void lcdif_crtc_mode_set_nofb(struct lcdif_drm_private *lcdif, + struct drm_plane_state *plane_state, struct drm_bridge_state *bridge_state, const u32 bus_format) { @@ -216,7 +383,7 @@ static void lcdif_crtc_mode_set_nofb(struct lcdif_drm_private *lcdif, /* Mandatory eLCDIF reset as per the Reference Manual */ lcdif_reset_block(lcdif); - lcdif_set_formats(lcdif, bus_format); + lcdif_set_formats(lcdif, plane_state, bus_format); lcdif_set_mode(lcdif, bus_flags); } @@ -299,7 +466,7 @@ static void lcdif_crtc_atomic_enable(struct drm_crtc *crtc, pm_runtime_get_sync(drm->dev); - lcdif_crtc_mode_set_nofb(lcdif, bridge_state, bus_format); + lcdif_crtc_mode_set_nofb(lcdif, new_pstate, bridge_state, bus_format); /* Write cur_buf as well to avoid an initial corrupt frame */ paddr = drm_fb_dma_get_gem_addr(new_pstate->fb, new_pstate, 0); @@ -443,12 +610,19 @@ static const struct drm_plane_funcs lcdif_plane_funcs = { }; static const u32 lcdif_primary_plane_formats[] = { + /* RGB */ DRM_FORMAT_RGB565, DRM_FORMAT_RGB888, DRM_FORMAT_XBGR8888, DRM_FORMAT_XRGB1555, DRM_FORMAT_XRGB4444, DRM_FORMAT_XRGB8888, + + /* Packed YCbCr */ + DRM_FORMAT_YUYV, + DRM_FORMAT_YVYU, + DRM_FORMAT_UYVY, + DRM_FORMAT_VYUY, }; static const u64 lcdif_modifiers[] = { @@ -462,6 +636,11 @@ static const u64 lcdif_modifiers[] = { int lcdif_kms_init(struct lcdif_drm_private *lcdif) { + const u32 supported_encodings = BIT(DRM_COLOR_YCBCR_BT601) | + BIT(DRM_COLOR_YCBCR_BT709) | + BIT(DRM_COLOR_YCBCR_BT2020); + const u32 supported_ranges = BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) | + BIT(DRM_COLOR_YCBCR_FULL_RANGE); struct drm_encoder *encoder = &lcdif->encoder; struct drm_crtc *crtc = &lcdif->crtc; int ret; @@ -477,6 +656,14 @@ int lcdif_kms_init(struct lcdif_drm_private *lcdif) if (ret) return ret; + ret = drm_plane_create_color_properties(&lcdif->planes.primary, + supported_encodings, + supported_ranges, + DRM_COLOR_YCBCR_BT601, + DRM_COLOR_YCBCR_LIMITED_RANGE); + if (ret) + return ret; + drm_crtc_helper_add(crtc, &lcdif_crtc_helper_funcs); ret = drm_crtc_init_with_planes(lcdif->drm, crtc, &lcdif->planes.primary, NULL, diff --git a/drivers/gpu/drm/mxsfb/lcdif_regs.h b/drivers/gpu/drm/mxsfb/lcdif_regs.h index 03c7827bdf5a..2d3920b8371e 100644 --- a/drivers/gpu/drm/mxsfb/lcdif_regs.h +++ b/drivers/gpu/drm/mxsfb/lcdif_regs.h @@ -212,7 +212,10 @@ #define CTRLDESCL0_5_YUV_FORMAT_UY2VY1 (0x3 << 14) #define CTRLDESCL0_5_YUV_FORMAT_MASK GENMASK(15, 14) -#define CSC0_CTRL_CSC_MODE_RGB2YCbCr GENMASK(2, 1) +#define CSC0_CTRL_CSC_MODE_YUV2RGB (0x0 << 1) +#define CSC0_CTRL_CSC_MODE_YCbCr2RGB (0x1 << 1) +#define CSC0_CTRL_CSC_MODE_RGB2YUV (0x2 << 1) +#define CSC0_CTRL_CSC_MODE_RGB2YCbCr (0x3 << 1) #define CSC0_CTRL_CSC_MODE_MASK GENMASK(2, 1) #define CSC0_CTRL_BYPASS BIT(0) -- cgit From 1fe182154984fa7942f8aafc268e9922e553cb13 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 13 Oct 2022 13:29:16 +0200 Subject: drm/ast: Acquire I/O-register lock in atomic_commit_tail function Hold I/O-register lock in atomic_commit_tail to protect all pipeline updates at once. Protects modesetting against concurrent EDID reads. Complex modesetting operations involve mode changes and plane updates. These steps used to be protected individually against concurrent I/O. Make all this atomic wrt to reading display modes via EDID. The EDID code in the connector's get_modes helper already acquires the necessary lock. A similar issue was fixed in commit 2d70b9a1482e ("drm/mgag200: Acquire I/O-register lock in atomic_commit_tail function") for mgag200. v2: * fix typo in commit message (Jocelyn) Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Tested-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20221013112923.769-2-tzimmermann@suse.de --- drivers/gpu/drm/ast/ast_mode.c | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index d5ee3ad538a8..e1e07928906e 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -1200,20 +1200,6 @@ out: return drm_atomic_add_affected_planes(state, crtc); } -static void ast_crtc_helper_atomic_begin(struct drm_crtc *crtc, struct drm_atomic_state *state) -{ - struct drm_device *dev = crtc->dev; - struct ast_private *ast = to_ast_private(dev); - - /* - * Concurrent operations could possibly trigger a call to - * drm_connector_helper_funcs.get_modes by trying to read the - * display modes. Protect access to I/O registers by acquiring - * the I/O-register lock. Released in atomic_flush(). - */ - mutex_lock(&ast->ioregs_lock); -} - static void ast_crtc_helper_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *state) @@ -1241,8 +1227,6 @@ ast_crtc_helper_atomic_flush(struct drm_crtc *crtc, //Set Aspeed Display-Port if (ast->tx_chip_types & AST_TX_ASTDP_BIT) ast_dp_set_mode(crtc, vbios_mode_info); - - mutex_unlock(&ast->ioregs_lock); } static void @@ -1301,7 +1285,6 @@ ast_crtc_helper_atomic_disable(struct drm_crtc *crtc, static const struct drm_crtc_helper_funcs ast_crtc_helper_funcs = { .mode_valid = ast_crtc_helper_mode_valid, .atomic_check = ast_crtc_helper_atomic_check, - .atomic_begin = ast_crtc_helper_atomic_begin, .atomic_flush = ast_crtc_helper_atomic_flush, .atomic_enable = ast_crtc_helper_atomic_enable, .atomic_disable = ast_crtc_helper_atomic_disable, @@ -1771,8 +1754,23 @@ static int ast_astdp_output_init(struct ast_private *ast) * Mode config */ +static void ast_mode_config_helper_atomic_commit_tail(struct drm_atomic_state *state) +{ + struct ast_private *ast = to_ast_private(state->dev); + + /* + * Concurrent operations could possibly trigger a call to + * drm_connector_helper_funcs.get_modes by trying to read the + * display modes. Protect access to I/O registers by acquiring + * the I/O-register lock. Released in atomic_flush(). + */ + mutex_lock(&ast->ioregs_lock); + drm_atomic_helper_commit_tail_rpm(state); + mutex_unlock(&ast->ioregs_lock); +} + static const struct drm_mode_config_helper_funcs ast_mode_config_helper_funcs = { - .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, + .atomic_commit_tail = ast_mode_config_helper_atomic_commit_tail, }; static const struct drm_mode_config_funcs ast_mode_config_funcs = { -- cgit From 0432a5044bb39fc542516cdec58e5041afad486c Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 13 Oct 2022 13:29:17 +0200 Subject: drm/ast: Call drm_atomic_helper_check_plane_state() unconditionally Always call drm_atomic_helper_check_plane_state() in each plane's atomic_check function. At the minimum, it needs to set or clear the plane state's 'visible' field. Otherwise the plane-state handling is bogus and would keep updating planes that have been disabled. While at it, also warn if the primary plane has been enabled, but is not visible. This cannot legally happen as the plane always covers the entire screen. Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Tested-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20221013112923.769-3-tzimmermann@suse.de --- drivers/gpu/drm/ast/ast_mode.c | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index e1e07928906e..e26471ecffb1 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -578,27 +578,28 @@ static const uint32_t ast_primary_plane_formats[] = { static int ast_primary_plane_helper_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state) { + struct drm_device *dev = plane->dev; struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); - struct drm_crtc_state *crtc_state; + struct drm_crtc_state *crtc_state = NULL; struct ast_crtc_state *ast_crtc_state; int ret; - if (!new_plane_state->crtc) - return 0; - - crtc_state = drm_atomic_get_new_crtc_state(state, - new_plane_state->crtc); + if (new_plane_state->crtc) + crtc_state = drm_atomic_get_new_crtc_state(state, new_plane_state->crtc); ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, DRM_PLANE_NO_SCALING, DRM_PLANE_NO_SCALING, false, true); - if (ret) + if (ret) { return ret; - - if (!new_plane_state->visible) - return 0; + } else if (!new_plane_state->visible) { + if (drm_WARN_ON(dev, new_plane_state->crtc)) /* cannot legally happen */ + return -EINVAL; + else + return 0; + } ast_crtc_state = to_ast_crtc_state(crtc_state); @@ -805,25 +806,19 @@ static int ast_cursor_plane_helper_atomic_check(struct drm_plane *plane, struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); struct drm_framebuffer *fb = new_plane_state->fb; - struct drm_crtc_state *crtc_state; + struct drm_crtc_state *crtc_state = NULL; int ret; - if (!new_plane_state->crtc) - return 0; - - crtc_state = drm_atomic_get_new_crtc_state(state, - new_plane_state->crtc); + if (new_plane_state->crtc) + crtc_state = drm_atomic_get_new_crtc_state(state, new_plane_state->crtc); ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, DRM_PLANE_NO_SCALING, DRM_PLANE_NO_SCALING, true, true); - if (ret) + if (ret || !new_plane_state->visible) return ret; - if (!new_plane_state->visible) - return 0; - if (fb->width > AST_MAX_HWC_WIDTH || fb->height > AST_MAX_HWC_HEIGHT) return -EINVAL; -- cgit From 963a2ba2adb51f677f2be875bb516fa636eaab47 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 13 Oct 2022 13:29:18 +0200 Subject: drm/ast: Do not call drm_atomic_add_affected_planes() There's no need to add planes to the atomic state. Remove the call to drm_atomic_add_affected_planes() from ast. On full modesets, the DRM helpers already add a CRTC's planes to the atomic state; see drm_atomic_helper_check_modeset(). There's no reason to call drm_atomic_add_affected_planes() unconditionally in the CRTC's atomic_check() in ast. It's also too late, as the atomic_check() of the added planes will not be called before the commit. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Reviewed-by: Jocelyn Falempe Tested-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20221013112923.769-4-tzimmermann@suse.de --- drivers/gpu/drm/ast/ast_mode.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index e26471ecffb1..059e4906507d 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -1157,7 +1157,7 @@ static int ast_crtc_helper_atomic_check(struct drm_crtc *crtc, int ret; if (!crtc_state->enable) - goto out; + return 0; ret = drm_atomic_helper_check_crtc_primary_plane(crtc_state); if (ret) @@ -1191,8 +1191,7 @@ static int ast_crtc_helper_atomic_check(struct drm_crtc *crtc, if (!succ) return -EINVAL; -out: - return drm_atomic_add_affected_planes(state, crtc); + return 0; } static void -- cgit From aa7c88650f705631f1e7ea03ea14171b0530b9ef Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 13 Oct 2022 13:29:19 +0200 Subject: drm/ast: Remove cursor double buffering Update the cursor image via damage handling in-place. The cursor's double buffering has no visible effect on the output, so remove it. Done in preparation of switching ast to GEM SHMEM helpers. Removing double buffering will allow us to use the same data structure for primary and cursor plane. Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Tested-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20221013112923.769-5-tzimmermann@suse.de --- drivers/gpu/drm/ast/ast_drv.h | 12 ++---- drivers/gpu/drm/ast/ast_mode.c | 83 ++++++++++++++++-------------------------- 2 files changed, 35 insertions(+), 60 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h index 2e44b971c3a6..12294c74d0fc 100644 --- a/drivers/gpu/drm/ast/ast_drv.h +++ b/drivers/gpu/drm/ast/ast_drv.h @@ -96,8 +96,6 @@ enum ast_tx_chip { #define AST_HWC_SIZE (AST_MAX_HWC_WIDTH * AST_MAX_HWC_HEIGHT * 2) #define AST_HWC_SIGNATURE_SIZE 32 -#define AST_DEFAULT_HWC_NUM 2 - /* define for signature structure */ #define AST_HWC_SIGNATURE_CHECKSUM 0x00 #define AST_HWC_SIGNATURE_SizeX 0x04 @@ -110,13 +108,9 @@ enum ast_tx_chip { struct ast_cursor_plane { struct drm_plane base; - struct { - struct drm_gem_vram_object *gbo; - struct iosys_map map; - u64 off; - } hwc[AST_DEFAULT_HWC_NUM]; - - unsigned int next_hwc_index; + struct drm_gem_vram_object *gbo; + struct iosys_map map; + u64 off; }; static inline struct ast_cursor_plane * diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index 059e4906507d..06ee79ec86f1 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -837,10 +837,8 @@ ast_cursor_plane_helper_atomic_update(struct drm_plane *plane, struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(new_state); struct drm_framebuffer *fb = new_state->fb; struct ast_private *ast = to_ast_private(plane->dev); - struct iosys_map dst_map = - ast_cursor_plane->hwc[ast_cursor_plane->next_hwc_index].map; - u64 dst_off = - ast_cursor_plane->hwc[ast_cursor_plane->next_hwc_index].off; + struct iosys_map dst_map = ast_cursor_plane->map; + u64 dst_off = ast_cursor_plane->off; struct iosys_map src_map = shadow_plane_state->data[0]; unsigned int offset_x, offset_y; u16 x, y; @@ -860,13 +858,9 @@ ast_cursor_plane_helper_atomic_update(struct drm_plane *plane, ast_update_cursor_image(dst, src, fb->width, fb->height); - if (new_state->fb != old_state->fb) { + if (new_state->fb != old_state->fb) ast_set_cursor_base(ast, dst_off); - ++ast_cursor_plane->next_hwc_index; - ast_cursor_plane->next_hwc_index %= ARRAY_SIZE(ast_cursor_plane->hwc); - } - /* * Update location in HWC signature and registers. */ @@ -917,17 +911,12 @@ static const struct drm_plane_helper_funcs ast_cursor_plane_helper_funcs = { static void ast_cursor_plane_destroy(struct drm_plane *plane) { struct ast_cursor_plane *ast_cursor_plane = to_ast_cursor_plane(plane); - size_t i; - struct drm_gem_vram_object *gbo; - struct iosys_map map; + struct drm_gem_vram_object *gbo = ast_cursor_plane->gbo; + struct iosys_map map = ast_cursor_plane->map; - for (i = 0; i < ARRAY_SIZE(ast_cursor_plane->hwc); ++i) { - gbo = ast_cursor_plane->hwc[i].gbo; - map = ast_cursor_plane->hwc[i].map; - drm_gem_vram_vunmap(gbo, &map); - drm_gem_vram_unpin(gbo); - drm_gem_vram_put(gbo); - } + drm_gem_vram_vunmap(gbo, &map); + drm_gem_vram_unpin(gbo); + drm_gem_vram_put(gbo); drm_plane_cleanup(plane); } @@ -944,7 +933,7 @@ static int ast_cursor_plane_init(struct ast_private *ast) struct drm_device *dev = &ast->base; struct ast_cursor_plane *ast_cursor_plane = &ast->cursor_plane; struct drm_plane *cursor_plane = &ast_cursor_plane->base; - size_t size, i; + size_t size; struct drm_gem_vram_object *gbo; struct iosys_map map; int ret; @@ -957,29 +946,27 @@ static int ast_cursor_plane_init(struct ast_private *ast) size = roundup(AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE, PAGE_SIZE); - for (i = 0; i < ARRAY_SIZE(ast_cursor_plane->hwc); ++i) { - gbo = drm_gem_vram_create(dev, size, 0); - if (IS_ERR(gbo)) { - ret = PTR_ERR(gbo); - goto err_hwc; - } - ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM | - DRM_GEM_VRAM_PL_FLAG_TOPDOWN); - if (ret) - goto err_drm_gem_vram_put; - ret = drm_gem_vram_vmap(gbo, &map); - if (ret) - goto err_drm_gem_vram_unpin; - off = drm_gem_vram_offset(gbo); - if (off < 0) { - ret = off; - goto err_drm_gem_vram_vunmap; - } - ast_cursor_plane->hwc[i].gbo = gbo; - ast_cursor_plane->hwc[i].map = map; - ast_cursor_plane->hwc[i].off = off; + gbo = drm_gem_vram_create(dev, size, 0); + if (IS_ERR(gbo)) + return PTR_ERR(gbo); + + ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM | + DRM_GEM_VRAM_PL_FLAG_TOPDOWN); + if (ret) + goto err_drm_gem_vram_put; + ret = drm_gem_vram_vmap(gbo, &map); + if (ret) + goto err_drm_gem_vram_unpin; + off = drm_gem_vram_offset(gbo); + if (off < 0) { + ret = off; + goto err_drm_gem_vram_vunmap; } + ast_cursor_plane->gbo = gbo; + ast_cursor_plane->map = map; + ast_cursor_plane->off = off; + /* * Create the cursor plane. The plane's destroy callback will release * the backing storages' BO memory. @@ -992,24 +979,18 @@ static int ast_cursor_plane_init(struct ast_private *ast) NULL, DRM_PLANE_TYPE_CURSOR, NULL); if (ret) { drm_err(dev, "drm_universal_plane failed(): %d\n", ret); - goto err_hwc; + goto err_drm_gem_vram_vunmap; } drm_plane_helper_add(cursor_plane, &ast_cursor_plane_helper_funcs); return 0; -err_hwc: - while (i) { - --i; - gbo = ast_cursor_plane->hwc[i].gbo; - map = ast_cursor_plane->hwc[i].map; err_drm_gem_vram_vunmap: - drm_gem_vram_vunmap(gbo, &map); + drm_gem_vram_vunmap(gbo, &map); err_drm_gem_vram_unpin: - drm_gem_vram_unpin(gbo); + drm_gem_vram_unpin(gbo); err_drm_gem_vram_put: - drm_gem_vram_put(gbo); - } + drm_gem_vram_put(gbo); return ret; } -- cgit From 537a1db9c5cd73989ed1aba38015281fab2b01d7 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 13 Oct 2022 13:29:20 +0200 Subject: drm/ast: Rename struct ast_cursor_plane to struct ast_plane Rename the plane structure struct ast_cursor_plane to struct ast_plane as it will be used for the primary plane as well. No functional changes. Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Tested-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20221013112923.769-6-tzimmermann@suse.de --- drivers/gpu/drm/ast/ast_drv.h | 15 +++++++++------ drivers/gpu/drm/ast/ast_mode.c | 22 +++++++++++----------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h index 12294c74d0fc..02120025b7ac 100644 --- a/drivers/gpu/drm/ast/ast_drv.h +++ b/drivers/gpu/drm/ast/ast_drv.h @@ -87,7 +87,7 @@ enum ast_tx_chip { #define AST_DRAM_8Gx16 8 /* - * Cursor plane + * Hardware cursor */ #define AST_MAX_HWC_WIDTH 64 @@ -105,7 +105,11 @@ enum ast_tx_chip { #define AST_HWC_SIGNATURE_HOTSPOTX 0x14 #define AST_HWC_SIGNATURE_HOTSPOTY 0x18 -struct ast_cursor_plane { +/* + * Planes + */ + +struct ast_plane { struct drm_plane base; struct drm_gem_vram_object *gbo; @@ -113,10 +117,9 @@ struct ast_cursor_plane { u64 off; }; -static inline struct ast_cursor_plane * -to_ast_cursor_plane(struct drm_plane *plane) +static inline struct ast_plane *to_ast_plane(struct drm_plane *plane) { - return container_of(plane, struct ast_cursor_plane, base); + return container_of(plane, struct ast_plane, base); } /* @@ -170,7 +173,7 @@ struct ast_private { uint32_t mclk; struct drm_plane primary_plane; - struct ast_cursor_plane cursor_plane; + struct ast_plane cursor_plane; struct drm_crtc crtc; struct { struct { diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index 06ee79ec86f1..00257db864ba 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -829,7 +829,7 @@ static void ast_cursor_plane_helper_atomic_update(struct drm_plane *plane, struct drm_atomic_state *state) { - struct ast_cursor_plane *ast_cursor_plane = to_ast_cursor_plane(plane); + struct ast_plane *ast_plane = to_ast_plane(plane); struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane); struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, @@ -837,8 +837,8 @@ ast_cursor_plane_helper_atomic_update(struct drm_plane *plane, struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(new_state); struct drm_framebuffer *fb = new_state->fb; struct ast_private *ast = to_ast_private(plane->dev); - struct iosys_map dst_map = ast_cursor_plane->map; - u64 dst_off = ast_cursor_plane->off; + struct iosys_map dst_map = ast_plane->map; + u64 dst_off = ast_plane->off; struct iosys_map src_map = shadow_plane_state->data[0]; unsigned int offset_x, offset_y; u16 x, y; @@ -910,9 +910,9 @@ static const struct drm_plane_helper_funcs ast_cursor_plane_helper_funcs = { static void ast_cursor_plane_destroy(struct drm_plane *plane) { - struct ast_cursor_plane *ast_cursor_plane = to_ast_cursor_plane(plane); - struct drm_gem_vram_object *gbo = ast_cursor_plane->gbo; - struct iosys_map map = ast_cursor_plane->map; + struct ast_plane *ast_plane = to_ast_plane(plane); + struct drm_gem_vram_object *gbo = ast_plane->gbo; + struct iosys_map map = ast_plane->map; drm_gem_vram_vunmap(gbo, &map); drm_gem_vram_unpin(gbo); @@ -931,8 +931,8 @@ static const struct drm_plane_funcs ast_cursor_plane_funcs = { static int ast_cursor_plane_init(struct ast_private *ast) { struct drm_device *dev = &ast->base; - struct ast_cursor_plane *ast_cursor_plane = &ast->cursor_plane; - struct drm_plane *cursor_plane = &ast_cursor_plane->base; + struct ast_plane *ast_plane = &ast->cursor_plane; + struct drm_plane *cursor_plane = &ast_plane->base; size_t size; struct drm_gem_vram_object *gbo; struct iosys_map map; @@ -963,9 +963,9 @@ static int ast_cursor_plane_init(struct ast_private *ast) goto err_drm_gem_vram_vunmap; } - ast_cursor_plane->gbo = gbo; - ast_cursor_plane->map = map; - ast_cursor_plane->off = off; + ast_plane->gbo = gbo; + ast_plane->map = map; + ast_plane->off = off; /* * Create the cursor plane. The plane's destroy callback will release -- cgit From d95dcfc4e3e747b7cee9077bfd18f6e5ccab1d12 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 13 Oct 2022 13:29:21 +0200 Subject: drm/ast: Style cleanups in plane code Rename some of the variables in the plane code to better reflect the old and new state during checks and updates. Change some indention as well. No functional changes. Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Tested-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20221013112923.769-7-tzimmermann@suse.de --- drivers/gpu/drm/ast/ast_mode.c | 104 ++++++++++++++++++----------------------- 1 file changed, 45 insertions(+), 59 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index 00257db864ba..59c70fd5b925 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -579,16 +579,15 @@ static int ast_primary_plane_helper_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state) { struct drm_device *dev = plane->dev; - struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, - plane); - struct drm_crtc_state *crtc_state = NULL; - struct ast_crtc_state *ast_crtc_state; + struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); + struct drm_crtc_state *new_crtc_state = NULL; + struct ast_crtc_state *new_ast_crtc_state; int ret; if (new_plane_state->crtc) - crtc_state = drm_atomic_get_new_crtc_state(state, new_plane_state->crtc); + new_crtc_state = drm_atomic_get_new_crtc_state(state, new_plane_state->crtc); - ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, + ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state, DRM_PLANE_NO_SCALING, DRM_PLANE_NO_SCALING, false, true); @@ -601,30 +600,28 @@ static int ast_primary_plane_helper_atomic_check(struct drm_plane *plane, return 0; } - ast_crtc_state = to_ast_crtc_state(crtc_state); + new_ast_crtc_state = to_ast_crtc_state(new_crtc_state); - ast_crtc_state->format = new_plane_state->fb->format; + new_ast_crtc_state->format = new_plane_state->fb->format; return 0; } -static void -ast_primary_plane_helper_atomic_update(struct drm_plane *plane, - struct drm_atomic_state *state) +static void ast_primary_plane_helper_atomic_update(struct drm_plane *plane, + struct drm_atomic_state *state) { - struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, - plane); struct drm_device *dev = plane->dev; struct ast_private *ast = to_ast_private(dev); - struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, - plane); + struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); + struct drm_framebuffer *fb = plane_state->fb; + struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); + struct drm_framebuffer *old_fb = old_plane_state->fb; struct drm_gem_vram_object *gbo; s64 gpu_addr; - struct drm_framebuffer *fb = new_state->fb; - struct drm_framebuffer *old_fb = old_state->fb; if (!old_fb || (fb->format != old_fb->format)) { - struct drm_crtc_state *crtc_state = new_state->crtc->state; + struct drm_crtc *crtc = plane_state->crtc; + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); struct ast_crtc_state *ast_crtc_state = to_ast_crtc_state(crtc_state); struct ast_vbios_mode_info *vbios_mode_info = &ast_crtc_state->vbios_mode_info; @@ -643,9 +640,8 @@ ast_primary_plane_helper_atomic_update(struct drm_plane *plane, ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x1, 0xdf, 0x00); } -static void -ast_primary_plane_helper_atomic_disable(struct drm_plane *plane, - struct drm_atomic_state *state) +static void ast_primary_plane_helper_atomic_disable(struct drm_plane *plane, + struct drm_atomic_state *state) { struct ast_private *ast = to_ast_private(plane->dev); @@ -803,39 +799,36 @@ static const uint32_t ast_cursor_plane_formats[] = { static int ast_cursor_plane_helper_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state) { - struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, - plane); - struct drm_framebuffer *fb = new_plane_state->fb; - struct drm_crtc_state *crtc_state = NULL; + struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); + struct drm_framebuffer *new_fb = new_plane_state->fb; + struct drm_crtc_state *new_crtc_state = NULL; int ret; if (new_plane_state->crtc) - crtc_state = drm_atomic_get_new_crtc_state(state, new_plane_state->crtc); + new_crtc_state = drm_atomic_get_new_crtc_state(state, new_plane_state->crtc); - ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, + ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state, DRM_PLANE_NO_SCALING, DRM_PLANE_NO_SCALING, true, true); if (ret || !new_plane_state->visible) return ret; - if (fb->width > AST_MAX_HWC_WIDTH || fb->height > AST_MAX_HWC_HEIGHT) + if (new_fb->width > AST_MAX_HWC_WIDTH || new_fb->height > AST_MAX_HWC_HEIGHT) return -EINVAL; return 0; } -static void -ast_cursor_plane_helper_atomic_update(struct drm_plane *plane, - struct drm_atomic_state *state) +static void ast_cursor_plane_helper_atomic_update(struct drm_plane *plane, + struct drm_atomic_state *state) { struct ast_plane *ast_plane = to_ast_plane(plane); - struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, - plane); - struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, - plane); - struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(new_state); - struct drm_framebuffer *fb = new_state->fb; + struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); + struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); + struct drm_framebuffer *fb = plane_state->fb; + struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); + struct drm_framebuffer *old_fb = old_plane_state->fb; struct ast_private *ast = to_ast_private(plane->dev); struct iosys_map dst_map = ast_plane->map; u64 dst_off = ast_plane->off; @@ -858,32 +851,32 @@ ast_cursor_plane_helper_atomic_update(struct drm_plane *plane, ast_update_cursor_image(dst, src, fb->width, fb->height); - if (new_state->fb != old_state->fb) + if (fb != old_fb) ast_set_cursor_base(ast, dst_off); /* * Update location in HWC signature and registers. */ - writel(new_state->crtc_x, sig + AST_HWC_SIGNATURE_X); - writel(new_state->crtc_y, sig + AST_HWC_SIGNATURE_Y); + writel(plane_state->crtc_x, sig + AST_HWC_SIGNATURE_X); + writel(plane_state->crtc_y, sig + AST_HWC_SIGNATURE_Y); offset_x = AST_MAX_HWC_WIDTH - fb->width; offset_y = AST_MAX_HWC_HEIGHT - fb->height; - if (new_state->crtc_x < 0) { - x_offset = (-new_state->crtc_x) + offset_x; + if (plane_state->crtc_x < 0) { + x_offset = (-plane_state->crtc_x) + offset_x; x = 0; } else { x_offset = offset_x; - x = new_state->crtc_x; + x = plane_state->crtc_x; } - if (new_state->crtc_y < 0) { - y_offset = (-new_state->crtc_y) + offset_y; + if (plane_state->crtc_y < 0) { + y_offset = (-plane_state->crtc_y) + offset_y; y = 0; } else { y_offset = offset_y; - y = new_state->crtc_y; + y = plane_state->crtc_y; } ast_set_cursor_location(ast, x, y, x_offset, y_offset); @@ -892,9 +885,8 @@ ast_cursor_plane_helper_atomic_update(struct drm_plane *plane, ast_set_cursor_enabled(ast, true); } -static void -ast_cursor_plane_helper_atomic_disable(struct drm_plane *plane, - struct drm_atomic_state *state) +static void ast_cursor_plane_helper_atomic_disable(struct drm_plane *plane, + struct drm_atomic_state *state) { struct ast_private *ast = to_ast_private(plane->dev); @@ -1204,13 +1196,11 @@ ast_crtc_helper_atomic_flush(struct drm_crtc *crtc, ast_dp_set_mode(crtc, vbios_mode_info); } -static void -ast_crtc_helper_atomic_enable(struct drm_crtc *crtc, - struct drm_atomic_state *state) +static void ast_crtc_helper_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state) { struct drm_device *dev = crtc->dev; struct ast_private *ast = to_ast_private(dev); - struct drm_crtc_state *crtc_state = crtc->state; + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); struct ast_crtc_state *ast_crtc_state = to_ast_crtc_state(crtc_state); struct ast_vbios_mode_info *vbios_mode_info = &ast_crtc_state->vbios_mode_info; @@ -1227,12 +1217,9 @@ ast_crtc_helper_atomic_enable(struct drm_crtc *crtc, ast_crtc_dpms(crtc, DRM_MODE_DPMS_ON); } -static void -ast_crtc_helper_atomic_disable(struct drm_crtc *crtc, - struct drm_atomic_state *state) +static void ast_crtc_helper_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *state) { - struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state, - crtc); + struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc); struct drm_device *dev = crtc->dev; struct ast_private *ast = to_ast_private(dev); @@ -1787,7 +1774,6 @@ int ast_mode_config_init(struct ast_private *ast) dev->mode_config.helper_private = &ast_mode_config_helper_funcs; - ret = ast_primary_plane_init(ast); if (ret) return ret; -- cgit From f2fa5a99ca81ce1056539e83c705f3d6bec62e31 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 13 Oct 2022 13:29:22 +0200 Subject: drm/ast: Convert ast to SHMEM Replace GEM VRAM helpers with GEM SHMEM helpers in ast. Avoids OOM errors when allocating video memory. Also adds support for dma-buf functionality. Aspeed display hardware supports display resolutions of FullHD and higher at 32-bit pixel depth. But the amount of video memory is in the range of 8 MiB to 32 MiB, which adds constraints to the actually available resolutions. As atomic modesetting with VRAM helpers requires double buffering in video memory, ast fails to pageflip in some configurations. For example, FullHD with an active cursor plane does not work on devices with 16 MiB of video memory. Resolve this problem by converting the ast driver to GEM SHMEM helpers. Keep the buffer objects in system memory and copy to video memory on pageflips via shadow-plane helpers. Userspace used to require shadow planes for decent performance, but that's now provided by the driver. To replace the memory management, the patch also implements damage handling for the primary plane. With GEM SHMEM helpers, dma-buf import and export is now supported by ast. This allows easier screen mirroring across devices or with an Aspeed-based BMC. A corresponding feature request is available at [1]. v2: * fix typos in commit message (Jocelyn) Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Tested-by: Jocelyn Falempe Link: https://lore.kernel.org/dri-devel/20220901124451.2523077-1-oushixiong@kylinos.cn/ # [1] Link: https://patchwork.freedesktop.org/patch/msgid/20221013112923.769-8-tzimmermann@suse.de --- drivers/gpu/drm/ast/Kconfig | 4 +- drivers/gpu/drm/ast/ast_drv.c | 4 +- drivers/gpu/drm/ast/ast_drv.h | 13 ++- drivers/gpu/drm/ast/ast_main.c | 5 +- drivers/gpu/drm/ast/ast_mm.c | 14 +-- drivers/gpu/drm/ast/ast_mode.c | 204 ++++++++++++++++++++++------------------- 6 files changed, 129 insertions(+), 115 deletions(-) diff --git a/drivers/gpu/drm/ast/Kconfig b/drivers/gpu/drm/ast/Kconfig index fbcf2f45cef5..d367a90cd3de 100644 --- a/drivers/gpu/drm/ast/Kconfig +++ b/drivers/gpu/drm/ast/Kconfig @@ -2,10 +2,8 @@ config DRM_AST tristate "AST server chips" depends on DRM && PCI && MMU + select DRM_GEM_SHMEM_HELPER select DRM_KMS_HELPER - select DRM_VRAM_HELPER - select DRM_TTM - select DRM_TTM_HELPER help Say yes for experimental AST GPU driver. Do not enable this driver without having a working -modesetting, diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c index b9392f31e629..bbeb5defc8f5 100644 --- a/drivers/gpu/drm/ast/ast_drv.c +++ b/drivers/gpu/drm/ast/ast_drv.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include @@ -63,7 +63,7 @@ static const struct drm_driver ast_driver = { .minor = DRIVER_MINOR, .patchlevel = DRIVER_PATCHLEVEL, - DRM_GEM_VRAM_DRIVER + DRM_GEM_SHMEM_DRIVER_OPS }; /* diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h index 02120025b7ac..74f41282444f 100644 --- a/drivers/gpu/drm/ast/ast_drv.h +++ b/drivers/gpu/drm/ast/ast_drv.h @@ -112,9 +112,9 @@ enum ast_tx_chip { struct ast_plane { struct drm_plane base; - struct drm_gem_vram_object *gbo; - struct iosys_map map; - u64 off; + void __iomem *vaddr; + u64 offset; + unsigned long size; }; static inline struct ast_plane *to_ast_plane(struct drm_plane *plane) @@ -172,7 +172,12 @@ struct ast_private { uint32_t dram_type; uint32_t mclk; - struct drm_plane primary_plane; + void __iomem *vram; + unsigned long vram_base; + unsigned long vram_size; + unsigned long vram_fb_available; + + struct ast_plane primary_plane; struct ast_plane cursor_plane; struct drm_crtc crtc; struct { diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index 067453266897..bffa310a0431 100644 --- a/drivers/gpu/drm/ast/ast_main.c +++ b/drivers/gpu/drm/ast/ast_main.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include "ast_drv.h" @@ -461,8 +460,8 @@ struct ast_private *ast_device_create(const struct drm_driver *drv, /* map reserved buffer */ ast->dp501_fw_buf = NULL; - if (dev->vram_mm->vram_size < pci_resource_len(pdev, 0)) { - ast->dp501_fw_buf = pci_iomap_range(pdev, 0, dev->vram_mm->vram_size, 0); + if (ast->vram_size < pci_resource_len(pdev, 0)) { + ast->dp501_fw_buf = pci_iomap_range(pdev, 0, ast->vram_size, 0); if (!ast->dp501_fw_buf) drm_info(dev, "failed to map reserved buffer!\n"); } diff --git a/drivers/gpu/drm/ast/ast_mm.c b/drivers/gpu/drm/ast/ast_mm.c index 6e999408dda9..248284a4b3ff 100644 --- a/drivers/gpu/drm/ast/ast_mm.c +++ b/drivers/gpu/drm/ast/ast_mm.c @@ -28,7 +28,6 @@ #include -#include #include #include @@ -80,7 +79,6 @@ int ast_mm_init(struct ast_private *ast) struct pci_dev *pdev = to_pci_dev(dev->dev); resource_size_t base, size; u32 vram_size; - int ret; base = pci_resource_start(pdev, 0); size = pci_resource_len(pdev, 0); @@ -91,11 +89,13 @@ int ast_mm_init(struct ast_private *ast) vram_size = ast_get_vram_size(ast); - ret = drmm_vram_helper_init(dev, base, vram_size); - if (ret) { - drm_err(dev, "Error initializing VRAM MM; %d\n", ret); - return ret; - } + ast->vram = devm_ioremap_wc(dev->dev, base, vram_size); + if (!ast->vram) + return -ENOMEM; + + ast->vram_base = base; + ast->vram_size = vram_size; + ast->vram_fb_available = vram_size; return 0; } diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index 59c70fd5b925..1b991658290b 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -36,11 +36,13 @@ #include #include #include +#include #include +#include #include #include #include -#include +#include #include #include #include @@ -565,6 +567,29 @@ static void ast_wait_for_vretrace(struct ast_private *ast) } while (!(vgair1 & AST_IO_VGAIR1_VREFRESH) && time_before(jiffies, timeout)); } +/* + * Planes + */ + +static int ast_plane_init(struct drm_device *dev, struct ast_plane *ast_plane, + void __iomem *vaddr, u64 offset, unsigned long size, + uint32_t possible_crtcs, + const struct drm_plane_funcs *funcs, + const uint32_t *formats, unsigned int format_count, + const uint64_t *format_modifiers, + enum drm_plane_type type) +{ + struct drm_plane *plane = &ast_plane->base; + + ast_plane->vaddr = vaddr; + ast_plane->offset = offset; + ast_plane->size = size; + + return drm_universal_plane_init(dev, plane, possible_crtcs, funcs, + formats, format_count, format_modifiers, + type, NULL); +} + /* * Primary plane */ @@ -607,17 +632,29 @@ static int ast_primary_plane_helper_atomic_check(struct drm_plane *plane, return 0; } +static void ast_handle_damage(struct ast_plane *ast_plane, struct iosys_map *src, + struct drm_framebuffer *fb, + const struct drm_rect *clip) +{ + struct iosys_map dst = IOSYS_MAP_INIT_VADDR(ast_plane->vaddr); + + iosys_map_incr(&dst, drm_fb_clip_offset(fb->pitches[0], fb->format, clip)); + drm_fb_memcpy(&dst, fb->pitches, src, fb, clip); +} + static void ast_primary_plane_helper_atomic_update(struct drm_plane *plane, struct drm_atomic_state *state) { struct drm_device *dev = plane->dev; struct ast_private *ast = to_ast_private(dev); struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); + struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); struct drm_framebuffer *fb = plane_state->fb; struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); struct drm_framebuffer *old_fb = old_plane_state->fb; - struct drm_gem_vram_object *gbo; - s64 gpu_addr; + struct ast_plane *ast_plane = to_ast_plane(plane); + struct drm_rect damage; + struct drm_atomic_helper_damage_iter iter; if (!old_fb || (fb->format != old_fb->format)) { struct drm_crtc *crtc = plane_state->crtc; @@ -629,13 +666,13 @@ static void ast_primary_plane_helper_atomic_update(struct drm_plane *plane, ast_set_vbios_color_reg(ast, fb->format, vbios_mode_info); } - gbo = drm_gem_vram_of_gem(fb->obj[0]); - gpu_addr = drm_gem_vram_offset(gbo); - if (drm_WARN_ON_ONCE(dev, gpu_addr < 0)) - return; /* Bug: we didn't pin the BO to VRAM in prepare_fb. */ + drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state); + drm_atomic_for_each_plane_damage(&iter, &damage) { + ast_handle_damage(ast_plane, shadow_plane_state->data, fb, &damage); + } ast_set_offset_reg(ast, fb); - ast_set_start_address_crt1(ast, (u32)gpu_addr); + ast_set_start_address_crt1(ast, (u32)ast_plane->offset); ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x1, 0xdf, 0x00); } @@ -649,7 +686,7 @@ static void ast_primary_plane_helper_atomic_disable(struct drm_plane *plane, } static const struct drm_plane_helper_funcs ast_primary_plane_helper_funcs = { - DRM_GEM_VRAM_PLANE_HELPER_FUNCS, + DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, .atomic_check = ast_primary_plane_helper_atomic_check, .atomic_update = ast_primary_plane_helper_atomic_update, .atomic_disable = ast_primary_plane_helper_atomic_disable, @@ -659,27 +696,30 @@ static const struct drm_plane_funcs ast_primary_plane_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, .destroy = drm_plane_cleanup, - .reset = drm_atomic_helper_plane_reset, - .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, + DRM_GEM_SHADOW_PLANE_FUNCS, }; static int ast_primary_plane_init(struct ast_private *ast) { struct drm_device *dev = &ast->base; - struct drm_plane *primary_plane = &ast->primary_plane; + struct ast_plane *ast_primary_plane = &ast->primary_plane; + struct drm_plane *primary_plane = &ast_primary_plane->base; + void __iomem *vaddr = ast->vram; + u64 offset = ast->vram_base; + unsigned long cursor_size = roundup(AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE, PAGE_SIZE); + unsigned long size = ast->vram_fb_available - cursor_size; int ret; - ret = drm_universal_plane_init(dev, primary_plane, 0x01, - &ast_primary_plane_funcs, - ast_primary_plane_formats, - ARRAY_SIZE(ast_primary_plane_formats), - NULL, DRM_PLANE_TYPE_PRIMARY, NULL); + ret = ast_plane_init(dev, ast_primary_plane, vaddr, offset, size, + 0x01, &ast_primary_plane_funcs, + ast_primary_plane_formats, ARRAY_SIZE(ast_primary_plane_formats), + NULL, DRM_PLANE_TYPE_PRIMARY); if (ret) { - drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret); + drm_err(dev, "ast_plane_init() failed: %d\n", ret); return ret; } drm_plane_helper_add(primary_plane, &ast_primary_plane_helper_funcs); + drm_plane_enable_fb_damage_clips(primary_plane); return 0; } @@ -828,31 +868,26 @@ static void ast_cursor_plane_helper_atomic_update(struct drm_plane *plane, struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); struct drm_framebuffer *fb = plane_state->fb; struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); - struct drm_framebuffer *old_fb = old_plane_state->fb; struct ast_private *ast = to_ast_private(plane->dev); - struct iosys_map dst_map = ast_plane->map; - u64 dst_off = ast_plane->off; struct iosys_map src_map = shadow_plane_state->data[0]; + struct drm_rect damage; + const u8 *src = src_map.vaddr; /* TODO: Use mapping abstraction properly */ + u64 dst_off = ast_plane->offset; + u8 __iomem *dst = ast_plane->vaddr; /* TODO: Use mapping abstraction properly */ + u8 __iomem *sig = dst + AST_HWC_SIZE; /* TODO: Use mapping abstraction properly */ unsigned int offset_x, offset_y; u16 x, y; u8 x_offset, y_offset; - u8 __iomem *dst; - u8 __iomem *sig; - const u8 *src; - - src = src_map.vaddr; /* TODO: Use mapping abstraction properly */ - dst = dst_map.vaddr_iomem; /* TODO: Use mapping abstraction properly */ - sig = dst + AST_HWC_SIZE; /* TODO: Use mapping abstraction properly */ /* - * Do data transfer to HW cursor BO. If a new cursor image was installed, - * point the scanout engine to dst_gbo's offset and page-flip the HWC buffers. + * Do data transfer to hardware buffer and point the scanout + * engine to the offset. */ - ast_update_cursor_image(dst, src, fb->width, fb->height); - - if (fb != old_fb) + if (drm_atomic_helper_damage_merged(old_plane_state, plane_state, &damage)) { + ast_update_cursor_image(dst, src, fb->width, fb->height); ast_set_cursor_base(ast, dst_off); + } /* * Update location in HWC signature and registers. @@ -900,36 +935,22 @@ static const struct drm_plane_helper_funcs ast_cursor_plane_helper_funcs = { .atomic_disable = ast_cursor_plane_helper_atomic_disable, }; -static void ast_cursor_plane_destroy(struct drm_plane *plane) -{ - struct ast_plane *ast_plane = to_ast_plane(plane); - struct drm_gem_vram_object *gbo = ast_plane->gbo; - struct iosys_map map = ast_plane->map; - - drm_gem_vram_vunmap(gbo, &map); - drm_gem_vram_unpin(gbo); - drm_gem_vram_put(gbo); - - drm_plane_cleanup(plane); -} - static const struct drm_plane_funcs ast_cursor_plane_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, - .destroy = ast_cursor_plane_destroy, + .destroy = drm_plane_cleanup, DRM_GEM_SHADOW_PLANE_FUNCS, }; static int ast_cursor_plane_init(struct ast_private *ast) { struct drm_device *dev = &ast->base; - struct ast_plane *ast_plane = &ast->cursor_plane; - struct drm_plane *cursor_plane = &ast_plane->base; + struct ast_plane *ast_cursor_plane = &ast->cursor_plane; + struct drm_plane *cursor_plane = &ast_cursor_plane->base; size_t size; - struct drm_gem_vram_object *gbo; - struct iosys_map map; + void __iomem *vaddr; + u64 offset; int ret; - s64 off; /* * Allocate backing storage for cursors. The BOs are permanently @@ -938,52 +959,26 @@ static int ast_cursor_plane_init(struct ast_private *ast) size = roundup(AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE, PAGE_SIZE); - gbo = drm_gem_vram_create(dev, size, 0); - if (IS_ERR(gbo)) - return PTR_ERR(gbo); - - ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM | - DRM_GEM_VRAM_PL_FLAG_TOPDOWN); - if (ret) - goto err_drm_gem_vram_put; - ret = drm_gem_vram_vmap(gbo, &map); - if (ret) - goto err_drm_gem_vram_unpin; - off = drm_gem_vram_offset(gbo); - if (off < 0) { - ret = off; - goto err_drm_gem_vram_vunmap; - } + if (ast->vram_fb_available < size) + return -ENOMEM; - ast_plane->gbo = gbo; - ast_plane->map = map; - ast_plane->off = off; - - /* - * Create the cursor plane. The plane's destroy callback will release - * the backing storages' BO memory. - */ + vaddr = ast->vram + ast->vram_fb_available - size; + offset = ast->vram_base + ast->vram_fb_available - size; - ret = drm_universal_plane_init(dev, cursor_plane, 0x01, - &ast_cursor_plane_funcs, - ast_cursor_plane_formats, - ARRAY_SIZE(ast_cursor_plane_formats), - NULL, DRM_PLANE_TYPE_CURSOR, NULL); + ret = ast_plane_init(dev, ast_cursor_plane, vaddr, offset, size, + 0x01, &ast_cursor_plane_funcs, + ast_cursor_plane_formats, ARRAY_SIZE(ast_cursor_plane_formats), + NULL, DRM_PLANE_TYPE_CURSOR); if (ret) { - drm_err(dev, "drm_universal_plane failed(): %d\n", ret); - goto err_drm_gem_vram_vunmap; + drm_err(dev, "ast_plane_init() failed: %d\n", ret); + return ret; } drm_plane_helper_add(cursor_plane, &ast_cursor_plane_helper_funcs); + drm_plane_enable_fb_damage_clips(cursor_plane); - return 0; + ast->vram_fb_available -= size; -err_drm_gem_vram_vunmap: - drm_gem_vram_vunmap(gbo, &map); -err_drm_gem_vram_unpin: - drm_gem_vram_unpin(gbo); -err_drm_gem_vram_put: - drm_gem_vram_put(gbo); - return ret; + return 0; } /* @@ -1313,7 +1308,7 @@ static int ast_crtc_init(struct drm_device *dev) struct drm_crtc *crtc = &ast->crtc; int ret; - ret = drm_crtc_init_with_planes(dev, crtc, &ast->primary_plane, + ret = drm_crtc_init_with_planes(dev, crtc, &ast->primary_plane.base, &ast->cursor_plane.base, &ast_crtc_funcs, NULL); if (ret) @@ -1735,9 +1730,27 @@ static const struct drm_mode_config_helper_funcs ast_mode_config_helper_funcs = .atomic_commit_tail = ast_mode_config_helper_atomic_commit_tail, }; +static enum drm_mode_status ast_mode_config_mode_valid(struct drm_device *dev, + const struct drm_display_mode *mode) +{ + static const unsigned long max_bpp = 4; /* DRM_FORMAT_XRGB8888 */ + struct ast_private *ast = to_ast_private(dev); + unsigned long fbsize, fbpages, max_fbpages; + + max_fbpages = (ast->vram_fb_available) >> PAGE_SHIFT; + + fbsize = mode->hdisplay * mode->vdisplay * max_bpp; + fbpages = DIV_ROUND_UP(fbsize, PAGE_SIZE); + + if (fbpages > max_fbpages) + return MODE_MEM; + + return MODE_OK; +} + static const struct drm_mode_config_funcs ast_mode_config_funcs = { - .fb_create = drm_gem_fb_create, - .mode_valid = drm_vram_helper_mode_valid, + .fb_create = drm_gem_fb_create_with_dirty, + .mode_valid = ast_mode_config_mode_valid, .atomic_check = drm_atomic_helper_check, .atomic_commit = drm_atomic_helper_commit, }; @@ -1756,7 +1769,6 @@ int ast_mode_config_init(struct ast_private *ast) dev->mode_config.min_width = 0; dev->mode_config.min_height = 0; dev->mode_config.preferred_depth = 24; - dev->mode_config.prefer_shadow = 1; dev->mode_config.fb_base = pci_resource_start(pdev, 0); if (ast->chip == AST2100 || -- cgit From 202fb33be38c98f7bc9f0fa370cd13d189b4f9d8 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 13 Oct 2022 13:29:23 +0200 Subject: drm/ast: Avoid reprogramming primary-plane scanout address Some AST-based BMCs stop display output for up to 5 seconds after reprogramming the scanout address. As the address is fixed, avoid re-setting the address' value. v2: * only update offset if it changed (Jocelyn) Reported-by: Jocelyn Falempe Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Tested-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20221013112923.769-9-tzimmermann@suse.de --- drivers/gpu/drm/ast/ast_mode.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index 1b991658290b..4355754d69b5 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -671,10 +671,19 @@ static void ast_primary_plane_helper_atomic_update(struct drm_plane *plane, ast_handle_damage(ast_plane, shadow_plane_state->data, fb, &damage); } - ast_set_offset_reg(ast, fb); - ast_set_start_address_crt1(ast, (u32)ast_plane->offset); - - ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x1, 0xdf, 0x00); + /* + * Some BMCs stop scanning out the video signal after the driver + * reprogrammed the offset or scanout address. This stalls display + * output for several seconds and makes the display unusable. + * Therefore only update the offset if it changes and reprogram the + * address after enabling the plane. + */ + if (!old_fb || old_fb->pitches[0] != fb->pitches[0]) + ast_set_offset_reg(ast, fb); + if (!old_fb) { + ast_set_start_address_crt1(ast, (u32)ast_plane->offset); + ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x1, 0xdf, 0x00); + } } static void ast_primary_plane_helper_atomic_disable(struct drm_plane *plane, -- cgit From d32f7960fb9370b9756f1668a7093a7afdaef72c Mon Sep 17 00:00:00 2001 From: Maíra Canal Date: Sat, 1 Oct 2022 19:34:21 -0300 Subject: drm/tests: Split drm_test_dp_mst_calc_pbn_mode into parameterized tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The drm_test_dp_mst_calc_pbn_mode is based on a loop that executes tests for a couple of test cases. This could be better represented by parameterized tests, provided by KUnit. So, convert the drm_test_dp_mst_calc_pbn_mode into parameterized tests. Signed-off-by: Maíra Canal Reviewed-by: Michał Winiarski Signed-off-by: Maíra Canal Link: https://patchwork.freedesktop.org/patch/msgid/20221001223422.857505-1-mcanal@igalia.com --- drivers/gpu/drm/tests/drm_dp_mst_helper_test.c | 77 ++++++++++++++++++-------- 1 file changed, 53 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/tests/drm_dp_mst_helper_test.c b/drivers/gpu/drm/tests/drm_dp_mst_helper_test.c index 65c9d225b558..12f41881db6b 100644 --- a/drivers/gpu/drm/tests/drm_dp_mst_helper_test.c +++ b/drivers/gpu/drm/tests/drm_dp_mst_helper_test.c @@ -16,33 +16,62 @@ #include "../display/drm_dp_mst_topology_internal.h" +struct drm_dp_mst_calc_pbn_mode_test { + const int clock; + const int bpp; + const bool dsc; + const int expected; +}; + +static const struct drm_dp_mst_calc_pbn_mode_test drm_dp_mst_calc_pbn_mode_cases[] = { + { + .clock = 154000, + .bpp = 30, + .dsc = false, + .expected = 689 + }, + { + .clock = 234000, + .bpp = 30, + .dsc = false, + .expected = 1047 + }, + { + .clock = 297000, + .bpp = 24, + .dsc = false, + .expected = 1063 + }, + { + .clock = 332880, + .bpp = 24, + .dsc = true, + .expected = 50 + }, + { + .clock = 324540, + .bpp = 24, + .dsc = true, + .expected = 49 + }, +}; + static void drm_test_dp_mst_calc_pbn_mode(struct kunit *test) { - int pbn, i; - const struct { - int rate; - int bpp; - int expected; - bool dsc; - } test_params[] = { - { 154000, 30, 689, false }, - { 234000, 30, 1047, false }, - { 297000, 24, 1063, false }, - { 332880, 24, 50, true }, - { 324540, 24, 49, true }, - }; - - for (i = 0; i < ARRAY_SIZE(test_params); i++) { - pbn = drm_dp_calc_pbn_mode(test_params[i].rate, - test_params[i].bpp, - test_params[i].dsc); - KUNIT_EXPECT_EQ_MSG(test, pbn, test_params[i].expected, - "Expected PBN %d for clock %d bpp %d, got %d\n", - test_params[i].expected, test_params[i].rate, - test_params[i].bpp, pbn); - } + const struct drm_dp_mst_calc_pbn_mode_test *params = test->param_value; + + KUNIT_EXPECT_EQ(test, drm_dp_calc_pbn_mode(params->clock, params->bpp, params->dsc), + params->expected); } +static void dp_mst_calc_pbn_mode_desc(const struct drm_dp_mst_calc_pbn_mode_test *t, char *desc) +{ + sprintf(desc, "Clock %d BPP %d DSC %s", t->clock, t->bpp, t->dsc ? "enabled" : "disabled"); +} + +KUNIT_ARRAY_PARAM(drm_dp_mst_calc_pbn_mode, drm_dp_mst_calc_pbn_mode_cases, + dp_mst_calc_pbn_mode_desc); + static bool sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in, const struct drm_dp_sideband_msg_req_body *out) @@ -271,7 +300,7 @@ static void drm_test_dp_mst_sideband_msg_req_decode(struct kunit *test) } static struct kunit_case drm_dp_mst_helper_tests[] = { - KUNIT_CASE(drm_test_dp_mst_calc_pbn_mode), + KUNIT_CASE_PARAM(drm_test_dp_mst_calc_pbn_mode, drm_dp_mst_calc_pbn_mode_gen_params), KUNIT_CASE(drm_test_dp_mst_sideband_msg_req_decode), { } }; -- cgit From 530f789766996c9298c02ac8b59cee6934322c6b Mon Sep 17 00:00:00 2001 From: Maíra Canal Date: Sat, 1 Oct 2022 19:34:22 -0300 Subject: drm/tests: Split drm_test_dp_mst_sideband_msg_req_decode into parameterized tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The drm_test_dp_mst_sideband_msg_req_decode repeats the same test structure with different parameters. This could be better represented by parameterized tests, provided by KUnit. In addition to the parameterization of the tests, the test case for the client ID was changed: instead of using get_random_bytes to generate the client ID, the client ID is now hardcoded in the test case. This doesn't affect the assertively of the tests, as this test case only compare the data going in with the data going out and it doesn't transform the data itself in any way. So, convert drm_test_dp_mst_sideband_msg_req_decode into parameterized tests and make the tests' allocations and prints completely managed by KUnit. Signed-off-by: Maíra Canal Reviewed-by: Michał Winiarski Signed-off-by: Maíra Canal Link: https://patchwork.freedesktop.org/patch/msgid/20221001223422.857505-2-mcanal@igalia.com --- drivers/gpu/drm/tests/drm_dp_mst_helper_test.c | 370 ++++++++++++++++--------- 1 file changed, 243 insertions(+), 127 deletions(-) diff --git a/drivers/gpu/drm/tests/drm_dp_mst_helper_test.c b/drivers/gpu/drm/tests/drm_dp_mst_helper_test.c index 12f41881db6b..545beea33e8c 100644 --- a/drivers/gpu/drm/tests/drm_dp_mst_helper_test.c +++ b/drivers/gpu/drm/tests/drm_dp_mst_helper_test.c @@ -5,12 +5,8 @@ * Copyright (c) 2022 Maíra Canal */ -#define PREFIX_STR "[drm_dp_mst_helper]" - #include -#include - #include #include @@ -72,6 +68,217 @@ static void dp_mst_calc_pbn_mode_desc(const struct drm_dp_mst_calc_pbn_mode_test KUNIT_ARRAY_PARAM(drm_dp_mst_calc_pbn_mode, drm_dp_mst_calc_pbn_mode_cases, dp_mst_calc_pbn_mode_desc); +static u8 data[] = { 0xff, 0x00, 0xdd }; + +struct drm_dp_mst_sideband_msg_req_test { + const char *desc; + const struct drm_dp_sideband_msg_req_body in; +}; + +static const struct drm_dp_mst_sideband_msg_req_test drm_dp_mst_sideband_msg_req_cases[] = { + { + .desc = "DP_ENUM_PATH_RESOURCES with port number", + .in = { + .req_type = DP_ENUM_PATH_RESOURCES, + .u.port_num.port_number = 5, + }, + }, + { + .desc = "DP_POWER_UP_PHY with port number", + .in = { + .req_type = DP_POWER_UP_PHY, + .u.port_num.port_number = 5, + }, + }, + { + .desc = "DP_POWER_DOWN_PHY with port number", + .in = { + .req_type = DP_POWER_DOWN_PHY, + .u.port_num.port_number = 5, + }, + }, + { + .desc = "DP_ALLOCATE_PAYLOAD with SDP stream sinks", + .in = { + .req_type = DP_ALLOCATE_PAYLOAD, + .u.allocate_payload.number_sdp_streams = 3, + .u.allocate_payload.sdp_stream_sink = { 1, 2, 3 }, + }, + }, + { + .desc = "DP_ALLOCATE_PAYLOAD with port number", + .in = { + .req_type = DP_ALLOCATE_PAYLOAD, + .u.allocate_payload.port_number = 0xf, + }, + }, + { + .desc = "DP_ALLOCATE_PAYLOAD with VCPI", + .in = { + .req_type = DP_ALLOCATE_PAYLOAD, + .u.allocate_payload.vcpi = 0x7f, + }, + }, + { + .desc = "DP_ALLOCATE_PAYLOAD with PBN", + .in = { + .req_type = DP_ALLOCATE_PAYLOAD, + .u.allocate_payload.pbn = U16_MAX, + }, + }, + { + .desc = "DP_QUERY_PAYLOAD with port number", + .in = { + .req_type = DP_QUERY_PAYLOAD, + .u.query_payload.port_number = 0xf, + }, + }, + { + .desc = "DP_QUERY_PAYLOAD with VCPI", + .in = { + .req_type = DP_QUERY_PAYLOAD, + .u.query_payload.vcpi = 0x7f, + }, + }, + { + .desc = "DP_REMOTE_DPCD_READ with port number", + .in = { + .req_type = DP_REMOTE_DPCD_READ, + .u.dpcd_read.port_number = 0xf, + }, + }, + { + .desc = "DP_REMOTE_DPCD_READ with DPCD address", + .in = { + .req_type = DP_REMOTE_DPCD_READ, + .u.dpcd_read.dpcd_address = 0xfedcb, + }, + }, + { + .desc = "DP_REMOTE_DPCD_READ with max number of bytes", + .in = { + .req_type = DP_REMOTE_DPCD_READ, + .u.dpcd_read.num_bytes = U8_MAX, + }, + }, + { + .desc = "DP_REMOTE_DPCD_WRITE with port number", + .in = { + .req_type = DP_REMOTE_DPCD_WRITE, + .u.dpcd_write.port_number = 0xf, + }, + }, + { + .desc = "DP_REMOTE_DPCD_WRITE with DPCD address", + .in = { + .req_type = DP_REMOTE_DPCD_WRITE, + .u.dpcd_write.dpcd_address = 0xfedcb, + }, + }, + { + .desc = "DP_REMOTE_DPCD_WRITE with data array", + .in = { + .req_type = DP_REMOTE_DPCD_WRITE, + .u.dpcd_write.num_bytes = ARRAY_SIZE(data), + .u.dpcd_write.bytes = data, + }, + }, + { + .desc = "DP_REMOTE_I2C_READ with port number", + .in = { + .req_type = DP_REMOTE_I2C_READ, + .u.i2c_read.port_number = 0xf, + }, + }, + { + .desc = "DP_REMOTE_I2C_READ with I2C device ID", + .in = { + .req_type = DP_REMOTE_I2C_READ, + .u.i2c_read.read_i2c_device_id = 0x7f, + }, + }, + { + .desc = "DP_REMOTE_I2C_READ with transactions array", + .in = { + .req_type = DP_REMOTE_I2C_READ, + .u.i2c_read.num_transactions = 3, + .u.i2c_read.num_bytes_read = ARRAY_SIZE(data) * 3, + .u.i2c_read.transactions = { + { .bytes = data, .num_bytes = ARRAY_SIZE(data), .i2c_dev_id = 0x7f, + .i2c_transaction_delay = 0xf, }, + { .bytes = data, .num_bytes = ARRAY_SIZE(data), .i2c_dev_id = 0x7e, + .i2c_transaction_delay = 0xe, }, + { .bytes = data, .num_bytes = ARRAY_SIZE(data), .i2c_dev_id = 0x7d, + .i2c_transaction_delay = 0xd, }, + }, + }, + }, + { + .desc = "DP_REMOTE_I2C_WRITE with port number", + .in = { + .req_type = DP_REMOTE_I2C_WRITE, + .u.i2c_write.port_number = 0xf, + }, + }, + { + .desc = "DP_REMOTE_I2C_WRITE with I2C device ID", + .in = { + .req_type = DP_REMOTE_I2C_WRITE, + .u.i2c_write.write_i2c_device_id = 0x7f, + }, + }, + { + .desc = "DP_REMOTE_I2C_WRITE with data array", + .in = { + .req_type = DP_REMOTE_I2C_WRITE, + .u.i2c_write.num_bytes = ARRAY_SIZE(data), + .u.i2c_write.bytes = data, + }, + }, + { + .desc = "DP_QUERY_STREAM_ENC_STATUS with stream ID", + .in = { + .req_type = DP_QUERY_STREAM_ENC_STATUS, + .u.enc_status.stream_id = 1, + }, + }, + { + .desc = "DP_QUERY_STREAM_ENC_STATUS with client ID", + .in = { + .req_type = DP_QUERY_STREAM_ENC_STATUS, + .u.enc_status.client_id = { 0x4f, 0x7f, 0xb4, 0x00, 0x8c, 0x0d, 0x67 }, + }, + }, + { + .desc = "DP_QUERY_STREAM_ENC_STATUS with stream event", + .in = { + .req_type = DP_QUERY_STREAM_ENC_STATUS, + .u.enc_status.stream_event = 3, + }, + }, + { + .desc = "DP_QUERY_STREAM_ENC_STATUS with valid stream event", + .in = { + .req_type = DP_QUERY_STREAM_ENC_STATUS, + .u.enc_status.valid_stream_event = 0, + }, + }, + { + .desc = "DP_QUERY_STREAM_ENC_STATUS with stream behavior", + .in = { + .req_type = DP_QUERY_STREAM_ENC_STATUS, + .u.enc_status.stream_behavior = 3, + }, + }, + { + .desc = "DP_QUERY_STREAM_ENC_STATUS with a valid stream behavior", + .in = { + .req_type = DP_QUERY_STREAM_ENC_STATUS, + .u.enc_status.valid_stream_behavior = 1, + } + }, +}; + static bool sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in, const struct drm_dp_sideband_msg_req_body *out) @@ -147,41 +354,41 @@ sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in, return true; } -static bool -sideband_msg_req_encode_decode(struct drm_dp_sideband_msg_req_body *in) +static void drm_test_dp_mst_msg_printf(struct drm_printer *p, struct va_format *vaf) +{ + struct kunit *test = p->arg; + + kunit_err(test, "%pV", vaf); +} + +static void drm_test_dp_mst_sideband_msg_req_decode(struct kunit *test) { + const struct drm_dp_mst_sideband_msg_req_test *params = test->param_value; + const struct drm_dp_sideband_msg_req_body *in = ¶ms->in; struct drm_dp_sideband_msg_req_body *out; - struct drm_printer p = drm_err_printer(PREFIX_STR); struct drm_dp_sideband_msg_tx *txmsg; - int i, ret; - bool result = true; + struct drm_printer p = { + .printfn = drm_test_dp_mst_msg_printf, + .arg = test + }; + int i; - out = kzalloc(sizeof(*out), GFP_KERNEL); - if (!out) - return false; + out = kunit_kzalloc(test, sizeof(*out), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, out); - txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL); - if (!txmsg) { - kfree(out); - return false; - } + txmsg = kunit_kzalloc(test, sizeof(*txmsg), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, txmsg); drm_dp_encode_sideband_req(in, txmsg); - ret = drm_dp_decode_sideband_req(txmsg, out); - if (ret < 0) { - drm_printf(&p, "Failed to decode sideband request: %d\n", - ret); - result = false; - goto out; - } + KUNIT_EXPECT_GE_MSG(test, drm_dp_decode_sideband_req(txmsg, out), 0, + "Failed to decode sideband request"); if (!sideband_msg_req_equal(in, out)) { - drm_printf(&p, "Encode/decode failed, expected:\n"); + KUNIT_FAIL(test, "Encode/decode failed"); + kunit_err(test, "Expected:"); drm_dp_dump_sideband_msg_req_body(in, 1, &p); - drm_printf(&p, "Got:\n"); + kunit_err(test, "Got:"); drm_dp_dump_sideband_msg_req_body(out, 1, &p); - result = false; - goto out; } switch (in->req_type) { @@ -196,112 +403,21 @@ sideband_msg_req_encode_decode(struct drm_dp_sideband_msg_req_body *in) kfree(out->u.i2c_write.bytes); break; } - - /* Clear everything but the req_type for the input */ - memset(&in->u, 0, sizeof(in->u)); - -out: - kfree(out); - kfree(txmsg); - return result; } -static void drm_test_dp_mst_sideband_msg_req_decode(struct kunit *test) +static void +drm_dp_mst_sideband_msg_req_desc(const struct drm_dp_mst_sideband_msg_req_test *t, char *desc) { - struct drm_dp_sideband_msg_req_body in = { 0 }; - u8 data[] = { 0xff, 0x0, 0xdd }; - int i; - - in.req_type = DP_ENUM_PATH_RESOURCES; - in.u.port_num.port_number = 5; - KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); - - in.req_type = DP_POWER_UP_PHY; - in.u.port_num.port_number = 5; - KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); - - in.req_type = DP_POWER_DOWN_PHY; - in.u.port_num.port_number = 5; - KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); - - in.req_type = DP_ALLOCATE_PAYLOAD; - in.u.allocate_payload.number_sdp_streams = 3; - for (i = 0; i < in.u.allocate_payload.number_sdp_streams; i++) - in.u.allocate_payload.sdp_stream_sink[i] = i + 1; - KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); - in.u.allocate_payload.port_number = 0xf; - KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); - in.u.allocate_payload.vcpi = 0x7f; - KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); - in.u.allocate_payload.pbn = U16_MAX; - KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); - - in.req_type = DP_QUERY_PAYLOAD; - in.u.query_payload.port_number = 0xf; - KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); - in.u.query_payload.vcpi = 0x7f; - KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); - - in.req_type = DP_REMOTE_DPCD_READ; - in.u.dpcd_read.port_number = 0xf; - KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); - in.u.dpcd_read.dpcd_address = 0xfedcb; - KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); - in.u.dpcd_read.num_bytes = U8_MAX; - KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); - - in.req_type = DP_REMOTE_DPCD_WRITE; - in.u.dpcd_write.port_number = 0xf; - KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); - in.u.dpcd_write.dpcd_address = 0xfedcb; - KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); - in.u.dpcd_write.num_bytes = ARRAY_SIZE(data); - in.u.dpcd_write.bytes = data; - KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); - - in.req_type = DP_REMOTE_I2C_READ; - in.u.i2c_read.port_number = 0xf; - KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); - in.u.i2c_read.read_i2c_device_id = 0x7f; - KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); - in.u.i2c_read.num_transactions = 3; - in.u.i2c_read.num_bytes_read = ARRAY_SIZE(data) * 3; - for (i = 0; i < in.u.i2c_read.num_transactions; i++) { - in.u.i2c_read.transactions[i].bytes = data; - in.u.i2c_read.transactions[i].num_bytes = ARRAY_SIZE(data); - in.u.i2c_read.transactions[i].i2c_dev_id = 0x7f & ~i; - in.u.i2c_read.transactions[i].i2c_transaction_delay = 0xf & ~i; - } - KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); - - in.req_type = DP_REMOTE_I2C_WRITE; - in.u.i2c_write.port_number = 0xf; - KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); - in.u.i2c_write.write_i2c_device_id = 0x7f; - KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); - in.u.i2c_write.num_bytes = ARRAY_SIZE(data); - in.u.i2c_write.bytes = data; - KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); - - in.req_type = DP_QUERY_STREAM_ENC_STATUS; - in.u.enc_status.stream_id = 1; - KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); - get_random_bytes(in.u.enc_status.client_id, - sizeof(in.u.enc_status.client_id)); - KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); - in.u.enc_status.stream_event = 3; - KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); - in.u.enc_status.valid_stream_event = 0; - KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); - in.u.enc_status.stream_behavior = 3; - KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); - in.u.enc_status.valid_stream_behavior = 1; - KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); + strcpy(desc, t->desc); } +KUNIT_ARRAY_PARAM(drm_dp_mst_sideband_msg_req, drm_dp_mst_sideband_msg_req_cases, + drm_dp_mst_sideband_msg_req_desc); + static struct kunit_case drm_dp_mst_helper_tests[] = { KUNIT_CASE_PARAM(drm_test_dp_mst_calc_pbn_mode, drm_dp_mst_calc_pbn_mode_gen_params), - KUNIT_CASE(drm_test_dp_mst_sideband_msg_req_decode), + KUNIT_CASE_PARAM(drm_test_dp_mst_sideband_msg_req_decode, + drm_dp_mst_sideband_msg_req_gen_params), { } }; -- cgit From f8ced2abe6df374cd6bbe7bc642397d439315033 Mon Sep 17 00:00:00 2001 From: Zeng Heng Date: Wed, 12 Oct 2022 20:47:35 +0800 Subject: drm/ttm: Remove unnecessary drm_mm_clean MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove unnecessary `drm_mm_clean` calling in `ttm_range_man_fini_nocheck`, due to effective check is already included in the following `drm_mm_takedown`. Signed-off-by: Zeng Heng Reviewed-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20221012124735.1702700-1-zengheng4@huawei.com Signed-off-by: Christian König --- drivers/gpu/drm/ttm/ttm_range_manager.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/ttm/ttm_range_manager.c b/drivers/gpu/drm/ttm/ttm_range_manager.c index 4cfef2b3514d..f7c16c46cfbc 100644 --- a/drivers/gpu/drm/ttm/ttm_range_manager.c +++ b/drivers/gpu/drm/ttm/ttm_range_manager.c @@ -229,7 +229,6 @@ int ttm_range_man_fini_nocheck(struct ttm_device *bdev, return ret; spin_lock(&rman->lock); - drm_mm_clean(mm); drm_mm_takedown(mm); spin_unlock(&rman->lock); -- cgit From b3b088e28183b84080b7f0a0b8da84ec42b4b0e8 Mon Sep 17 00:00:00 2001 From: Dale B Stimson Date: Thu, 13 Oct 2022 08:45:20 -0700 Subject: drm/i915/hwmon: Add HWMON infrastructure The i915 HWMON module will be used to expose voltage, power and energy values for dGfx. Here we set up i915 hwmon infrastructure including i915 hwmon registration, basic data structures and functions. v2: - Create HWMON infra patch (Ashutosh) - Fixed review comments (Jani) - Remove "select HWMON" from i915/Kconfig (Jani) v3: Use hwm_ prefix for static functions (Ashutosh) v4: s/#ifdef CONFIG_HWMON/#if IS_REACHABLE(CONFIG_HWMON)/ since the former doesn't work if hwmon is compiled as a module (Guenter) v5: Fixed review comments (Jani) v6: s/kzalloc/devm_kzalloc/ (Andi) v7: s/hwmon_device_register_with_info/ devm_hwmon_device_register_with_info/ (Ashutosh) Cc: Guenter Roeck Signed-off-by: Dale B Stimson Signed-off-by: Ashutosh Dixit Signed-off-by: Riana Tauro Signed-off-by: Badal Nilawar Acked-by: Guenter Roeck Reviewed-by: Ashutosh Dixit Reviewed-by: Anshuman Gupta Reviewed-by: Andi Shyti Signed-off-by: Anshuman Gupta Link: https://patchwork.freedesktop.org/patch/msgid/20221013154526.2105579-2-ashutosh.dixit@intel.com --- drivers/gpu/drm/i915/Makefile | 3 + drivers/gpu/drm/i915/i915_driver.c | 5 ++ drivers/gpu/drm/i915/i915_drv.h | 2 + drivers/gpu/drm/i915/i915_hwmon.c | 122 +++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/i915_hwmon.h | 20 ++++++ 5 files changed, 152 insertions(+) create mode 100644 drivers/gpu/drm/i915/i915_hwmon.c create mode 100644 drivers/gpu/drm/i915/i915_hwmon.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index f8cc1eb52626..2535593ab379 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -209,6 +209,9 @@ i915-y += gt/uc/intel_uc.o \ # graphics system controller (GSC) support i915-y += gt/intel_gsc.o +# graphics hardware monitoring (HWMON) support +i915-$(CONFIG_HWMON) += i915_hwmon.o + # modesetting core code i915-y += \ display/hsw_ips.o \ diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c index 9d1fc2477f80..ae0414037625 100644 --- a/drivers/gpu/drm/i915/i915_driver.c +++ b/drivers/gpu/drm/i915/i915_driver.c @@ -81,6 +81,7 @@ #include "i915_drm_client.h" #include "i915_drv.h" #include "i915_getparam.h" +#include "i915_hwmon.h" #include "i915_ioc32.h" #include "i915_ioctl.h" #include "i915_irq.h" @@ -763,6 +764,8 @@ static void i915_driver_register(struct drm_i915_private *dev_priv) for_each_gt(gt, dev_priv, i) intel_gt_driver_register(gt); + i915_hwmon_register(dev_priv); + intel_display_driver_register(dev_priv); intel_power_domains_enable(dev_priv); @@ -795,6 +798,8 @@ static void i915_driver_unregister(struct drm_i915_private *dev_priv) for_each_gt(gt, dev_priv, i) intel_gt_driver_unregister(gt); + i915_hwmon_unregister(dev_priv); + i915_perf_unregister(dev_priv); i915_pmu_unregister(dev_priv); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e390da969be5..74a1a646878b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -352,6 +352,8 @@ struct drm_i915_private { struct i915_perf perf; + struct i915_hwmon *hwmon; + /* Abstract the submission mechanism (legacy ringbuffer or execlists) away */ struct intel_gt gt0; diff --git a/drivers/gpu/drm/i915/i915_hwmon.c b/drivers/gpu/drm/i915/i915_hwmon.c new file mode 100644 index 000000000000..231552fda374 --- /dev/null +++ b/drivers/gpu/drm/i915/i915_hwmon.c @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2022 Intel Corporation + */ + +#include +#include +#include + +#include "i915_drv.h" +#include "i915_hwmon.h" +#include "i915_reg.h" +#include "intel_mchbar_regs.h" + +struct hwm_reg { +}; + +struct hwm_drvdata { + struct i915_hwmon *hwmon; + struct intel_uncore *uncore; + struct device *hwmon_dev; + char name[12]; +}; + +struct i915_hwmon { + struct hwm_drvdata ddat; + struct mutex hwmon_lock; /* counter overflow logic and rmw */ + struct hwm_reg rg; +}; + +static const struct hwmon_channel_info *hwm_info[] = { + NULL +}; + +static umode_t +hwm_is_visible(const void *drvdata, enum hwmon_sensor_types type, + u32 attr, int channel) +{ + switch (type) { + default: + return 0; + } +} + +static int +hwm_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, + int channel, long *val) +{ + switch (type) { + default: + return -EOPNOTSUPP; + } +} + +static int +hwm_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, + int channel, long val) +{ + switch (type) { + default: + return -EOPNOTSUPP; + } +} + +static const struct hwmon_ops hwm_ops = { + .is_visible = hwm_is_visible, + .read = hwm_read, + .write = hwm_write, +}; + +static const struct hwmon_chip_info hwm_chip_info = { + .ops = &hwm_ops, + .info = hwm_info, +}; + +static void +hwm_get_preregistration_info(struct drm_i915_private *i915) +{ +} + +void i915_hwmon_register(struct drm_i915_private *i915) +{ + struct device *dev = i915->drm.dev; + struct i915_hwmon *hwmon; + struct device *hwmon_dev; + struct hwm_drvdata *ddat; + + /* hwmon is available only for dGfx */ + if (!IS_DGFX(i915)) + return; + + hwmon = devm_kzalloc(dev, sizeof(*hwmon), GFP_KERNEL); + if (!hwmon) + return; + + i915->hwmon = hwmon; + mutex_init(&hwmon->hwmon_lock); + ddat = &hwmon->ddat; + + ddat->hwmon = hwmon; + ddat->uncore = &i915->uncore; + snprintf(ddat->name, sizeof(ddat->name), "i915"); + + hwm_get_preregistration_info(i915); + + /* hwmon_dev points to device hwmon */ + hwmon_dev = devm_hwmon_device_register_with_info(dev, ddat->name, + ddat, + &hwm_chip_info, + NULL); + if (IS_ERR(hwmon_dev)) { + i915->hwmon = NULL; + return; + } + + ddat->hwmon_dev = hwmon_dev; +} + +void i915_hwmon_unregister(struct drm_i915_private *i915) +{ + fetch_and_zero(&i915->hwmon); +} diff --git a/drivers/gpu/drm/i915/i915_hwmon.h b/drivers/gpu/drm/i915/i915_hwmon.h new file mode 100644 index 000000000000..7ca9cf2c34c9 --- /dev/null +++ b/drivers/gpu/drm/i915/i915_hwmon.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: MIT */ + +/* + * Copyright © 2022 Intel Corporation + */ + +#ifndef __I915_HWMON_H__ +#define __I915_HWMON_H__ + +struct drm_i915_private; + +#if IS_REACHABLE(CONFIG_HWMON) +void i915_hwmon_register(struct drm_i915_private *i915); +void i915_hwmon_unregister(struct drm_i915_private *i915); +#else +static inline void i915_hwmon_register(struct drm_i915_private *i915) { }; +static inline void i915_hwmon_unregister(struct drm_i915_private *i915) { }; +#endif + +#endif /* __I915_HWMON_H__ */ -- cgit From f8572bb675250ee527d9ba35fa1ce17480407399 Mon Sep 17 00:00:00 2001 From: Riana Tauro Date: Thu, 13 Oct 2022 08:45:21 -0700 Subject: drm/i915/hwmon: Add HWMON current voltage support Use i915 HWMON subsystem to display current input voltage. v2: - Updated date and kernel version in feature description - Fixed review comments (Ashutosh) v3: Use macro HWMON_CHANNEL_INFO to define hwmon channel (Guenter) v4: - Fixed review comments (Ashutosh) - Use hwm_ prefix for static functions (Ashutosh) v5: Added unit of voltage as millivolts (Ashutosh) v6: KernelVersion: 6.2, Date: February 2023 in doc (Tvrtko) v7: Change contact to intel-gfx (Rodrigo) GEN12_RPSTAT1 is available for all Gen12+ (Andi) Added Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon to MAINTAINERS Cc: Guenter Roeck Cc: Anshuman Gupta Signed-off-by: Riana Tauro Signed-off-by: Badal Nilawar Signed-off-by: Ashutosh Dixit Acked-by: Guenter Roeck Reviewed-by: Ashutosh Dixit Reviewed-by: Anshuman Gupta Signed-off-by: Anshuman Gupta Link: https://patchwork.freedesktop.org/patch/msgid/20221013154526.2105579-3-ashutosh.dixit@intel.com --- .../ABI/testing/sysfs-driver-intel-i915-hwmon | 7 +++ MAINTAINERS | 1 + drivers/gpu/drm/i915/gt/intel_gt_regs.h | 3 ++ drivers/gpu/drm/i915/i915_hwmon.c | 53 ++++++++++++++++++++++ 4 files changed, 64 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon diff --git a/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon b/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon new file mode 100644 index 000000000000..5f4b136f0850 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon @@ -0,0 +1,7 @@ +What: /sys/devices/.../hwmon/hwmon/in0_input +Date: February 2023 +KernelVersion: 6.2 +Contact: intel-gfx@lists.freedesktop.org +Description: RO. Current Voltage in millivolt. + + Only supported for particular Intel i915 graphics platforms. diff --git a/MAINTAINERS b/MAINTAINERS index 4f2fa9925116..c03539c86e9e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10140,6 +10140,7 @@ Q: http://patchwork.freedesktop.org/project/intel-gfx/ B: https://gitlab.freedesktop.org/drm/intel/-/wikis/How-to-file-i915-bugs C: irc://irc.oftc.net/intel-gfx T: git git://anongit.freedesktop.org/drm-intel +F: Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon F: Documentation/gpu/i915.rst F: drivers/gpu/drm/i915/ F: include/drm/i915* diff --git a/drivers/gpu/drm/i915/gt/intel_gt_regs.h b/drivers/gpu/drm/i915/gt/intel_gt_regs.h index 755a2c101269..c7639ae79a8f 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_regs.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_regs.h @@ -1516,6 +1516,9 @@ #define VLV_RENDER_C0_COUNT _MMIO(0x138118) #define VLV_MEDIA_C0_COUNT _MMIO(0x13811c) +#define GEN12_RPSTAT1 _MMIO(0x1381b4) +#define GEN12_VOLTAGE_MASK REG_GENMASK(10, 0) + #define GEN11_GT_INTR_DW(x) _MMIO(0x190018 + ((x) * 4)) #define GEN11_CSME (31) #define GEN11_GUNIT (28) diff --git a/drivers/gpu/drm/i915/i915_hwmon.c b/drivers/gpu/drm/i915/i915_hwmon.c index 231552fda374..025399391ddc 100644 --- a/drivers/gpu/drm/i915/i915_hwmon.c +++ b/drivers/gpu/drm/i915/i915_hwmon.c @@ -11,8 +11,16 @@ #include "i915_hwmon.h" #include "i915_reg.h" #include "intel_mchbar_regs.h" +#include "gt/intel_gt_regs.h" + +/* + * SF_* - scale factors for particular quantities according to hwmon spec. + * - voltage - millivolts + */ +#define SF_VOLTAGE 1000 struct hwm_reg { + i915_reg_t gt_perf_status; }; struct hwm_drvdata { @@ -29,14 +37,51 @@ struct i915_hwmon { }; static const struct hwmon_channel_info *hwm_info[] = { + HWMON_CHANNEL_INFO(in, HWMON_I_INPUT), NULL }; +static umode_t +hwm_in_is_visible(const struct hwm_drvdata *ddat, u32 attr) +{ + struct drm_i915_private *i915 = ddat->uncore->i915; + + switch (attr) { + case hwmon_in_input: + return IS_DG1(i915) || IS_DG2(i915) ? 0444 : 0; + default: + return 0; + } +} + +static int +hwm_in_read(struct hwm_drvdata *ddat, u32 attr, long *val) +{ + struct i915_hwmon *hwmon = ddat->hwmon; + intel_wakeref_t wakeref; + u32 reg_value; + + switch (attr) { + case hwmon_in_input: + with_intel_runtime_pm(ddat->uncore->rpm, wakeref) + reg_value = intel_uncore_read(ddat->uncore, hwmon->rg.gt_perf_status); + /* HW register value in units of 2.5 millivolt */ + *val = DIV_ROUND_CLOSEST(REG_FIELD_GET(GEN12_VOLTAGE_MASK, reg_value) * 25, 10); + return 0; + default: + return -EOPNOTSUPP; + } +} + static umode_t hwm_is_visible(const void *drvdata, enum hwmon_sensor_types type, u32 attr, int channel) { + struct hwm_drvdata *ddat = (struct hwm_drvdata *)drvdata; + switch (type) { + case hwmon_in: + return hwm_in_is_visible(ddat, attr); default: return 0; } @@ -46,7 +91,11 @@ static int hwm_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long *val) { + struct hwm_drvdata *ddat = dev_get_drvdata(dev); + switch (type) { + case hwmon_in: + return hwm_in_read(ddat, attr, val); default: return -EOPNOTSUPP; } @@ -76,6 +125,10 @@ static const struct hwmon_chip_info hwm_chip_info = { static void hwm_get_preregistration_info(struct drm_i915_private *i915) { + struct i915_hwmon *hwmon = i915->hwmon; + + /* Available for all Gen12+/dGfx */ + hwmon->rg.gt_perf_status = GEN12_RPSTAT1; } void i915_hwmon_register(struct drm_i915_private *i915) -- cgit From 99f55efb79114f7bc38e9c769f06f5bacb5e9d21 Mon Sep 17 00:00:00 2001 From: Dale B Stimson Date: Thu, 13 Oct 2022 08:45:22 -0700 Subject: drm/i915/hwmon: Power PL1 limit and TDP setting Use i915 HWMON to display/modify dGfx power PL1 limit and TDP setting. v2: - Fix review comments (Ashutosh) - Do not restore power1_max upon module unload/load sequence because on production systems modules are always loaded and not unloaded/reloaded (Ashutosh) - Fix review comments (Jani) - Remove endianness conversion (Ashutosh) v3: Add power1_rated_max (Ashutosh) v4: - Use macro HWMON_CHANNEL_INFO to define power channel (Guenter) - Update the date and kernel version in Documentation (Badal) v5: Use hwm_ prefix for static functions (Ashutosh) v6: Fix review comments (Ashutosh) v7: - Define PCU_PACKAGE_POWER_SKU for DG1,DG2 and move PKG_PKG_TDP to intel_mchbar_regs.h (Anshuman) - KernelVersion: 6.2, Date: February 2023 in doc (Tvrtko) v8: Change contact to intel-gfx (Rodrigo) Minor change to val_sku_unit init (Andi) Cc: Guenter Roeck Signed-off-by: Dale B Stimson Signed-off-by: Ashutosh Dixit Signed-off-by: Riana Tauro Signed-off-by: Badal Nilawar Acked-by: Guenter Roeck Reviewed-by: Ashutosh Dixit Reviewed-by: Anshuman Gupta Reviewed-by: Andi Shyti Signed-off-by: Anshuman Gupta Link: https://patchwork.freedesktop.org/patch/msgid/20221013154526.2105579-4-ashutosh.dixit@intel.com --- .../ABI/testing/sysfs-driver-intel-i915-hwmon | 20 +++ drivers/gpu/drm/i915/i915_hwmon.c | 154 +++++++++++++++++++++ drivers/gpu/drm/i915/intel_mchbar_regs.h | 12 ++ 3 files changed, 186 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon b/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon index 5f4b136f0850..e0b1af4ec6d8 100644 --- a/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon +++ b/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon @@ -5,3 +5,23 @@ Contact: intel-gfx@lists.freedesktop.org Description: RO. Current Voltage in millivolt. Only supported for particular Intel i915 graphics platforms. + +What: /sys/devices/.../hwmon/hwmon/power1_max +Date: February 2023 +KernelVersion: 6.2 +Contact: intel-gfx@lists.freedesktop.org +Description: RW. Card reactive sustained (PL1/Tau) power limit in microwatts. + + The power controller will throttle the operating frequency + if the power averaged over a window (typically seconds) + exceeds this limit. + + Only supported for particular Intel i915 graphics platforms. + +What: /sys/devices/.../hwmon/hwmon/power1_rated_max +Date: February 2023 +KernelVersion: 6.2 +Contact: intel-gfx@lists.freedesktop.org +Description: RO. Card default power limit (default TDP setting). + + Only supported for particular Intel i915 graphics platforms. diff --git a/drivers/gpu/drm/i915/i915_hwmon.c b/drivers/gpu/drm/i915/i915_hwmon.c index 025399391ddc..db254413a07d 100644 --- a/drivers/gpu/drm/i915/i915_hwmon.c +++ b/drivers/gpu/drm/i915/i915_hwmon.c @@ -16,11 +16,16 @@ /* * SF_* - scale factors for particular quantities according to hwmon spec. * - voltage - millivolts + * - power - microwatts */ #define SF_VOLTAGE 1000 +#define SF_POWER 1000000 struct hwm_reg { i915_reg_t gt_perf_status; + i915_reg_t pkg_power_sku_unit; + i915_reg_t pkg_power_sku; + i915_reg_t pkg_rapl_limit; }; struct hwm_drvdata { @@ -34,10 +39,68 @@ struct i915_hwmon { struct hwm_drvdata ddat; struct mutex hwmon_lock; /* counter overflow logic and rmw */ struct hwm_reg rg; + int scl_shift_power; }; +static void +hwm_locked_with_pm_intel_uncore_rmw(struct hwm_drvdata *ddat, + i915_reg_t reg, u32 clear, u32 set) +{ + struct i915_hwmon *hwmon = ddat->hwmon; + struct intel_uncore *uncore = ddat->uncore; + intel_wakeref_t wakeref; + + mutex_lock(&hwmon->hwmon_lock); + + with_intel_runtime_pm(uncore->rpm, wakeref) + intel_uncore_rmw(uncore, reg, clear, set); + + mutex_unlock(&hwmon->hwmon_lock); +} + +/* + * This function's return type of u64 allows for the case where the scaling + * of the field taken from the 32-bit register value might cause a result to + * exceed 32 bits. + */ +static u64 +hwm_field_read_and_scale(struct hwm_drvdata *ddat, i915_reg_t rgadr, + u32 field_msk, int nshift, u32 scale_factor) +{ + struct intel_uncore *uncore = ddat->uncore; + intel_wakeref_t wakeref; + u32 reg_value; + + with_intel_runtime_pm(uncore->rpm, wakeref) + reg_value = intel_uncore_read(uncore, rgadr); + + reg_value = REG_FIELD_GET(field_msk, reg_value); + + return mul_u64_u32_shr(reg_value, scale_factor, nshift); +} + +static void +hwm_field_scale_and_write(struct hwm_drvdata *ddat, i915_reg_t rgadr, + u32 field_msk, int nshift, + unsigned int scale_factor, long lval) +{ + u32 nval; + u32 bits_to_clear; + u32 bits_to_set; + + /* Computation in 64-bits to avoid overflow. Round to nearest. */ + nval = DIV_ROUND_CLOSEST_ULL((u64)lval << nshift, scale_factor); + + bits_to_clear = field_msk; + bits_to_set = FIELD_PREP(field_msk, nval); + + hwm_locked_with_pm_intel_uncore_rmw(ddat, rgadr, + bits_to_clear, bits_to_set); +} + static const struct hwmon_channel_info *hwm_info[] = { HWMON_CHANNEL_INFO(in, HWMON_I_INPUT), + HWMON_CHANNEL_INFO(power, HWMON_P_MAX | HWMON_P_RATED_MAX), NULL }; @@ -73,6 +136,64 @@ hwm_in_read(struct hwm_drvdata *ddat, u32 attr, long *val) } } +static umode_t +hwm_power_is_visible(const struct hwm_drvdata *ddat, u32 attr, int chan) +{ + struct i915_hwmon *hwmon = ddat->hwmon; + + switch (attr) { + case hwmon_power_max: + return i915_mmio_reg_valid(hwmon->rg.pkg_rapl_limit) ? 0664 : 0; + case hwmon_power_rated_max: + return i915_mmio_reg_valid(hwmon->rg.pkg_power_sku) ? 0444 : 0; + default: + return 0; + } +} + +static int +hwm_power_read(struct hwm_drvdata *ddat, u32 attr, int chan, long *val) +{ + struct i915_hwmon *hwmon = ddat->hwmon; + + switch (attr) { + case hwmon_power_max: + *val = hwm_field_read_and_scale(ddat, + hwmon->rg.pkg_rapl_limit, + PKG_PWR_LIM_1, + hwmon->scl_shift_power, + SF_POWER); + return 0; + case hwmon_power_rated_max: + *val = hwm_field_read_and_scale(ddat, + hwmon->rg.pkg_power_sku, + PKG_PKG_TDP, + hwmon->scl_shift_power, + SF_POWER); + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int +hwm_power_write(struct hwm_drvdata *ddat, u32 attr, int chan, long val) +{ + struct i915_hwmon *hwmon = ddat->hwmon; + + switch (attr) { + case hwmon_power_max: + hwm_field_scale_and_write(ddat, + hwmon->rg.pkg_rapl_limit, + PKG_PWR_LIM_1, + hwmon->scl_shift_power, + SF_POWER, val); + return 0; + default: + return -EOPNOTSUPP; + } +} + static umode_t hwm_is_visible(const void *drvdata, enum hwmon_sensor_types type, u32 attr, int channel) @@ -82,6 +203,8 @@ hwm_is_visible(const void *drvdata, enum hwmon_sensor_types type, switch (type) { case hwmon_in: return hwm_in_is_visible(ddat, attr); + case hwmon_power: + return hwm_power_is_visible(ddat, attr, channel); default: return 0; } @@ -96,6 +219,8 @@ hwm_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, switch (type) { case hwmon_in: return hwm_in_read(ddat, attr, val); + case hwmon_power: + return hwm_power_read(ddat, attr, channel, val); default: return -EOPNOTSUPP; } @@ -105,7 +230,11 @@ static int hwm_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long val) { + struct hwm_drvdata *ddat = dev_get_drvdata(dev); + switch (type) { + case hwmon_power: + return hwm_power_write(ddat, attr, channel, val); default: return -EOPNOTSUPP; } @@ -126,9 +255,34 @@ static void hwm_get_preregistration_info(struct drm_i915_private *i915) { struct i915_hwmon *hwmon = i915->hwmon; + struct intel_uncore *uncore = &i915->uncore; + intel_wakeref_t wakeref; + u32 val_sku_unit = 0; /* Available for all Gen12+/dGfx */ hwmon->rg.gt_perf_status = GEN12_RPSTAT1; + + if (IS_DG1(i915) || IS_DG2(i915)) { + hwmon->rg.pkg_power_sku_unit = PCU_PACKAGE_POWER_SKU_UNIT; + hwmon->rg.pkg_power_sku = PCU_PACKAGE_POWER_SKU; + hwmon->rg.pkg_rapl_limit = PCU_PACKAGE_RAPL_LIMIT; + } else { + hwmon->rg.pkg_power_sku_unit = INVALID_MMIO_REG; + hwmon->rg.pkg_power_sku = INVALID_MMIO_REG; + hwmon->rg.pkg_rapl_limit = INVALID_MMIO_REG; + } + + with_intel_runtime_pm(uncore->rpm, wakeref) { + /* + * The contents of register hwmon->rg.pkg_power_sku_unit do not change, + * so read it once and store the shift values. + */ + if (i915_mmio_reg_valid(hwmon->rg.pkg_power_sku_unit)) + val_sku_unit = intel_uncore_read(uncore, + hwmon->rg.pkg_power_sku_unit); + + hwmon->scl_shift_power = REG_FIELD_GET(PKG_PWR_UNIT, val_sku_unit); + } } void i915_hwmon_register(struct drm_i915_private *i915) diff --git a/drivers/gpu/drm/i915/intel_mchbar_regs.h b/drivers/gpu/drm/i915/intel_mchbar_regs.h index ffc702b79579..d7e2e4711792 100644 --- a/drivers/gpu/drm/i915/intel_mchbar_regs.h +++ b/drivers/gpu/drm/i915/intel_mchbar_regs.h @@ -189,6 +189,16 @@ #define DG1_QCLK_RATIO_MASK REG_GENMASK(9, 2) #define DG1_QCLK_REFERENCE REG_BIT(10) +/* + * *_PACKAGE_POWER_SKU - SKU power and timing parameters. + */ +#define PCU_PACKAGE_POWER_SKU _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5930) +#define PKG_PKG_TDP GENMASK_ULL(14, 0) + +#define PCU_PACKAGE_POWER_SKU_UNIT _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5938) +#define PKG_PWR_UNIT REG_GENMASK(3, 0) +#define PKG_TIME_UNIT REG_GENMASK(19, 16) + #define GEN6_GT_PERF_STATUS _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5948) #define GEN6_RP_STATE_LIMITS _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5994) #define GEN6_RP_STATE_CAP _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5998) @@ -198,6 +208,8 @@ #define GEN10_FREQ_INFO_REC _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5ef0) #define RPE_MASK REG_GENMASK(15, 8) +#define PCU_PACKAGE_RAPL_LIMIT _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x59a0) +#define PKG_PWR_LIM_1 REG_GENMASK(14, 0) /* snb MCH registers for priority tuning */ #define MCH_SSKPD _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5d10) -- cgit From c41b8bdcc2973ca10c6f5c5c60d007a41f080a89 Mon Sep 17 00:00:00 2001 From: Dale B Stimson Date: Thu, 13 Oct 2022 08:45:23 -0700 Subject: drm/i915/hwmon: Show device level energy usage Use i915 HWMON to display device level energy input. v2: Updated the date and kernel version in feature description v3: - Cleaned up hwm_energy function and removed unused function i915_hwmon_energy_status_get (Ashutosh) v4: KernelVersion: 6.2, Date: February 2023 in doc (Tvrtko) v5: Change contact to intel-gfx (Rodrigo) Change return type of hwm_energy to void (Andi) Signed-off-by: Dale B Stimson Signed-off-by: Ashutosh Dixit Signed-off-by: Riana Tauro Signed-off-by: Badal Nilawar Acked-by: Guenter Roeck Reviewed-by: Ashutosh Dixit Reviewed-by: Anshuman Gupta Signed-off-by: Anshuman Gupta Link: https://patchwork.freedesktop.org/patch/msgid/20221013154526.2105579-5-ashutosh.dixit@intel.com --- .../ABI/testing/sysfs-driver-intel-i915-hwmon | 8 ++ drivers/gpu/drm/i915/i915_hwmon.c | 106 ++++++++++++++++++++- drivers/gpu/drm/i915/intel_mchbar_regs.h | 2 + 3 files changed, 114 insertions(+), 2 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon b/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon index e0b1af4ec6d8..aa00c558495b 100644 --- a/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon +++ b/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon @@ -25,3 +25,11 @@ Contact: intel-gfx@lists.freedesktop.org Description: RO. Card default power limit (default TDP setting). Only supported for particular Intel i915 graphics platforms. + +What: /sys/devices/.../hwmon/hwmon/energy1_input +Date: February 2023 +KernelVersion: 6.2 +Contact: intel-gfx@lists.freedesktop.org +Description: RO. Energy input of device in microjoules. + + Only supported for particular Intel i915 graphics platforms. diff --git a/drivers/gpu/drm/i915/i915_hwmon.c b/drivers/gpu/drm/i915/i915_hwmon.c index db254413a07d..d8d30daa3794 100644 --- a/drivers/gpu/drm/i915/i915_hwmon.c +++ b/drivers/gpu/drm/i915/i915_hwmon.c @@ -17,21 +17,30 @@ * SF_* - scale factors for particular quantities according to hwmon spec. * - voltage - millivolts * - power - microwatts + * - energy - microjoules */ #define SF_VOLTAGE 1000 #define SF_POWER 1000000 +#define SF_ENERGY 1000000 struct hwm_reg { i915_reg_t gt_perf_status; i915_reg_t pkg_power_sku_unit; i915_reg_t pkg_power_sku; i915_reg_t pkg_rapl_limit; + i915_reg_t energy_status_all; +}; + +struct hwm_energy_info { + u32 reg_val_prev; + long accum_energy; /* Accumulated energy for energy1_input */ }; struct hwm_drvdata { struct i915_hwmon *hwmon; struct intel_uncore *uncore; struct device *hwmon_dev; + struct hwm_energy_info ei; /* Energy info for energy1_input */ char name[12]; }; @@ -40,6 +49,7 @@ struct i915_hwmon { struct mutex hwmon_lock; /* counter overflow logic and rmw */ struct hwm_reg rg; int scl_shift_power; + int scl_shift_energy; }; static void @@ -98,9 +108,58 @@ hwm_field_scale_and_write(struct hwm_drvdata *ddat, i915_reg_t rgadr, bits_to_clear, bits_to_set); } +/* + * hwm_energy - Obtain energy value + * + * The underlying energy hardware register is 32-bits and is subject to + * overflow. How long before overflow? For example, with an example + * scaling bit shift of 14 bits (see register *PACKAGE_POWER_SKU_UNIT) and + * a power draw of 1000 watts, the 32-bit counter will overflow in + * approximately 4.36 minutes. + * + * Examples: + * 1 watt: (2^32 >> 14) / 1 W / (60 * 60 * 24) secs/day -> 3 days + * 1000 watts: (2^32 >> 14) / 1000 W / 60 secs/min -> 4.36 minutes + * + * The function significantly increases overflow duration (from 4.36 + * minutes) by accumulating the energy register into a 'long' as allowed by + * the hwmon API. Using x86_64 128 bit arithmetic (see mul_u64_u32_shr()), + * a 'long' of 63 bits, SF_ENERGY of 1e6 (~20 bits) and + * hwmon->scl_shift_energy of 14 bits we have 57 (63 - 20 + 14) bits before + * energy1_input overflows. This at 1000 W is an overflow duration of 278 years. + */ +static void +hwm_energy(struct hwm_drvdata *ddat, long *energy) +{ + struct intel_uncore *uncore = ddat->uncore; + struct i915_hwmon *hwmon = ddat->hwmon; + struct hwm_energy_info *ei = &ddat->ei; + intel_wakeref_t wakeref; + i915_reg_t rgaddr; + u32 reg_val; + + rgaddr = hwmon->rg.energy_status_all; + + mutex_lock(&hwmon->hwmon_lock); + + with_intel_runtime_pm(uncore->rpm, wakeref) + reg_val = intel_uncore_read(uncore, rgaddr); + + if (reg_val >= ei->reg_val_prev) + ei->accum_energy += reg_val - ei->reg_val_prev; + else + ei->accum_energy += UINT_MAX - ei->reg_val_prev + reg_val; + ei->reg_val_prev = reg_val; + + *energy = mul_u64_u32_shr(ei->accum_energy, SF_ENERGY, + hwmon->scl_shift_energy); + mutex_unlock(&hwmon->hwmon_lock); +} + static const struct hwmon_channel_info *hwm_info[] = { HWMON_CHANNEL_INFO(in, HWMON_I_INPUT), HWMON_CHANNEL_INFO(power, HWMON_P_MAX | HWMON_P_RATED_MAX), + HWMON_CHANNEL_INFO(energy, HWMON_E_INPUT), NULL }; @@ -194,6 +253,33 @@ hwm_power_write(struct hwm_drvdata *ddat, u32 attr, int chan, long val) } } +static umode_t +hwm_energy_is_visible(const struct hwm_drvdata *ddat, u32 attr) +{ + struct i915_hwmon *hwmon = ddat->hwmon; + i915_reg_t rgaddr; + + switch (attr) { + case hwmon_energy_input: + rgaddr = hwmon->rg.energy_status_all; + return i915_mmio_reg_valid(rgaddr) ? 0444 : 0; + default: + return 0; + } +} + +static int +hwm_energy_read(struct hwm_drvdata *ddat, u32 attr, long *val) +{ + switch (attr) { + case hwmon_energy_input: + hwm_energy(ddat, val); + return 0; + default: + return -EOPNOTSUPP; + } +} + static umode_t hwm_is_visible(const void *drvdata, enum hwmon_sensor_types type, u32 attr, int channel) @@ -205,6 +291,8 @@ hwm_is_visible(const void *drvdata, enum hwmon_sensor_types type, return hwm_in_is_visible(ddat, attr); case hwmon_power: return hwm_power_is_visible(ddat, attr, channel); + case hwmon_energy: + return hwm_energy_is_visible(ddat, attr); default: return 0; } @@ -221,6 +309,8 @@ hwm_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, return hwm_in_read(ddat, attr, val); case hwmon_power: return hwm_power_read(ddat, attr, channel, val); + case hwmon_energy: + return hwm_energy_read(ddat, attr, val); default: return -EOPNOTSUPP; } @@ -256,8 +346,10 @@ hwm_get_preregistration_info(struct drm_i915_private *i915) { struct i915_hwmon *hwmon = i915->hwmon; struct intel_uncore *uncore = &i915->uncore; + struct hwm_drvdata *ddat = &hwmon->ddat; intel_wakeref_t wakeref; u32 val_sku_unit = 0; + long energy; /* Available for all Gen12+/dGfx */ hwmon->rg.gt_perf_status = GEN12_RPSTAT1; @@ -266,10 +358,12 @@ hwm_get_preregistration_info(struct drm_i915_private *i915) hwmon->rg.pkg_power_sku_unit = PCU_PACKAGE_POWER_SKU_UNIT; hwmon->rg.pkg_power_sku = PCU_PACKAGE_POWER_SKU; hwmon->rg.pkg_rapl_limit = PCU_PACKAGE_RAPL_LIMIT; + hwmon->rg.energy_status_all = PCU_PACKAGE_ENERGY_STATUS; } else { hwmon->rg.pkg_power_sku_unit = INVALID_MMIO_REG; hwmon->rg.pkg_power_sku = INVALID_MMIO_REG; hwmon->rg.pkg_rapl_limit = INVALID_MMIO_REG; + hwmon->rg.energy_status_all = INVALID_MMIO_REG; } with_intel_runtime_pm(uncore->rpm, wakeref) { @@ -280,9 +374,17 @@ hwm_get_preregistration_info(struct drm_i915_private *i915) if (i915_mmio_reg_valid(hwmon->rg.pkg_power_sku_unit)) val_sku_unit = intel_uncore_read(uncore, hwmon->rg.pkg_power_sku_unit); - - hwmon->scl_shift_power = REG_FIELD_GET(PKG_PWR_UNIT, val_sku_unit); } + + hwmon->scl_shift_power = REG_FIELD_GET(PKG_PWR_UNIT, val_sku_unit); + hwmon->scl_shift_energy = REG_FIELD_GET(PKG_ENERGY_UNIT, val_sku_unit); + + /* + * Initialize 'struct hwm_energy_info', i.e. set fields to the + * first value of the energy register read + */ + if (i915_mmio_reg_valid(hwmon->rg.energy_status_all)) + hwm_energy(ddat, &energy); } void i915_hwmon_register(struct drm_i915_private *i915) diff --git a/drivers/gpu/drm/i915/intel_mchbar_regs.h b/drivers/gpu/drm/i915/intel_mchbar_regs.h index d7e2e4711792..decd411c2cdd 100644 --- a/drivers/gpu/drm/i915/intel_mchbar_regs.h +++ b/drivers/gpu/drm/i915/intel_mchbar_regs.h @@ -197,7 +197,9 @@ #define PCU_PACKAGE_POWER_SKU_UNIT _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5938) #define PKG_PWR_UNIT REG_GENMASK(3, 0) +#define PKG_ENERGY_UNIT REG_GENMASK(12, 8) #define PKG_TIME_UNIT REG_GENMASK(19, 16) +#define PCU_PACKAGE_ENERGY_STATUS _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x593c) #define GEN6_GT_PERF_STATUS _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5948) #define GEN6_RP_STATE_LIMITS _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5994) -- cgit From c8939848f7e4b01fe37295529f8b94e93ffbdd16 Mon Sep 17 00:00:00 2001 From: Ashutosh Dixit Date: Thu, 13 Oct 2022 08:45:24 -0700 Subject: drm/i915/hwmon: Expose card reactive critical power Expose the card reactive critical (I1) power. I1 is exposed as power1_crit in microwatts (typically for client products) or as curr1_crit in milliamperes (typically for server). v2: Add curr1_crit functionality (Ashutosh) v3: Use HWMON_CHANNEL_INFO to define power1_crit, curr1_crit (Badal) v4: Use hwm_ prefix for static functions (Ashutosh) v5: KernelVersion: 6.2, Date: February 2023 in doc (Tvrtko) v6: Change contact to intel-gfx (Rodrigo) Cc: Sujaritha Sundaresan Signed-off-by: Ashutosh Dixit Signed-off-by: Badal Nilawar Acked-by: Guenter Roeck Reviewed-by: Anshuman Gupta Signed-off-by: Anshuman Gupta Link: https://patchwork.freedesktop.org/patch/msgid/20221013154526.2105579-6-ashutosh.dixit@intel.com --- .../ABI/testing/sysfs-driver-intel-i915-hwmon | 26 ++++++ drivers/gpu/drm/i915/i915_hwmon.c | 95 +++++++++++++++++++++- drivers/gpu/drm/i915/i915_reg.h | 6 ++ 3 files changed, 126 insertions(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon b/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon index aa00c558495b..a7a6512fcc8c 100644 --- a/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon +++ b/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon @@ -26,6 +26,32 @@ Description: RO. Card default power limit (default TDP setting). Only supported for particular Intel i915 graphics platforms. +What: /sys/devices/.../hwmon/hwmon/power1_crit +Date: February 2023 +KernelVersion: 6.2 +Contact: intel-gfx@lists.freedesktop.org +Description: RW. Card reactive critical (I1) power limit in microwatts. + + Card reactive critical (I1) power limit in microwatts is exposed + for client products. The power controller will throttle the + operating frequency if the power averaged over a window exceeds + this limit. + + Only supported for particular Intel i915 graphics platforms. + +What: /sys/devices/.../hwmon/hwmon/curr1_crit +Date: February 2023 +KernelVersion: 6.2 +Contact: intel-gfx@lists.freedesktop.org +Description: RW. Card reactive critical (I1) power limit in milliamperes. + + Card reactive critical (I1) power limit in milliamperes is + exposed for server products. The power controller will throttle + the operating frequency if the power averaged over a window + exceeds this limit. + + Only supported for particular Intel i915 graphics platforms. + What: /sys/devices/.../hwmon/hwmon/energy1_input Date: February 2023 KernelVersion: 6.2 diff --git a/drivers/gpu/drm/i915/i915_hwmon.c b/drivers/gpu/drm/i915/i915_hwmon.c index d8d30daa3794..2b24a7a71140 100644 --- a/drivers/gpu/drm/i915/i915_hwmon.c +++ b/drivers/gpu/drm/i915/i915_hwmon.c @@ -11,16 +11,19 @@ #include "i915_hwmon.h" #include "i915_reg.h" #include "intel_mchbar_regs.h" +#include "intel_pcode.h" #include "gt/intel_gt_regs.h" /* * SF_* - scale factors for particular quantities according to hwmon spec. * - voltage - millivolts * - power - microwatts + * - curr - milliamperes * - energy - microjoules */ #define SF_VOLTAGE 1000 #define SF_POWER 1000000 +#define SF_CURR 1000 #define SF_ENERGY 1000000 struct hwm_reg { @@ -158,11 +161,25 @@ hwm_energy(struct hwm_drvdata *ddat, long *energy) static const struct hwmon_channel_info *hwm_info[] = { HWMON_CHANNEL_INFO(in, HWMON_I_INPUT), - HWMON_CHANNEL_INFO(power, HWMON_P_MAX | HWMON_P_RATED_MAX), + HWMON_CHANNEL_INFO(power, HWMON_P_MAX | HWMON_P_RATED_MAX | HWMON_P_CRIT), HWMON_CHANNEL_INFO(energy, HWMON_E_INPUT), + HWMON_CHANNEL_INFO(curr, HWMON_C_CRIT), NULL }; +/* I1 is exposed as power_crit or as curr_crit depending on bit 31 */ +static int hwm_pcode_read_i1(struct drm_i915_private *i915, u32 *uval) +{ + return snb_pcode_read_p(&i915->uncore, PCODE_POWER_SETUP, + POWER_SETUP_SUBCOMMAND_READ_I1, 0, uval); +} + +static int hwm_pcode_write_i1(struct drm_i915_private *i915, u32 uval) +{ + return snb_pcode_write_p(&i915->uncore, PCODE_POWER_SETUP, + POWER_SETUP_SUBCOMMAND_WRITE_I1, 0, uval); +} + static umode_t hwm_in_is_visible(const struct hwm_drvdata *ddat, u32 attr) { @@ -198,13 +215,18 @@ hwm_in_read(struct hwm_drvdata *ddat, u32 attr, long *val) static umode_t hwm_power_is_visible(const struct hwm_drvdata *ddat, u32 attr, int chan) { + struct drm_i915_private *i915 = ddat->uncore->i915; struct i915_hwmon *hwmon = ddat->hwmon; + u32 uval; switch (attr) { case hwmon_power_max: return i915_mmio_reg_valid(hwmon->rg.pkg_rapl_limit) ? 0664 : 0; case hwmon_power_rated_max: return i915_mmio_reg_valid(hwmon->rg.pkg_power_sku) ? 0444 : 0; + case hwmon_power_crit: + return (hwm_pcode_read_i1(i915, &uval) || + !(uval & POWER_SETUP_I1_WATTS)) ? 0 : 0644; default: return 0; } @@ -214,6 +236,8 @@ static int hwm_power_read(struct hwm_drvdata *ddat, u32 attr, int chan, long *val) { struct i915_hwmon *hwmon = ddat->hwmon; + int ret; + u32 uval; switch (attr) { case hwmon_power_max: @@ -230,6 +254,15 @@ hwm_power_read(struct hwm_drvdata *ddat, u32 attr, int chan, long *val) hwmon->scl_shift_power, SF_POWER); return 0; + case hwmon_power_crit: + ret = hwm_pcode_read_i1(ddat->uncore->i915, &uval); + if (ret) + return ret; + if (!(uval & POWER_SETUP_I1_WATTS)) + return -ENODEV; + *val = mul_u64_u32_shr(REG_FIELD_GET(POWER_SETUP_I1_DATA_MASK, uval), + SF_POWER, POWER_SETUP_I1_SHIFT); + return 0; default: return -EOPNOTSUPP; } @@ -239,6 +272,7 @@ static int hwm_power_write(struct hwm_drvdata *ddat, u32 attr, int chan, long val) { struct i915_hwmon *hwmon = ddat->hwmon; + u32 uval; switch (attr) { case hwmon_power_max: @@ -248,6 +282,9 @@ hwm_power_write(struct hwm_drvdata *ddat, u32 attr, int chan, long val) hwmon->scl_shift_power, SF_POWER, val); return 0; + case hwmon_power_crit: + uval = DIV_ROUND_CLOSEST_ULL(val << POWER_SETUP_I1_SHIFT, SF_POWER); + return hwm_pcode_write_i1(ddat->uncore->i915, uval); default: return -EOPNOTSUPP; } @@ -280,6 +317,56 @@ hwm_energy_read(struct hwm_drvdata *ddat, u32 attr, long *val) } } +static umode_t +hwm_curr_is_visible(const struct hwm_drvdata *ddat, u32 attr) +{ + struct drm_i915_private *i915 = ddat->uncore->i915; + u32 uval; + + switch (attr) { + case hwmon_curr_crit: + return (hwm_pcode_read_i1(i915, &uval) || + (uval & POWER_SETUP_I1_WATTS)) ? 0 : 0644; + default: + return 0; + } +} + +static int +hwm_curr_read(struct hwm_drvdata *ddat, u32 attr, long *val) +{ + int ret; + u32 uval; + + switch (attr) { + case hwmon_curr_crit: + ret = hwm_pcode_read_i1(ddat->uncore->i915, &uval); + if (ret) + return ret; + if (uval & POWER_SETUP_I1_WATTS) + return -ENODEV; + *val = mul_u64_u32_shr(REG_FIELD_GET(POWER_SETUP_I1_DATA_MASK, uval), + SF_CURR, POWER_SETUP_I1_SHIFT); + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int +hwm_curr_write(struct hwm_drvdata *ddat, u32 attr, long val) +{ + u32 uval; + + switch (attr) { + case hwmon_curr_crit: + uval = DIV_ROUND_CLOSEST_ULL(val << POWER_SETUP_I1_SHIFT, SF_CURR); + return hwm_pcode_write_i1(ddat->uncore->i915, uval); + default: + return -EOPNOTSUPP; + } +} + static umode_t hwm_is_visible(const void *drvdata, enum hwmon_sensor_types type, u32 attr, int channel) @@ -293,6 +380,8 @@ hwm_is_visible(const void *drvdata, enum hwmon_sensor_types type, return hwm_power_is_visible(ddat, attr, channel); case hwmon_energy: return hwm_energy_is_visible(ddat, attr); + case hwmon_curr: + return hwm_curr_is_visible(ddat, attr); default: return 0; } @@ -311,6 +400,8 @@ hwm_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, return hwm_power_read(ddat, attr, channel, val); case hwmon_energy: return hwm_energy_read(ddat, attr, val); + case hwmon_curr: + return hwm_curr_read(ddat, attr, val); default: return -EOPNOTSUPP; } @@ -325,6 +416,8 @@ hwm_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, switch (type) { case hwmon_power: return hwm_power_write(ddat, attr, channel, val); + case hwmon_curr: + return hwm_curr_write(ddat, attr, val); default: return -EOPNOTSUPP; } diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index fc7b0968f423..ab0823e9e6c7 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6650,6 +6650,12 @@ #define DG1_PCODE_STATUS 0x7E #define DG1_UNCORE_GET_INIT_STATUS 0x0 #define DG1_UNCORE_INIT_STATUS_COMPLETE 0x1 +#define PCODE_POWER_SETUP 0x7C +#define POWER_SETUP_SUBCOMMAND_READ_I1 0x4 +#define POWER_SETUP_SUBCOMMAND_WRITE_I1 0x5 +#define POWER_SETUP_I1_WATTS REG_BIT(31) +#define POWER_SETUP_I1_SHIFT 6 /* 10.6 fixed point format */ +#define POWER_SETUP_I1_DATA_MASK REG_GENMASK(15, 0) #define GEN12_PCODE_READ_SAGV_BLOCK_TIME_US 0x23 #define XEHP_PCODE_FREQUENCY_CONFIG 0x6e /* xehpsdv, pvc */ /* XEHP_PCODE_FREQUENCY_CONFIG sub-commands (param1) */ -- cgit From 4c2572fe0ae742c2fa25b6fbb06ef4b3cd08b454 Mon Sep 17 00:00:00 2001 From: Ashutosh Dixit Date: Thu, 13 Oct 2022 08:45:25 -0700 Subject: drm/i915/hwmon: Expose power1_max_interval Expose power1_max_interval, that is the tau corresponding to PL1, as a custom hwmon attribute. Some bit manipulation is needed because of the format of PKG_PWR_LIM_1_TIME in GT0_PACKAGE_RAPL_LIMIT register (1.x * power(2,y)). v2: Update date and kernel version in Documentation (Badal) v3: Cleaned up hwm_power1_max_interval_store() (Badal) v4: - Fixed review comments (Anshuman) - In hwm_power1_max_interval_store() get PKG_MAX_WIN from pkg_power_sku when it is valid (Ashutosh) - KernelVersion: 6.2, Date: February 2023 in doc (Tvrtko) v5: On some of the DGFX setups it is seen that although pkg_power_sku is valid the field PKG_WIN_MAX is not populated. So it is decided to stick to default value of PKG_WIN_MAX (Ashutosh) v6: Change contact to intel-gfx (Rodrigo) Fixed variable types in hwm_power1_max_interval_store (Andi) Documented PKG_MAX_WIN_DEFAULT (Andi) Removed else in hwm_attributes_visible (Andi) Signed-off-by: Ashutosh Dixit Signed-off-by: Badal Nilawar Acked-by: Guenter Roeck Reviewed-by: Anshuman Gupta Signed-off-by: Anshuman Gupta Link: https://patchwork.freedesktop.org/patch/msgid/20221013154526.2105579-7-ashutosh.dixit@intel.com --- .../ABI/testing/sysfs-driver-intel-i915-hwmon | 9 ++ drivers/gpu/drm/i915/i915_hwmon.c | 119 ++++++++++++++++++++- drivers/gpu/drm/i915/intel_mchbar_regs.h | 7 ++ 3 files changed, 134 insertions(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon b/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon index a7a6512fcc8c..9dc5ff14107b 100644 --- a/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon +++ b/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon @@ -26,6 +26,15 @@ Description: RO. Card default power limit (default TDP setting). Only supported for particular Intel i915 graphics platforms. +What: /sys/devices/.../hwmon/hwmon/power1_max_interval +Date: February 2023 +KernelVersion: 6.2 +Contact: intel-gfx@lists.freedesktop.org +Description: RW. Sustained power limit interval (Tau in PL1/Tau) in + milliseconds over which sustained power is averaged. + + Only supported for particular Intel i915 graphics platforms. + What: /sys/devices/.../hwmon/hwmon/power1_crit Date: February 2023 KernelVersion: 6.2 diff --git a/drivers/gpu/drm/i915/i915_hwmon.c b/drivers/gpu/drm/i915/i915_hwmon.c index 2b24a7a71140..58f80380e542 100644 --- a/drivers/gpu/drm/i915/i915_hwmon.c +++ b/drivers/gpu/drm/i915/i915_hwmon.c @@ -20,11 +20,13 @@ * - power - microwatts * - curr - milliamperes * - energy - microjoules + * - time - milliseconds */ #define SF_VOLTAGE 1000 #define SF_POWER 1000000 #define SF_CURR 1000 #define SF_ENERGY 1000000 +#define SF_TIME 1000 struct hwm_reg { i915_reg_t gt_perf_status; @@ -53,6 +55,7 @@ struct i915_hwmon { struct hwm_reg rg; int scl_shift_power; int scl_shift_energy; + int scl_shift_time; }; static void @@ -159,6 +162,119 @@ hwm_energy(struct hwm_drvdata *ddat, long *energy) mutex_unlock(&hwmon->hwmon_lock); } +static ssize_t +hwm_power1_max_interval_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct hwm_drvdata *ddat = dev_get_drvdata(dev); + struct i915_hwmon *hwmon = ddat->hwmon; + intel_wakeref_t wakeref; + u32 r, x, y, x_w = 2; /* 2 bits */ + u64 tau4, out; + + with_intel_runtime_pm(ddat->uncore->rpm, wakeref) + r = intel_uncore_read(ddat->uncore, hwmon->rg.pkg_rapl_limit); + + x = REG_FIELD_GET(PKG_PWR_LIM_1_TIME_X, r); + y = REG_FIELD_GET(PKG_PWR_LIM_1_TIME_Y, r); + /* + * tau = 1.x * power(2,y), x = bits(23:22), y = bits(21:17) + * = (4 | x) << (y - 2) + * where (y - 2) ensures a 1.x fixed point representation of 1.x + * However because y can be < 2, we compute + * tau4 = (4 | x) << y + * but add 2 when doing the final right shift to account for units + */ + tau4 = ((1 << x_w) | x) << y; + /* val in hwmon interface units (millisec) */ + out = mul_u64_u32_shr(tau4, SF_TIME, hwmon->scl_shift_time + x_w); + + return sysfs_emit(buf, "%llu\n", out); +} + +static ssize_t +hwm_power1_max_interval_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct hwm_drvdata *ddat = dev_get_drvdata(dev); + struct i915_hwmon *hwmon = ddat->hwmon; + u32 x, y, rxy, x_w = 2; /* 2 bits */ + u64 tau4, r, max_win; + unsigned long val; + int ret; + + ret = kstrtoul(buf, 0, &val); + if (ret) + return ret; + + /* + * Max HW supported tau in '1.x * power(2,y)' format, x = 0, y = 0x12 + * The hwmon->scl_shift_time default of 0xa results in a max tau of 256 seconds + */ +#define PKG_MAX_WIN_DEFAULT 0x12ull + + /* + * val must be < max in hwmon interface units. The steps below are + * explained in i915_power1_max_interval_show() + */ + r = FIELD_PREP(PKG_MAX_WIN, PKG_MAX_WIN_DEFAULT); + x = REG_FIELD_GET(PKG_MAX_WIN_X, r); + y = REG_FIELD_GET(PKG_MAX_WIN_Y, r); + tau4 = ((1 << x_w) | x) << y; + max_win = mul_u64_u32_shr(tau4, SF_TIME, hwmon->scl_shift_time + x_w); + + if (val > max_win) + return -EINVAL; + + /* val in hw units */ + val = DIV_ROUND_CLOSEST_ULL((u64)val << hwmon->scl_shift_time, SF_TIME); + /* Convert to 1.x * power(2,y) */ + if (!val) + return -EINVAL; + y = ilog2(val); + /* x = (val - (1 << y)) >> (y - 2); */ + x = (val - (1ul << y)) << x_w >> y; + + rxy = REG_FIELD_PREP(PKG_PWR_LIM_1_TIME_X, x) | REG_FIELD_PREP(PKG_PWR_LIM_1_TIME_Y, y); + + hwm_locked_with_pm_intel_uncore_rmw(ddat, hwmon->rg.pkg_rapl_limit, + PKG_PWR_LIM_1_TIME, rxy); + return count; +} + +static SENSOR_DEVICE_ATTR(power1_max_interval, 0664, + hwm_power1_max_interval_show, + hwm_power1_max_interval_store, 0); + +static struct attribute *hwm_attributes[] = { + &sensor_dev_attr_power1_max_interval.dev_attr.attr, + NULL +}; + +static umode_t hwm_attributes_visible(struct kobject *kobj, + struct attribute *attr, int index) +{ + struct device *dev = kobj_to_dev(kobj); + struct hwm_drvdata *ddat = dev_get_drvdata(dev); + struct i915_hwmon *hwmon = ddat->hwmon; + + if (attr == &sensor_dev_attr_power1_max_interval.dev_attr.attr) + return i915_mmio_reg_valid(hwmon->rg.pkg_rapl_limit) ? attr->mode : 0; + + return 0; +} + +static const struct attribute_group hwm_attrgroup = { + .attrs = hwm_attributes, + .is_visible = hwm_attributes_visible, +}; + +static const struct attribute_group *hwm_groups[] = { + &hwm_attrgroup, + NULL +}; + static const struct hwmon_channel_info *hwm_info[] = { HWMON_CHANNEL_INFO(in, HWMON_I_INPUT), HWMON_CHANNEL_INFO(power, HWMON_P_MAX | HWMON_P_RATED_MAX | HWMON_P_CRIT), @@ -471,6 +587,7 @@ hwm_get_preregistration_info(struct drm_i915_private *i915) hwmon->scl_shift_power = REG_FIELD_GET(PKG_PWR_UNIT, val_sku_unit); hwmon->scl_shift_energy = REG_FIELD_GET(PKG_ENERGY_UNIT, val_sku_unit); + hwmon->scl_shift_time = REG_FIELD_GET(PKG_TIME_UNIT, val_sku_unit); /* * Initialize 'struct hwm_energy_info', i.e. set fields to the @@ -509,7 +626,7 @@ void i915_hwmon_register(struct drm_i915_private *i915) hwmon_dev = devm_hwmon_device_register_with_info(dev, ddat->name, ddat, &hwm_chip_info, - NULL); + hwm_groups); if (IS_ERR(hwmon_dev)) { i915->hwmon = NULL; return; diff --git a/drivers/gpu/drm/i915/intel_mchbar_regs.h b/drivers/gpu/drm/i915/intel_mchbar_regs.h index decd411c2cdd..f93e9af43ac3 100644 --- a/drivers/gpu/drm/i915/intel_mchbar_regs.h +++ b/drivers/gpu/drm/i915/intel_mchbar_regs.h @@ -194,6 +194,9 @@ */ #define PCU_PACKAGE_POWER_SKU _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5930) #define PKG_PKG_TDP GENMASK_ULL(14, 0) +#define PKG_MAX_WIN GENMASK_ULL(54, 48) +#define PKG_MAX_WIN_X GENMASK_ULL(54, 53) +#define PKG_MAX_WIN_Y GENMASK_ULL(52, 48) #define PCU_PACKAGE_POWER_SKU_UNIT _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5938) #define PKG_PWR_UNIT REG_GENMASK(3, 0) @@ -212,6 +215,10 @@ #define RPE_MASK REG_GENMASK(15, 8) #define PCU_PACKAGE_RAPL_LIMIT _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x59a0) #define PKG_PWR_LIM_1 REG_GENMASK(14, 0) +#define PKG_PWR_LIM_1_EN REG_BIT(15) +#define PKG_PWR_LIM_1_TIME REG_GENMASK(23, 17) +#define PKG_PWR_LIM_1_TIME_X REG_GENMASK(23, 22) +#define PKG_PWR_LIM_1_TIME_Y REG_GENMASK(21, 17) /* snb MCH registers for priority tuning */ #define MCH_SSKPD _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5d10) -- cgit From a6a924abf865d232f93d317f054be263c86f903c Mon Sep 17 00:00:00 2001 From: Dale B Stimson Date: Thu, 13 Oct 2022 08:45:26 -0700 Subject: drm/i915/hwmon: Extend power/energy for XEHPSDV Extend hwmon power/energy for XEHPSDV especially per gt level energy usage. v2: Update to latest HWMON spec (Ashutosh) v3: Fix review comments (Ashutosh) v4: Fix review comments (Anshuman) v5: s/hwmon_device_register_with_info/ devm_hwmon_device_register_with_info/ (Ashutosh) v6: Change contact to intel-gfx (Rodrigo) GEN12_RPSTAT1 is available for all Gen12+ (Andi) Signed-off-by: Ashutosh Dixit Signed-off-by: Dale B Stimson Signed-off-by: Badal Nilawar Acked-by: Guenter Roeck Reviewed-by: Ashutosh Dixit Reviewed-by: Anshuman Gupta Reviewed-by: Andi Shyti Signed-off-by: Anshuman Gupta Link: https://patchwork.freedesktop.org/patch/msgid/20221013154526.2105579-8-ashutosh.dixit@intel.com --- .../ABI/testing/sysfs-driver-intel-i915-hwmon | 7 +- drivers/gpu/drm/i915/gt/intel_gt_regs.h | 5 + drivers/gpu/drm/i915/i915_hwmon.c | 101 ++++++++++++++++++++- 3 files changed, 110 insertions(+), 3 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon b/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon index 9dc5ff14107b..2d6a472eef88 100644 --- a/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon +++ b/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon @@ -65,6 +65,11 @@ What: /sys/devices/.../hwmon/hwmon/energy1_input Date: February 2023 KernelVersion: 6.2 Contact: intel-gfx@lists.freedesktop.org -Description: RO. Energy input of device in microjoules. +Description: RO. Energy input of device or gt in microjoules. + + For i915 device level hwmon devices (name "i915") this + reflects energy input for the entire device. For gt level + hwmon devices (name "i915_gtN") this reflects energy input + for the gt. Only supported for particular Intel i915 graphics platforms. diff --git a/drivers/gpu/drm/i915/gt/intel_gt_regs.h b/drivers/gpu/drm/i915/gt/intel_gt_regs.h index c7639ae79a8f..2d06610cbec9 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_regs.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_regs.h @@ -1589,6 +1589,11 @@ #define GEN12_SFC_DONE(n) _MMIO(0x1cc000 + (n) * 0x1000) +#define GT0_PACKAGE_ENERGY_STATUS _MMIO(0x250004) +#define GT0_PACKAGE_RAPL_LIMIT _MMIO(0x250008) +#define GT0_PACKAGE_POWER_SKU_UNIT _MMIO(0x250068) +#define GT0_PLATFORM_ENERGY_STATUS _MMIO(0x25006c) + /* * Standalone Media's non-engine GT registers are located at their regular GT * offsets plus 0x380000. This extra offset is stored inside the intel_uncore diff --git a/drivers/gpu/drm/i915/i915_hwmon.c b/drivers/gpu/drm/i915/i915_hwmon.c index 58f80380e542..9e9781493025 100644 --- a/drivers/gpu/drm/i915/i915_hwmon.c +++ b/drivers/gpu/drm/i915/i915_hwmon.c @@ -12,6 +12,7 @@ #include "i915_reg.h" #include "intel_mchbar_regs.h" #include "intel_pcode.h" +#include "gt/intel_gt.h" #include "gt/intel_gt_regs.h" /* @@ -34,6 +35,7 @@ struct hwm_reg { i915_reg_t pkg_power_sku; i915_reg_t pkg_rapl_limit; i915_reg_t energy_status_all; + i915_reg_t energy_status_tile; }; struct hwm_energy_info { @@ -47,10 +49,12 @@ struct hwm_drvdata { struct device *hwmon_dev; struct hwm_energy_info ei; /* Energy info for energy1_input */ char name[12]; + int gt_n; }; struct i915_hwmon { struct hwm_drvdata ddat; + struct hwm_drvdata ddat_gt[I915_MAX_GT]; struct mutex hwmon_lock; /* counter overflow logic and rmw */ struct hwm_reg rg; int scl_shift_power; @@ -144,7 +148,10 @@ hwm_energy(struct hwm_drvdata *ddat, long *energy) i915_reg_t rgaddr; u32 reg_val; - rgaddr = hwmon->rg.energy_status_all; + if (ddat->gt_n >= 0) + rgaddr = hwmon->rg.energy_status_tile; + else + rgaddr = hwmon->rg.energy_status_all; mutex_lock(&hwmon->hwmon_lock); @@ -283,6 +290,11 @@ static const struct hwmon_channel_info *hwm_info[] = { NULL }; +static const struct hwmon_channel_info *hwm_gt_info[] = { + HWMON_CHANNEL_INFO(energy, HWMON_E_INPUT), + NULL +}; + /* I1 is exposed as power_crit or as curr_crit depending on bit 31 */ static int hwm_pcode_read_i1(struct drm_i915_private *i915, u32 *uval) { @@ -414,7 +426,10 @@ hwm_energy_is_visible(const struct hwm_drvdata *ddat, u32 attr) switch (attr) { case hwmon_energy_input: - rgaddr = hwmon->rg.energy_status_all; + if (ddat->gt_n >= 0) + rgaddr = hwmon->rg.energy_status_tile; + else + rgaddr = hwmon->rg.energy_status_all; return i915_mmio_reg_valid(rgaddr) ? 0444 : 0; default: return 0; @@ -550,6 +565,44 @@ static const struct hwmon_chip_info hwm_chip_info = { .info = hwm_info, }; +static umode_t +hwm_gt_is_visible(const void *drvdata, enum hwmon_sensor_types type, + u32 attr, int channel) +{ + struct hwm_drvdata *ddat = (struct hwm_drvdata *)drvdata; + + switch (type) { + case hwmon_energy: + return hwm_energy_is_visible(ddat, attr); + default: + return 0; + } +} + +static int +hwm_gt_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, + int channel, long *val) +{ + struct hwm_drvdata *ddat = dev_get_drvdata(dev); + + switch (type) { + case hwmon_energy: + return hwm_energy_read(ddat, attr, val); + default: + return -EOPNOTSUPP; + } +} + +static const struct hwmon_ops hwm_gt_ops = { + .is_visible = hwm_gt_is_visible, + .read = hwm_gt_read, +}; + +static const struct hwmon_chip_info hwm_gt_chip_info = { + .ops = &hwm_gt_ops, + .info = hwm_gt_info, +}; + static void hwm_get_preregistration_info(struct drm_i915_private *i915) { @@ -558,7 +611,9 @@ hwm_get_preregistration_info(struct drm_i915_private *i915) struct hwm_drvdata *ddat = &hwmon->ddat; intel_wakeref_t wakeref; u32 val_sku_unit = 0; + struct intel_gt *gt; long energy; + int i; /* Available for all Gen12+/dGfx */ hwmon->rg.gt_perf_status = GEN12_RPSTAT1; @@ -568,11 +623,19 @@ hwm_get_preregistration_info(struct drm_i915_private *i915) hwmon->rg.pkg_power_sku = PCU_PACKAGE_POWER_SKU; hwmon->rg.pkg_rapl_limit = PCU_PACKAGE_RAPL_LIMIT; hwmon->rg.energy_status_all = PCU_PACKAGE_ENERGY_STATUS; + hwmon->rg.energy_status_tile = INVALID_MMIO_REG; + } else if (IS_XEHPSDV(i915)) { + hwmon->rg.pkg_power_sku_unit = GT0_PACKAGE_POWER_SKU_UNIT; + hwmon->rg.pkg_power_sku = INVALID_MMIO_REG; + hwmon->rg.pkg_rapl_limit = GT0_PACKAGE_RAPL_LIMIT; + hwmon->rg.energy_status_all = GT0_PLATFORM_ENERGY_STATUS; + hwmon->rg.energy_status_tile = GT0_PACKAGE_ENERGY_STATUS; } else { hwmon->rg.pkg_power_sku_unit = INVALID_MMIO_REG; hwmon->rg.pkg_power_sku = INVALID_MMIO_REG; hwmon->rg.pkg_rapl_limit = INVALID_MMIO_REG; hwmon->rg.energy_status_all = INVALID_MMIO_REG; + hwmon->rg.energy_status_tile = INVALID_MMIO_REG; } with_intel_runtime_pm(uncore->rpm, wakeref) { @@ -595,6 +658,10 @@ hwm_get_preregistration_info(struct drm_i915_private *i915) */ if (i915_mmio_reg_valid(hwmon->rg.energy_status_all)) hwm_energy(ddat, &energy); + if (i915_mmio_reg_valid(hwmon->rg.energy_status_tile)) { + for_each_gt(gt, i915, i) + hwm_energy(&hwmon->ddat_gt[i], &energy); + } } void i915_hwmon_register(struct drm_i915_private *i915) @@ -603,6 +670,9 @@ void i915_hwmon_register(struct drm_i915_private *i915) struct i915_hwmon *hwmon; struct device *hwmon_dev; struct hwm_drvdata *ddat; + struct hwm_drvdata *ddat_gt; + struct intel_gt *gt; + int i; /* hwmon is available only for dGfx */ if (!IS_DGFX(i915)) @@ -619,6 +689,16 @@ void i915_hwmon_register(struct drm_i915_private *i915) ddat->hwmon = hwmon; ddat->uncore = &i915->uncore; snprintf(ddat->name, sizeof(ddat->name), "i915"); + ddat->gt_n = -1; + + for_each_gt(gt, i915, i) { + ddat_gt = hwmon->ddat_gt + i; + + ddat_gt->hwmon = hwmon; + ddat_gt->uncore = gt->uncore; + snprintf(ddat_gt->name, sizeof(ddat_gt->name), "i915_gt%u", i); + ddat_gt->gt_n = i; + } hwm_get_preregistration_info(i915); @@ -633,6 +713,23 @@ void i915_hwmon_register(struct drm_i915_private *i915) } ddat->hwmon_dev = hwmon_dev; + + for_each_gt(gt, i915, i) { + ddat_gt = hwmon->ddat_gt + i; + /* + * Create per-gt directories only if a per-gt attribute is + * visible. Currently this is only energy + */ + if (!hwm_gt_is_visible(ddat_gt, hwmon_energy, hwmon_energy_input, 0)) + continue; + + hwmon_dev = devm_hwmon_device_register_with_info(dev, ddat_gt->name, + ddat_gt, + &hwm_gt_chip_info, + NULL); + if (!IS_ERR(hwmon_dev)) + ddat_gt->hwmon_dev = hwmon_dev; + } } void i915_hwmon_unregister(struct drm_i915_private *i915) -- cgit From dfa13f1bfc8648041da6f39ca95364f1030af3b9 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Fri, 14 Oct 2022 16:02:26 -0700 Subject: drm/i915/gen8: Create separate reg definitions for new MCR registers Gen8 was the first time our hardware had multicast registers (or at least the first time the multicast nature was exposed and MMIO accesses could be steered). There are some registers that transitioned from singleton behavior to multicast during the gen7 -> gen8 transition; let's duplicate the register definitions for those registers in preparation for upcoming patches that will handle MCR registers in a special manner. The registers adjusted are: * MISCCPCTL * SAMPLER_INSTDONE * ROW_INSTDONE * ROW_CHICKEN2 * HALF_SLICE_CHICKEN1 * HALF_SLICE_CHICKEN3 v2: - Use the gen8 version of HALF_SLICE_CHICKEN3 in GVT's gen9 engine MMIO list. (Bala) - Update to the gen8 version of MISCCPCTL in a couple new workarounds that were recently added for DG2/PVC. (Bala) Signed-off-by: Matt Roper Reviewed-by: Balasubramani Vivekanandan Reviewed-by: Balasubramani Vivekanandan Link: https://patchwork.freedesktop.org/patch/msgid/20221014230239.1023689-2-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/gt/intel_engine_cs.c | 4 ++-- drivers/gpu/drm/i915/gt/intel_gt_regs.h | 11 ++++++++++- drivers/gpu/drm/i915/gt/intel_workarounds.c | 26 +++++++++++++------------- drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c | 4 ++-- drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c | 2 +- drivers/gpu/drm/i915/gvt/handlers.c | 2 +- drivers/gpu/drm/i915/gvt/mmio_context.c | 2 +- drivers/gpu/drm/i915/intel_gvt_mmio_table.c | 2 +- drivers/gpu/drm/i915/intel_pm.c | 11 ++++++----- 9 files changed, 37 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c index 2ddcad497fa3..c408bac3c533 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c @@ -1559,11 +1559,11 @@ void intel_engine_get_instdone(const struct intel_engine_cs *engine, for_each_ss_steering(iter, engine->gt, slice, subslice) { instdone->sampler[slice][subslice] = intel_gt_mcr_read(engine->gt, - GEN7_SAMPLER_INSTDONE, + GEN8_SAMPLER_INSTDONE, slice, subslice); instdone->row[slice][subslice] = intel_gt_mcr_read(engine->gt, - GEN7_ROW_INSTDONE, + GEN8_ROW_INSTDONE, slice, subslice); } diff --git a/drivers/gpu/drm/i915/gt/intel_gt_regs.h b/drivers/gpu/drm/i915/gt/intel_gt_regs.h index 2d06610cbec9..d62be9b28863 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_regs.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_regs.h @@ -648,6 +648,9 @@ #define GEN7_MISCCPCTL _MMIO(0x9424) #define GEN7_DOP_CLOCK_GATE_ENABLE (1 << 0) + +#define GEN8_MISCCPCTL _MMIO(0x9424) +#define GEN8_DOP_CLOCK_GATE_ENABLE REG_BIT(0) #define GEN12_DOP_CLOCK_GATE_RENDER_ENABLE REG_BIT(1) #define GEN8_DOP_CLOCK_GATE_CFCLK_ENABLE (1 << 2) #define GEN8_DOP_CLOCK_GATE_GUC_ENABLE (1 << 4) @@ -1069,18 +1072,22 @@ #define GEN12_GAM_DONE _MMIO(0xcf68) #define GEN7_HALF_SLICE_CHICKEN1 _MMIO(0xe100) /* IVB GT1 + VLV */ +#define GEN8_HALF_SLICE_CHICKEN1 _MMIO(0xe100) #define GEN7_MAX_PS_THREAD_DEP (8 << 12) #define GEN7_SINGLE_SUBSCAN_DISPATCH_ENABLE (1 << 10) #define GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE (1 << 4) #define GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE (1 << 3) #define GEN7_SAMPLER_INSTDONE _MMIO(0xe160) +#define GEN8_SAMPLER_INSTDONE _MMIO(0xe160) #define GEN7_ROW_INSTDONE _MMIO(0xe164) +#define GEN8_ROW_INSTDONE _MMIO(0xe164) #define HALF_SLICE_CHICKEN2 _MMIO(0xe180) #define GEN8_ST_PO_DISABLE (1 << 13) -#define HALF_SLICE_CHICKEN3 _MMIO(0xe184) +#define HSW_HALF_SLICE_CHICKEN3 _MMIO(0xe184) +#define GEN8_HALF_SLICE_CHICKEN3 _MMIO(0xe184) #define HSW_SAMPLE_C_PERFORMANCE (1 << 9) #define GEN8_CENTROID_PIXEL_OPT_DIS (1 << 8) #define GEN9_DISABLE_OCL_OOB_SUPPRESS_LOGIC (1 << 5) @@ -1133,6 +1140,8 @@ #define DISABLE_EARLY_EOT REG_BIT(1) #define GEN7_ROW_CHICKEN2 _MMIO(0xe4f4) + +#define GEN8_ROW_CHICKEN2 _MMIO(0xe4f4) #define GEN12_DISABLE_READ_SUPPRESSION REG_BIT(15) #define GEN12_DISABLE_EARLY_READ REG_BIT(14) #define GEN12_ENABLE_LARGE_GRF_MODE REG_BIT(12) diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c index b8eb20a155f0..47a683dcc8a5 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds.c +++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c @@ -295,10 +295,10 @@ static void bdw_ctx_workarounds_init(struct intel_engine_cs *engine, * Also see the related UCGTCL1 write in bdw_init_clock_gating() * to disable EUTC clock gating. */ - wa_masked_en(wal, GEN7_ROW_CHICKEN2, + wa_masked_en(wal, GEN8_ROW_CHICKEN2, DOP_CLOCK_GATING_DISABLE); - wa_masked_en(wal, HALF_SLICE_CHICKEN3, + wa_masked_en(wal, GEN8_HALF_SLICE_CHICKEN3, GEN8_SAMPLER_POWER_BYPASS_DIS); wa_masked_en(wal, HDC_CHICKEN0, @@ -386,7 +386,7 @@ static void gen9_ctx_workarounds_init(struct intel_engine_cs *engine, IS_KABYLAKE(i915) || IS_COFFEELAKE(i915) || IS_COMETLAKE(i915)) - wa_masked_en(wal, HALF_SLICE_CHICKEN3, + wa_masked_en(wal, GEN8_HALF_SLICE_CHICKEN3, GEN8_SAMPLER_POWER_BYPASS_DIS); /* WaDisableSTUnitPowerOptimization:skl,bxt,kbl,glk,cfl */ @@ -490,7 +490,7 @@ static void kbl_ctx_workarounds_init(struct intel_engine_cs *engine, GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION); /* WaDisableSbeCacheDispatchPortSharing:kbl */ - wa_masked_en(wal, GEN7_HALF_SLICE_CHICKEN1, + wa_masked_en(wal, GEN8_HALF_SLICE_CHICKEN1, GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE); } @@ -514,7 +514,7 @@ static void cfl_ctx_workarounds_init(struct intel_engine_cs *engine, GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION); /* WaDisableSbeCacheDispatchPortSharing:cfl */ - wa_masked_en(wal, GEN7_HALF_SLICE_CHICKEN1, + wa_masked_en(wal, GEN8_HALF_SLICE_CHICKEN1, GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE); } @@ -1517,7 +1517,7 @@ dg2_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) wa_write_or(wal, GEN12_SQCM, EN_32B_ACCESS); /* Wa_14015795083 */ - wa_write_clr(wal, GEN7_MISCCPCTL, GEN12_DOP_CLOCK_GATE_RENDER_ENABLE); + wa_write_clr(wal, GEN8_MISCCPCTL, GEN12_DOP_CLOCK_GATE_RENDER_ENABLE); } static void @@ -1526,7 +1526,7 @@ pvc_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) pvc_init_mcr(gt, wal); /* Wa_14015795083 */ - wa_write_clr(wal, GEN7_MISCCPCTL, GEN12_DOP_CLOCK_GATE_RENDER_ENABLE); + wa_write_clr(wal, GEN8_MISCCPCTL, GEN12_DOP_CLOCK_GATE_RENDER_ENABLE); } static void @@ -2117,7 +2117,7 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) if (IS_DG2_GRAPHICS_STEP(i915, G11, STEP_A0, STEP_B0)) { /* Wa_14013392000:dg2_g11 */ - wa_masked_en(wal, GEN7_ROW_CHICKEN2, GEN12_ENABLE_LARGE_GRF_MODE); + wa_masked_en(wal, GEN8_ROW_CHICKEN2, GEN12_ENABLE_LARGE_GRF_MODE); } if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_B0, STEP_FOREVER) || @@ -2163,7 +2163,7 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) DISABLE_128B_EVICTION_COMMAND_UDW); /* Wa_22012856258:dg2 */ - wa_masked_en(wal, GEN7_ROW_CHICKEN2, + wa_masked_en(wal, GEN8_ROW_CHICKEN2, GEN12_DISABLE_READ_SUPPRESSION); /* @@ -2260,7 +2260,7 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) if (IS_ALDERLAKE_P(i915) || IS_ALDERLAKE_S(i915) || IS_DG1(i915) || IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915)) { /* Wa_1606931601:tgl,rkl,dg1,adl-s,adl-p */ - wa_masked_en(wal, GEN7_ROW_CHICKEN2, GEN12_DISABLE_EARLY_READ); + wa_masked_en(wal, GEN8_ROW_CHICKEN2, GEN12_DISABLE_EARLY_READ); /* * Wa_1407928979:tgl A* @@ -2289,7 +2289,7 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) IS_DG1_GRAPHICS_STEP(i915, STEP_A0, STEP_B0) || IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915)) { /* Wa_1409804808:tgl,rkl,dg1[a0],adl-s,adl-p */ - wa_masked_en(wal, GEN7_ROW_CHICKEN2, + wa_masked_en(wal, GEN8_ROW_CHICKEN2, GEN12_PUSH_CONST_DEREF_HOLD_DIS); /* @@ -2508,7 +2508,7 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) if (IS_HASWELL(i915)) { /* WaSampleCChickenBitEnable:hsw */ wa_masked_en(wal, - HALF_SLICE_CHICKEN3, HSW_SAMPLE_C_PERFORMANCE); + HSW_HALF_SLICE_CHICKEN3, HSW_SAMPLE_C_PERFORMANCE); wa_masked_dis(wal, CACHE_MODE_0_GEN7, @@ -2806,7 +2806,7 @@ general_render_compute_wa_init(struct intel_engine_cs *engine, struct i915_wa_li wa_write_or(wal, XEHP_L3NODEARBCFG, XEHP_LNESPARE); /* Wa_14010449647:xehpsdv */ - wa_masked_en(wal, GEN7_HALF_SLICE_CHICKEN1, + wa_masked_en(wal, GEN8_HALF_SLICE_CHICKEN1, GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE); /* Wa_18011725039:xehpsdv */ diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c index 8f1165146013..9495a7928bc8 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c @@ -244,8 +244,8 @@ struct __ext_steer_reg { }; static const struct __ext_steer_reg xe_extregs[] = { - {"GEN7_SAMPLER_INSTDONE", GEN7_SAMPLER_INSTDONE}, - {"GEN7_ROW_INSTDONE", GEN7_ROW_INSTDONE} + {"GEN8_SAMPLER_INSTDONE", GEN8_SAMPLER_INSTDONE}, + {"GEN8_ROW_INSTDONE", GEN8_ROW_INSTDONE} }; static void __fill_ext_reg(struct __guc_mmio_reg_descr *ext, diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c index a0372735cddb..9229243992c2 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c @@ -35,7 +35,7 @@ static void guc_prepare_xfer(struct intel_uncore *uncore) if (GRAPHICS_VER(uncore->i915) == 9) { /* DOP Clock Gating Enable for GuC clocks */ - intel_uncore_rmw(uncore, GEN7_MISCCPCTL, + intel_uncore_rmw(uncore, GEN8_MISCCPCTL, 0, GEN8_DOP_CLOCK_GATE_GUC_ENABLE); /* allows for 5us (in 10ns units) before GT can go to RC6 */ diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c index e7e33f95cc51..683f88f5d669 100644 --- a/drivers/gpu/drm/i915/gvt/handlers.c +++ b/drivers/gpu/drm/i915/gvt/handlers.c @@ -2257,7 +2257,7 @@ static int init_generic_mmio_info(struct intel_gvt *gvt) MMIO_DFH(_MMIO(0x2438), D_ALL, F_CMD_ACCESS, NULL, NULL); MMIO_DFH(_MMIO(0x243c), D_ALL, F_CMD_ACCESS, NULL, NULL); MMIO_DFH(_MMIO(0x7018), D_ALL, F_MODE_MASK | F_CMD_ACCESS, NULL, NULL); - MMIO_DFH(HALF_SLICE_CHICKEN3, D_ALL, F_MODE_MASK | F_CMD_ACCESS, NULL, NULL); + MMIO_DFH(HSW_HALF_SLICE_CHICKEN3, D_ALL, F_MODE_MASK | F_CMD_ACCESS, NULL, NULL); MMIO_DFH(GEN7_HALF_SLICE_CHICKEN1, D_ALL, F_MODE_MASK | F_CMD_ACCESS, NULL, NULL); /* display */ diff --git a/drivers/gpu/drm/i915/gvt/mmio_context.c b/drivers/gpu/drm/i915/gvt/mmio_context.c index c85bafe7539e..485ff6c8e558 100644 --- a/drivers/gpu/drm/i915/gvt/mmio_context.c +++ b/drivers/gpu/drm/i915/gvt/mmio_context.c @@ -111,7 +111,7 @@ static struct engine_mmio gen9_engine_mmio_list[] __cacheline_aligned = { {RCS0, GEN9_SCRATCH_LNCF1, 0, false}, /* 0xb008 */ {RCS0, GEN7_HALF_SLICE_CHICKEN1, 0xffff, true}, /* 0xe100 */ {RCS0, HALF_SLICE_CHICKEN2, 0xffff, true}, /* 0xe180 */ - {RCS0, HALF_SLICE_CHICKEN3, 0xffff, true}, /* 0xe184 */ + {RCS0, GEN8_HALF_SLICE_CHICKEN3, 0xffff, true}, /* 0xe184 */ {RCS0, GEN9_HALF_SLICE_CHICKEN5, 0xffff, true}, /* 0xe188 */ {RCS0, GEN9_HALF_SLICE_CHICKEN7, 0xffff, true}, /* 0xe194 */ {RCS0, GEN8_ROW_CHICKEN, 0xffff, true}, /* 0xe4f0 */ diff --git a/drivers/gpu/drm/i915/intel_gvt_mmio_table.c b/drivers/gpu/drm/i915/intel_gvt_mmio_table.c index e015bc91a26f..51d5c3c804d5 100644 --- a/drivers/gpu/drm/i915/intel_gvt_mmio_table.c +++ b/drivers/gpu/drm/i915/intel_gvt_mmio_table.c @@ -102,7 +102,7 @@ static int iterate_generic_mmio(struct intel_gvt_mmio_table_iter *iter) MMIO_D(_MMIO(0x2438)); MMIO_D(_MMIO(0x243c)); MMIO_D(_MMIO(0x7018)); - MMIO_D(HALF_SLICE_CHICKEN3); + MMIO_D(HSW_HALF_SLICE_CHICKEN3); MMIO_D(GEN7_HALF_SLICE_CHICKEN1); /* display */ MMIO_F(_MMIO(0x60220), 0x20); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 8f86f56e7ca4..21bc2f356451 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4325,8 +4325,8 @@ static void gen8_set_l3sqc_credits(struct drm_i915_private *dev_priv, u32 val; /* WaTempDisableDOPClkGating:bdw */ - misccpctl = intel_uncore_read(&dev_priv->uncore, GEN7_MISCCPCTL); - intel_uncore_write(&dev_priv->uncore, GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE); + misccpctl = intel_uncore_read(&dev_priv->uncore, GEN8_MISCCPCTL); + intel_uncore_write(&dev_priv->uncore, GEN8_MISCCPCTL, misccpctl & ~GEN8_DOP_CLOCK_GATE_ENABLE); val = intel_uncore_read(&dev_priv->uncore, GEN8_L3SQCREG1); val &= ~L3_PRIO_CREDITS_MASK; @@ -4340,7 +4340,7 @@ static void gen8_set_l3sqc_credits(struct drm_i915_private *dev_priv, */ intel_uncore_posting_read(&dev_priv->uncore, GEN8_L3SQCREG1); udelay(1); - intel_uncore_write(&dev_priv->uncore, GEN7_MISCCPCTL, misccpctl); + intel_uncore_write(&dev_priv->uncore, GEN8_MISCCPCTL, misccpctl); } static void icl_init_clock_gating(struct drm_i915_private *dev_priv) @@ -4500,8 +4500,9 @@ static void skl_init_clock_gating(struct drm_i915_private *dev_priv) gen9_init_clock_gating(dev_priv); /* WaDisableDopClockGating:skl */ - intel_uncore_write(&dev_priv->uncore, GEN7_MISCCPCTL, intel_uncore_read(&dev_priv->uncore, GEN7_MISCCPCTL) & - ~GEN7_DOP_CLOCK_GATE_ENABLE); + intel_uncore_write(&dev_priv->uncore, GEN8_MISCCPCTL, + intel_uncore_read(&dev_priv->uncore, GEN8_MISCCPCTL) & + ~GEN8_DOP_CLOCK_GATE_ENABLE); /* WAC6entrylatency:skl */ intel_uncore_write(&dev_priv->uncore, FBC_LLC_READ_CTRL, intel_uncore_read(&dev_priv->uncore, FBC_LLC_READ_CTRL) | -- cgit From 77fa9efc16a901ba451695362fa503cf1556e0c4 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Fri, 14 Oct 2022 16:02:27 -0700 Subject: drm/i915/xehp: Create separate reg definitions for new MCR registers Starting in Xe_HP, several registers our driver works with have been converted from singleton registers into replicated registers with multicast behavior. Although the registers are still located at the same MMIO offsets as on previous platforms, let's duplicate the register definitions in preparation for upcoming patches that will handle multicast registers in a special manner. The registers that are now replicated on Xe_HP are: * PAT_INDEX (mslice replication) * FF_MODE2 (gslice replication) * COMMON_SLICE_CHICKEN3 (gslice replication) * SLICE_COMMON_ECO_CHICKEN1 (gslice replication) * SLICE_UNIT_LEVEL_CLKGATE (gslice replication) * LNCFCMOCS (lncf replication) Note that there are a couple places in selftest_mocs.c where the gen9 version of LNCFCMOCS is still used without regards for which platform we're on. Those cases are just doing an offset lookup and not issuing any CPU reads/writes of the register, so the potentially multicast nature of the register doesn't come into play. v2: - Add commit message note about the unconditional GEN9_LNCFCMOCS usage in selftest_mocs. (Bala) - Include some additional TLB registers. Bspec: 66534 Cc: Balasubramani Vivekanandan Signed-off-by: Matt Roper Reviewed-by: Balasubramani Vivekanandan Link: https://patchwork.freedesktop.org/patch/msgid/20221014230239.1023689-3-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/gt/intel_ggtt.c | 4 ++-- drivers/gpu/drm/i915/gt/intel_gt.c | 18 ++++++++++++++++-- drivers/gpu/drm/i915/gt/intel_gt_regs.h | 26 +++++++++++++++++++------- drivers/gpu/drm/i915/gt/intel_gtt.c | 22 +++++++++++++++++++--- drivers/gpu/drm/i915/gt/intel_gtt.h | 2 +- drivers/gpu/drm/i915/gt/intel_mocs.c | 5 ++++- drivers/gpu/drm/i915/gt/intel_workarounds.c | 24 ++++++++++++------------ drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c | 7 +++++-- 8 files changed, 78 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt.c b/drivers/gpu/drm/i915/gt/intel_ggtt.c index 5c67e49aacf6..6b58c95ad6a0 100644 --- a/drivers/gpu/drm/i915/gt/intel_ggtt.c +++ b/drivers/gpu/drm/i915/gt/intel_ggtt.c @@ -986,7 +986,7 @@ static int gen8_gmch_probe(struct i915_ggtt *ggtt) ggtt->vm.pte_encode = gen8_ggtt_pte_encode; - setup_private_pat(ggtt->vm.gt->uncore); + setup_private_pat(ggtt->vm.gt); return ggtt_probe_common(ggtt, size); } @@ -1308,7 +1308,7 @@ void i915_ggtt_resume(struct i915_ggtt *ggtt) wbinvd_on_all_cpus(); if (GRAPHICS_VER(ggtt->vm.i915) >= 8) - setup_private_pat(ggtt->vm.gt->uncore); + setup_private_pat(ggtt->vm.gt); intel_ggtt_restore_fences(ggtt); } diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c b/drivers/gpu/drm/i915/gt/intel_gt.c index b367cfff48d5..445e171940fa 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt.c +++ b/drivers/gpu/drm/i915/gt/intel_gt.c @@ -314,7 +314,11 @@ static void gen8_check_faults(struct intel_gt *gt) i915_reg_t fault_reg, fault_data0_reg, fault_data1_reg; u32 fault; - if (GRAPHICS_VER(gt->i915) >= 12) { + if (GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 50)) { + fault_reg = XEHP_RING_FAULT_REG; + fault_data0_reg = XEHP_FAULT_TLB_DATA0; + fault_data1_reg = XEHP_FAULT_TLB_DATA1; + } else if (GRAPHICS_VER(gt->i915) >= 12) { fault_reg = GEN12_RING_FAULT_REG; fault_data0_reg = GEN12_FAULT_TLB_DATA0; fault_data1_reg = GEN12_FAULT_TLB_DATA1; @@ -990,6 +994,13 @@ static void mmio_invalidate_full(struct intel_gt *gt) [COPY_ENGINE_CLASS] = GEN12_BLT_TLB_INV_CR, [COMPUTE_CLASS] = GEN12_COMPCTX_TLB_INV_CR, }; + static const i915_reg_t xehp_regs[] = { + [RENDER_CLASS] = XEHP_GFX_TLB_INV_CR, + [VIDEO_DECODE_CLASS] = XEHP_VD_TLB_INV_CR, + [VIDEO_ENHANCEMENT_CLASS] = XEHP_VE_TLB_INV_CR, + [COPY_ENGINE_CLASS] = XEHP_BLT_TLB_INV_CR, + [COMPUTE_CLASS] = XEHP_COMPCTX_TLB_INV_CR, + }; struct drm_i915_private *i915 = gt->i915; struct intel_uncore *uncore = gt->uncore; struct intel_engine_cs *engine; @@ -998,7 +1009,10 @@ static void mmio_invalidate_full(struct intel_gt *gt) const i915_reg_t *regs; unsigned int num = 0; - if (GRAPHICS_VER(i915) == 12) { + if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50)) { + regs = xehp_regs; + num = ARRAY_SIZE(xehp_regs); + } else if (GRAPHICS_VER(i915) == 12) { regs = gen12_regs; num = ARRAY_SIZE(gen12_regs); } else if (GRAPHICS_VER(i915) >= 8 && GRAPHICS_VER(i915) <= 11) { diff --git a/drivers/gpu/drm/i915/gt/intel_gt_regs.h b/drivers/gpu/drm/i915/gt/intel_gt_regs.h index d62be9b28863..ebc9a1d62131 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_regs.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_regs.h @@ -330,6 +330,7 @@ #define GEN7_TLB_RD_ADDR _MMIO(0x4700) #define GEN12_PAT_INDEX(index) _MMIO(0x4800 + (index) * 4) +#define XEHP_PAT_INDEX(index) _MMIO(0x4800 + (index) * 4) #define XEHP_TILE0_ADDR_RANGE _MMIO(0x4900) #define XEHP_TILE_LMEM_RANGE_SHIFT 8 @@ -388,7 +389,8 @@ #define DIS_OVER_FETCH_CACHE REG_BIT(1) #define DIS_MULT_MISS_RD_SQUASH REG_BIT(0) -#define FF_MODE2 _MMIO(0x6604) +#define GEN12_FF_MODE2 _MMIO(0x6604) +#define XEHP_FF_MODE2 _MMIO(0x6604) #define FF_MODE2_GS_TIMER_MASK REG_GENMASK(31, 24) #define FF_MODE2_GS_TIMER_224 REG_FIELD_PREP(FF_MODE2_GS_TIMER_MASK, 224) #define FF_MODE2_TDS_TIMER_MASK REG_GENMASK(23, 16) @@ -443,6 +445,7 @@ #define GEN8_HDC_CHICKEN1 _MMIO(0x7304) #define GEN11_COMMON_SLICE_CHICKEN3 _MMIO(0x7304) +#define XEHP_COMMON_SLICE_CHICKEN3 _MMIO(0x7304) #define DG1_FLOAT_POINT_BLEND_OPT_STRICT_MODE_EN REG_BIT(12) #define XEHP_DUAL_SIMD8_SEQ_MERGE_DISABLE REG_BIT(12) #define GEN11_BLEND_EMB_FIX_DISABLE_IN_RCC REG_BIT(11) @@ -456,10 +459,9 @@ #define DISABLE_PIXEL_MASK_CAMMING (1 << 14) #define GEN9_SLICE_COMMON_ECO_CHICKEN1 _MMIO(0x731c) -#define GEN11_STATE_CACHE_REDIRECT_TO_CS (1 << 11) - -#define SLICE_COMMON_ECO_CHICKEN1 _MMIO(0x731c) +#define XEHP_SLICE_COMMON_ECO_CHICKEN1 _MMIO(0x731c) #define MSC_MSAA_REODER_BUF_BYPASS_DISABLE REG_BIT(14) +#define GEN11_STATE_CACHE_REDIRECT_TO_CS (1 << 11) #define GEN9_SLICE_PGCTL_ACK(slice) _MMIO(0x804c + (slice) * 0x4) #define GEN10_SLICE_PGCTL_ACK(slice) _MMIO(0x804c + ((slice) / 3) * 0x34 + \ @@ -704,7 +706,8 @@ #define GAMTLBVEBOX0_CLKGATE_DIS REG_BIT(16) #define LTCDD_CLKGATE_DIS REG_BIT(10) -#define SLICE_UNIT_LEVEL_CLKGATE _MMIO(0x94d4) +#define GEN11_SLICE_UNIT_LEVEL_CLKGATE _MMIO(0x94d4) +#define XEHP_SLICE_UNIT_LEVEL_CLKGATE _MMIO(0x94d4) #define SARBUNIT_CLKGATE_DIS (1 << 5) #define RCCUNIT_CLKGATE_DIS (1 << 7) #define MSCUNIT_CLKGATE_DIS (1 << 10) @@ -719,7 +722,7 @@ #define VSUNIT_CLKGATE_DIS_TGL REG_BIT(19) #define PSDUNIT_CLKGATE_DIS REG_BIT(5) -#define SUBSLICE_UNIT_LEVEL_CLKGATE _MMIO(0x9524) +#define GEN11_SUBSLICE_UNIT_LEVEL_CLKGATE _MMIO(0x9524) #define DSS_ROUTER_CLKGATE_DIS REG_BIT(28) #define GWUNIT_CLKGATE_DIS REG_BIT(16) @@ -944,7 +947,8 @@ /* MOCS (Memory Object Control State) registers */ #define GEN9_LNCFCMOCS(i) _MMIO(0xb020 + (i) * 4) /* L3 Cache Control */ -#define GEN9_LNCFCMOCS_REG_COUNT 32 +#define XEHP_LNCFCMOCS(i) _MMIO(0xb020 + (i) * 4) +#define LNCFCMOCS_REG_COUNT 32 #define GEN7_L3CNTLREG3 _MMIO(0xb024) @@ -1036,11 +1040,14 @@ #define GEN9_BLT_MOCS(i) _MMIO(__GEN9_BCS0_MOCS0 + (i) * 4) #define GEN12_FAULT_TLB_DATA0 _MMIO(0xceb8) +#define XEHP_FAULT_TLB_DATA0 _MMIO(0xceb8) #define GEN12_FAULT_TLB_DATA1 _MMIO(0xcebc) +#define XEHP_FAULT_TLB_DATA1 _MMIO(0xcebc) #define FAULT_VA_HIGH_BITS (0xf << 0) #define FAULT_GTT_SEL (1 << 4) #define GEN12_RING_FAULT_REG _MMIO(0xcec4) +#define XEHP_RING_FAULT_REG _MMIO(0xcec4) #define GEN8_RING_FAULT_ENGINE_ID(x) (((x) >> 12) & 0x7) #define RING_FAULT_GTTSEL_MASK (1 << 11) #define RING_FAULT_SRCID(x) (((x) >> 3) & 0xff) @@ -1048,10 +1055,15 @@ #define RING_FAULT_VALID (1 << 0) #define GEN12_GFX_TLB_INV_CR _MMIO(0xced8) +#define XEHP_GFX_TLB_INV_CR _MMIO(0xced8) #define GEN12_VD_TLB_INV_CR _MMIO(0xcedc) +#define XEHP_VD_TLB_INV_CR _MMIO(0xcedc) #define GEN12_VE_TLB_INV_CR _MMIO(0xcee0) +#define XEHP_VE_TLB_INV_CR _MMIO(0xcee0) #define GEN12_BLT_TLB_INV_CR _MMIO(0xcee4) +#define XEHP_BLT_TLB_INV_CR _MMIO(0xcee4) #define GEN12_COMPCTX_TLB_INV_CR _MMIO(0xcf04) +#define XEHP_COMPCTX_TLB_INV_CR _MMIO(0xcf04) #define GEN12_MERT_MOD_CTRL _MMIO(0xcf28) #define RENDER_MOD_CTRL _MMIO(0xcf2c) diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.c b/drivers/gpu/drm/i915/gt/intel_gtt.c index 13e411187fd5..e82a9d763e57 100644 --- a/drivers/gpu/drm/i915/gt/intel_gtt.c +++ b/drivers/gpu/drm/i915/gt/intel_gtt.c @@ -15,6 +15,7 @@ #include "i915_trace.h" #include "i915_utils.h" #include "intel_gt.h" +#include "intel_gt_mcr.h" #include "intel_gt_regs.h" #include "intel_gtt.h" @@ -478,6 +479,18 @@ static void tgl_setup_private_ppat(struct intel_uncore *uncore) intel_uncore_write(uncore, GEN12_PAT_INDEX(7), GEN8_PPAT_WB); } +static void xehp_setup_private_ppat(struct intel_gt *gt) +{ + intel_gt_mcr_multicast_write(gt, XEHP_PAT_INDEX(0), GEN8_PPAT_WB); + intel_gt_mcr_multicast_write(gt, XEHP_PAT_INDEX(1), GEN8_PPAT_WC); + intel_gt_mcr_multicast_write(gt, XEHP_PAT_INDEX(2), GEN8_PPAT_WT); + intel_gt_mcr_multicast_write(gt, XEHP_PAT_INDEX(3), GEN8_PPAT_UC); + intel_gt_mcr_multicast_write(gt, XEHP_PAT_INDEX(4), GEN8_PPAT_WB); + intel_gt_mcr_multicast_write(gt, XEHP_PAT_INDEX(5), GEN8_PPAT_WB); + intel_gt_mcr_multicast_write(gt, XEHP_PAT_INDEX(6), GEN8_PPAT_WB); + intel_gt_mcr_multicast_write(gt, XEHP_PAT_INDEX(7), GEN8_PPAT_WB); +} + static void icl_setup_private_ppat(struct intel_uncore *uncore) { intel_uncore_write(uncore, @@ -570,13 +583,16 @@ static void chv_setup_private_ppat(struct intel_uncore *uncore) intel_uncore_write(uncore, GEN8_PRIVATE_PAT_HI, upper_32_bits(pat)); } -void setup_private_pat(struct intel_uncore *uncore) +void setup_private_pat(struct intel_gt *gt) { - struct drm_i915_private *i915 = uncore->i915; + struct intel_uncore *uncore = gt->uncore; + struct drm_i915_private *i915 = gt->i915; GEM_BUG_ON(GRAPHICS_VER(i915) < 8); - if (GRAPHICS_VER(i915) >= 12) + if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50)) + xehp_setup_private_ppat(gt); + else if (GRAPHICS_VER(i915) >= 12) tgl_setup_private_ppat(uncore); else if (GRAPHICS_VER(i915) >= 11) icl_setup_private_ppat(uncore); diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.h b/drivers/gpu/drm/i915/gt/intel_gtt.h index 062b78333fb2..4d75ba4bb41d 100644 --- a/drivers/gpu/drm/i915/gt/intel_gtt.h +++ b/drivers/gpu/drm/i915/gt/intel_gtt.h @@ -668,7 +668,7 @@ void ppgtt_unbind_vma(struct i915_address_space *vm, void gtt_write_workarounds(struct intel_gt *gt); -void setup_private_pat(struct intel_uncore *uncore); +void setup_private_pat(struct intel_gt *gt); int i915_vm_alloc_pt_stash(struct i915_address_space *vm, struct i915_vm_pt_stash *stash, diff --git a/drivers/gpu/drm/i915/gt/intel_mocs.c b/drivers/gpu/drm/i915/gt/intel_mocs.c index 152244d7f62a..ecfa5baa5e3f 100644 --- a/drivers/gpu/drm/i915/gt/intel_mocs.c +++ b/drivers/gpu/drm/i915/gt/intel_mocs.c @@ -616,7 +616,10 @@ static void init_l3cc_table(struct intel_uncore *uncore, u32 l3cc; for_each_l3cc(l3cc, table, i) - intel_uncore_write_fw(uncore, GEN9_LNCFCMOCS(i), l3cc); + if (GRAPHICS_VER_FULL(uncore->i915) >= IP_VER(12, 50)) + intel_uncore_write_fw(uncore, XEHP_LNCFCMOCS(i), l3cc); + else + intel_uncore_write_fw(uncore, GEN9_LNCFCMOCS(i), l3cc); } void intel_mocs_init_engine(struct intel_engine_cs *engine) diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c index 47a683dcc8a5..3056b099dd17 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds.c +++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c @@ -572,7 +572,7 @@ static void dg2_ctx_gt_tuning_init(struct intel_engine_cs *engine, wa_write_clr_set(wal, GEN11_L3SQCREG5, L3_PWM_TIMER_INIT_VAL_MASK, REG_FIELD_PREP(L3_PWM_TIMER_INIT_VAL_MASK, 0x7f)); wa_add(wal, - FF_MODE2, + XEHP_FF_MODE2, FF_MODE2_TDS_TIMER_MASK, FF_MODE2_TDS_TIMER_128, 0, false); @@ -599,7 +599,7 @@ static void gen12_ctx_gt_tuning_init(struct intel_engine_cs *engine, * verification is ignored. */ wa_add(wal, - FF_MODE2, + GEN12_FF_MODE2, FF_MODE2_TDS_TIMER_MASK, FF_MODE2_TDS_TIMER_128, 0, false); @@ -637,7 +637,7 @@ static void gen12_ctx_workarounds_init(struct intel_engine_cs *engine, * to Wa_1608008084. */ wa_add(wal, - FF_MODE2, + GEN12_FF_MODE2, FF_MODE2_GS_TIMER_MASK, FF_MODE2_GS_TIMER_224, 0, false); @@ -670,7 +670,7 @@ static void dg2_ctx_workarounds_init(struct intel_engine_cs *engine, if (IS_DG2_GRAPHICS_STEP(engine->i915, G10, STEP_A0, STEP_B0)) { /* Wa_14010469329:dg2_g10 */ - wa_masked_en(wal, GEN11_COMMON_SLICE_CHICKEN3, + wa_masked_en(wal, XEHP_COMMON_SLICE_CHICKEN3, XEHP_DUAL_SIMD8_SEQ_MERGE_DISABLE); /* @@ -678,12 +678,12 @@ static void dg2_ctx_workarounds_init(struct intel_engine_cs *engine, * Wa_22010613112:dg2_g10 * Wa_14010698770:dg2_g10 */ - wa_masked_en(wal, GEN11_COMMON_SLICE_CHICKEN3, + wa_masked_en(wal, XEHP_COMMON_SLICE_CHICKEN3, GEN12_DISABLE_CPS_AWARE_COLOR_PIPE); } /* Wa_16013271637:dg2 */ - wa_masked_en(wal, SLICE_COMMON_ECO_CHICKEN1, + wa_masked_en(wal, XEHP_SLICE_COMMON_ECO_CHICKEN1, MSC_MSAA_REODER_BUF_BYPASS_DISABLE); /* Wa_14014947963:dg2 */ @@ -1265,14 +1265,14 @@ icl_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) /* Wa_1406680159:icl,ehl */ wa_write_or(wal, - SUBSLICE_UNIT_LEVEL_CLKGATE, + GEN11_SUBSLICE_UNIT_LEVEL_CLKGATE, GWUNIT_CLKGATE_DIS); /* Wa_1607087056:icl,ehl,jsl */ if (IS_ICELAKE(i915) || IS_JSL_EHL_GRAPHICS_STEP(i915, STEP_A0, STEP_B0)) wa_write_or(wal, - SLICE_UNIT_LEVEL_CLKGATE, + GEN11_SLICE_UNIT_LEVEL_CLKGATE, L3_CLKGATE_DIS | L3_CR2X_CLKGATE_DIS); /* @@ -1332,7 +1332,7 @@ tgl_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) /* Wa_1607087056:tgl also know as BUG:1409180338 */ if (IS_TGL_UY_GRAPHICS_STEP(i915, STEP_A0, STEP_B0)) wa_write_or(wal, - SLICE_UNIT_LEVEL_CLKGATE, + GEN11_SLICE_UNIT_LEVEL_CLKGATE, L3_CLKGATE_DIS | L3_CR2X_CLKGATE_DIS); /* Wa_1408615072:tgl[a0] */ @@ -1351,7 +1351,7 @@ dg1_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) /* Wa_1607087056:dg1 */ if (IS_DG1_GRAPHICS_STEP(i915, STEP_A0, STEP_B0)) wa_write_or(wal, - SLICE_UNIT_LEVEL_CLKGATE, + GEN11_SLICE_UNIT_LEVEL_CLKGATE, L3_CLKGATE_DIS | L3_CR2X_CLKGATE_DIS); /* Wa_1409420604:dg1 */ @@ -1455,7 +1455,7 @@ dg2_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) CG3DDISCFEG_CLKGATE_DIS); /* Wa_14011006942:dg2 */ - wa_write_or(wal, SUBSLICE_UNIT_LEVEL_CLKGATE, + wa_write_or(wal, GEN11_SUBSLICE_UNIT_LEVEL_CLKGATE, DSS_ROUTER_CLKGATE_DIS); } @@ -1467,7 +1467,7 @@ dg2_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) wa_write_or(wal, UNSLCGCTL9444, LTCDD_CLKGATE_DIS); /* Wa_14011371254:dg2_g10 */ - wa_write_or(wal, SLICE_UNIT_LEVEL_CLKGATE, NODEDSS_CLKGATE_DIS); + wa_write_or(wal, XEHP_SLICE_UNIT_LEVEL_CLKGATE, NODEDSS_CLKGATE_DIS); /* Wa_14011431319:dg2_g10 */ wa_write_or(wal, UNSLCGCTL9440, GAMTLBOACS_CLKGATE_DIS | diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c index 657f0beb8e06..cc357fa0c270 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c @@ -373,8 +373,11 @@ static int guc_mmio_regset_init(struct temp_regset *regset, false); /* add in local MOCS registers */ - for (i = 0; i < GEN9_LNCFCMOCS_REG_COUNT; i++) - ret |= GUC_MMIO_REG_ADD(gt, regset, GEN9_LNCFCMOCS(i), false); + for (i = 0; i < LNCFCMOCS_REG_COUNT; i++) + if (GRAPHICS_VER_FULL(engine->i915) >= IP_VER(12, 50)) + ret |= GUC_MMIO_REG_ADD(gt, regset, XEHP_LNCFCMOCS(i), false); + else + ret |= GUC_MMIO_REG_ADD(gt, regset, GEN9_LNCFCMOCS(i), false); return ret ? -1 : 0; } -- cgit From fb8af9205595dd79e1051974e1214fbed16f3d74 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Fri, 14 Oct 2022 16:02:28 -0700 Subject: drm/i915/gt: Drop a few unused register definitions Let's drop a few register definitions that are unused anywhere in the driver today. Since the referenced offsets are part of what is now considered a multicast register region, the current definitions would not be correct for use on any future platform. Signed-off-by: Matt Roper Reviewed-by: Balasubramani Vivekanandan Link: https://patchwork.freedesktop.org/patch/msgid/20221014230239.1023689-4-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/gt/intel_gt_regs.h | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_regs.h b/drivers/gpu/drm/i915/gt/intel_gt_regs.h index ebc9a1d62131..be6f0066c2a8 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_regs.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_regs.h @@ -451,13 +451,6 @@ #define GEN11_BLEND_EMB_FIX_DISABLE_IN_RCC REG_BIT(11) #define GEN12_DISABLE_CPS_AWARE_COLOR_PIPE REG_BIT(9) -/* GEN9 chicken */ -#define SLICE_ECO_CHICKEN0 _MMIO(0x7308) -#define PIXEL_MASK_CAMMING_DISABLE (1 << 14) - -#define GEN9_SLICE_COMMON_ECO_CHICKEN0 _MMIO(0x7308) -#define DISABLE_PIXEL_MASK_CAMMING (1 << 14) - #define GEN9_SLICE_COMMON_ECO_CHICKEN1 _MMIO(0x731c) #define XEHP_SLICE_COMMON_ECO_CHICKEN1 _MMIO(0x731c) #define MSC_MSAA_REODER_BUF_BYPASS_DISABLE REG_BIT(14) @@ -964,11 +957,6 @@ #define GEN7_L3LOG(slice, i) _MMIO(0xb070 + (slice) * 0x200 + (i) * 4) #define GEN7_L3LOG_SIZE 0x80 -#define GEN10_SCRATCH_LNCF2 _MMIO(0xb0a0) -#define PMFLUSHDONE_LNICRSDROP (1 << 20) -#define PMFLUSH_GAPL3UNBLOCK (1 << 21) -#define PMFLUSHDONE_LNEBLK (1 << 22) - #define XEHP_L3NODEARBCFG _MMIO(0xb0b4) #define XEHP_LNESPARE REG_BIT(19) @@ -983,9 +971,6 @@ #define L3_HIGH_PRIO_CREDITS(x) (((x) >> 1) << 14) #define L3_PRIO_CREDITS_MASK ((0x1f << 19) | (0x1f << 14)) -#define GEN10_L3_CHICKEN_MODE_REGISTER _MMIO(0xb114) -#define GEN11_I2M_WRITE_DISABLE (1 << 28) - #define GEN8_L3SQCREG4 _MMIO(0xb118) #define GEN11_LQSC_CLEAN_EVICT_DISABLE (1 << 6) #define GEN8_LQSC_RO_PERF_DIS (1 << 27) @@ -1188,8 +1173,6 @@ #define SARB_CHICKEN1 _MMIO(0xe90c) #define COMP_CKN_IN REG_GENMASK(30, 29) -#define GEN7_HALF_SLICE_CHICKEN1_GT2 _MMIO(0xf100) - #define GEN7_ROW_CHICKEN2_GT2 _MMIO(0xf4f4) #define DOP_CLOCK_GATING_DISABLE (1 << 0) #define PUSH_CONSTANT_DEREF_DISABLE (1 << 8) -- cgit From e4abeab94658cdf27f75a824f33ab9ad81d47f96 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Fri, 14 Oct 2022 16:02:29 -0700 Subject: drm/i915/gt: Correct prefix on a few registers We have a few registers that have existed for several hardware generations, but are only used by the driver on Xe_HP and beyond. In cases where the Xe_HP version of the register is now replicated and uses multicast behavior, but earlier generations were singleton, let's change the register prefix to "XEHP_" to help clarify that we're using the newer multicast form of the register. Signed-off-by: Matt Roper Reviewed-by: Balasubramani Vivekanandan Link: https://patchwork.freedesktop.org/patch/msgid/20221014230239.1023689-5-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/gt/intel_gt_regs.h | 8 ++++---- drivers/gpu/drm/i915/gt/intel_workarounds.c | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_regs.h b/drivers/gpu/drm/i915/gt/intel_gt_regs.h index be6f0066c2a8..cf965ade8d90 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_regs.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_regs.h @@ -483,7 +483,7 @@ #define GEN8_RC6_CTX_INFO _MMIO(0x8504) -#define GEN12_SQCM _MMIO(0x8724) +#define XEHP_SQCM _MMIO(0x8724) #define EN_32B_ACCESS REG_BIT(30) #define HSW_IDICR _MMIO(0x9008) @@ -986,7 +986,7 @@ #define GEN11_SCRATCH2 _MMIO(0xb140) #define GEN11_COHERENT_PARTIAL_WRITE_MERGE_ENABLE (1 << 19) -#define GEN11_L3SQCREG5 _MMIO(0xb158) +#define XEHP_L3SQCREG5 _MMIO(0xb158) #define L3_PWM_TIMER_INIT_VAL_MASK REG_GENMASK(9, 0) #define MLTICTXCTL _MMIO(0xb170) @@ -1050,7 +1050,7 @@ #define GEN12_COMPCTX_TLB_INV_CR _MMIO(0xcf04) #define XEHP_COMPCTX_TLB_INV_CR _MMIO(0xcf04) -#define GEN12_MERT_MOD_CTRL _MMIO(0xcf28) +#define XEHP_MERT_MOD_CTRL _MMIO(0xcf28) #define RENDER_MOD_CTRL _MMIO(0xcf2c) #define COMP_MOD_CTRL _MMIO(0xcf30) #define VDBX_MOD_CTRL _MMIO(0xcf34) @@ -1152,7 +1152,7 @@ #define EU_PERF_CNTL1 _MMIO(0xe558) #define EU_PERF_CNTL5 _MMIO(0xe55c) -#define GEN12_HDC_CHICKEN0 _MMIO(0xe5f0) +#define XEHP_HDC_CHICKEN0 _MMIO(0xe5f0) #define LSC_L1_FLUSH_CTL_3D_DATAPORT_FLUSH_EVENTS_MASK REG_GENMASK(13, 11) #define ICL_HDC_MODE _MMIO(0xe5f4) diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c index 3056b099dd17..96b9f02a2284 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds.c +++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c @@ -569,7 +569,7 @@ static void dg2_ctx_gt_tuning_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) { wa_masked_en(wal, CHICKEN_RASTER_2, TBIMR_FAST_CLIP); - wa_write_clr_set(wal, GEN11_L3SQCREG5, L3_PWM_TIMER_INIT_VAL_MASK, + wa_write_clr_set(wal, XEHP_L3SQCREG5, L3_PWM_TIMER_INIT_VAL_MASK, REG_FIELD_PREP(L3_PWM_TIMER_INIT_VAL_MASK, 0x7f)); wa_add(wal, XEHP_FF_MODE2, @@ -1514,7 +1514,7 @@ dg2_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) * recommended tuning settings documented in the bspec's * performance guide section. */ - wa_write_or(wal, GEN12_SQCM, EN_32B_ACCESS); + wa_write_or(wal, XEHP_SQCM, EN_32B_ACCESS); /* Wa_14015795083 */ wa_write_clr(wal, GEN8_MISCCPCTL, GEN12_DOP_CLOCK_GATE_RENDER_ENABLE); @@ -2170,7 +2170,7 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) * Wa_22010960976:dg2 * Wa_14013347512:dg2 */ - wa_masked_dis(wal, GEN12_HDC_CHICKEN0, + wa_masked_dis(wal, XEHP_HDC_CHICKEN0, LSC_L1_FLUSH_CTL_3D_DATAPORT_FLUSH_EVENTS_MASK); } @@ -2223,7 +2223,7 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) if (IS_DG2_GRAPHICS_STEP(engine->i915, G10, STEP_A0, STEP_B0) || IS_DG2_GRAPHICS_STEP(engine->i915, G11, STEP_A0, STEP_B0)) { /* Wa_14012362059:dg2 */ - wa_write_or(wal, GEN12_MERT_MOD_CTRL, FORCE_MISS_FTLB); + wa_write_or(wal, XEHP_MERT_MOD_CTRL, FORCE_MISS_FTLB); } if (IS_DG2_GRAPHICS_STEP(i915, G11, STEP_B0, STEP_FOREVER) || @@ -2816,7 +2816,7 @@ general_render_compute_wa_init(struct intel_engine_cs *engine, struct i915_wa_li } /* Wa_14012362059:xehpsdv */ - wa_write_or(wal, GEN12_MERT_MOD_CTRL, FORCE_MISS_FTLB); + wa_write_or(wal, XEHP_MERT_MOD_CTRL, FORCE_MISS_FTLB); /* Wa_14014368820:xehpsdv */ wa_write_or(wal, GEN12_GAMCNTRL_CTRL, INVALIDATION_BROADCAST_MODE_DIS | -- cgit From 851435ec3686c513b469f8d3d9f8bd405a312412 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Fri, 14 Oct 2022 16:02:30 -0700 Subject: drm/i915/gt: Add intel_gt_mcr_multicast_rmw() operation There are cases where we wish to read from any non-terminated MCR register instance (or the primary instance in the case of GAM ranges), clear/set some bits, and then write the value back out to the register in a multicast manner. Adding a "multicast RMW" will avoid the need to open-code this. v2: - Return a u32 to align with the recent change to intel_uncore_rmw. Signed-off-by: Matt Roper Reviewed-by: Balasubramani Vivekanandan Link: https://patchwork.freedesktop.org/patch/msgid/20221014230239.1023689-6-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/gt/intel_gt_mcr.c | 28 ++++++++++++++++++++++++++++ drivers/gpu/drm/i915/gt/intel_gt_mcr.h | 3 +++ 2 files changed, 31 insertions(+) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_mcr.c b/drivers/gpu/drm/i915/gt/intel_gt_mcr.c index a2047a68ea7a..4dc360f4e344 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_mcr.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_mcr.c @@ -302,6 +302,34 @@ void intel_gt_mcr_multicast_write_fw(struct intel_gt *gt, i915_reg_t reg, u32 va intel_uncore_write_fw(gt->uncore, reg, value); } +/** + * intel_gt_mcr_multicast_rmw - Performs a multicast RMW operations + * @gt: GT structure + * @reg: the MCR register to read and write + * @clear: bits to clear during RMW + * @set: bits to set during RMW + * + * Performs a read-modify-write on an MCR register in a multicast manner. + * This operation only makes sense on MCR registers where all instances are + * expected to have the same value. The read will target any non-terminated + * instance and the write will be applied to all instances. + * + * This function assumes the caller is already holding any necessary forcewake + * domains; use intel_gt_mcr_multicast_rmw() in cases where forcewake should + * be obtained automatically. + * + * Returns the old (unmodified) value read. + */ +u32 intel_gt_mcr_multicast_rmw(struct intel_gt *gt, i915_reg_t reg, + u32 clear, u32 set) +{ + u32 val = intel_gt_mcr_read_any(gt, reg); + + intel_gt_mcr_multicast_write(gt, reg, (val & ~clear) | set); + + return val; +} + /* * reg_needs_read_steering - determine whether a register read requires * explicit steering diff --git a/drivers/gpu/drm/i915/gt/intel_gt_mcr.h b/drivers/gpu/drm/i915/gt/intel_gt_mcr.h index 77a8b11c287d..781b267478db 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_mcr.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_mcr.h @@ -24,6 +24,9 @@ void intel_gt_mcr_multicast_write(struct intel_gt *gt, void intel_gt_mcr_multicast_write_fw(struct intel_gt *gt, i915_reg_t reg, u32 value); +u32 intel_gt_mcr_multicast_rmw(struct intel_gt *gt, i915_reg_t reg, + u32 clear, u32 set); + void intel_gt_mcr_get_nonterminated_steering(struct intel_gt *gt, i915_reg_t reg, u8 *group, u8 *instance); -- cgit From ab1b2d40d626bfb94d10e182a891fd21154234ef Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Fri, 14 Oct 2022 16:02:31 -0700 Subject: drm/i915/xehp: Check for faults on primary GAM On Xe_HP the fault registers are now in a multicast register range. However as part of the GAM these registers follow special rules and we need only read from the "primary" GAM's instance to get the information we need. So a single intel_gt_mcr_read_any() (which will automatically steer to the primary GAM) is sufficient; we don't need to loop over each instance of the MCR register. v2: - Update more instances of fault registers. (Bala) Signed-off-by: Matt Roper Reviewed-by: Balasubramani Vivekanandan Link: https://patchwork.freedesktop.org/patch/msgid/20221014230239.1023689-7-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/gt/intel_gt.c | 52 ++++++++++++++++++++++++++++++----- drivers/gpu/drm/i915/i915_gpu_error.c | 12 ++++++-- 2 files changed, 55 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c b/drivers/gpu/drm/i915/gt/intel_gt.c index 445e171940fa..e14f159ad9fc 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt.c +++ b/drivers/gpu/drm/i915/gt/intel_gt.c @@ -270,7 +270,11 @@ intel_gt_clear_error_registers(struct intel_gt *gt, I915_MASTER_ERROR_INTERRUPT); } - if (GRAPHICS_VER(i915) >= 12) { + if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50)) { + intel_gt_mcr_multicast_rmw(gt, XEHP_RING_FAULT_REG, + RING_FAULT_VALID, 0); + intel_gt_mcr_read_any(gt, XEHP_RING_FAULT_REG); + } else if (GRAPHICS_VER(i915) >= 12) { rmw_clear(uncore, GEN12_RING_FAULT_REG, RING_FAULT_VALID); intel_uncore_posting_read(uncore, GEN12_RING_FAULT_REG); } else if (GRAPHICS_VER(i915) >= 8) { @@ -308,17 +312,49 @@ static void gen6_check_faults(struct intel_gt *gt) } } +static void xehp_check_faults(struct intel_gt *gt) +{ + u32 fault; + + /* + * Although the fault register now lives in an MCR register range, + * the GAM registers are special and we only truly need to read + * the "primary" GAM instance rather than handling each instance + * individually. intel_gt_mcr_read_any() will automatically steer + * toward the primary instance. + */ + fault = intel_gt_mcr_read_any(gt, XEHP_RING_FAULT_REG); + if (fault & RING_FAULT_VALID) { + u32 fault_data0, fault_data1; + u64 fault_addr; + + fault_data0 = intel_gt_mcr_read_any(gt, XEHP_FAULT_TLB_DATA0); + fault_data1 = intel_gt_mcr_read_any(gt, XEHP_FAULT_TLB_DATA1); + + fault_addr = ((u64)(fault_data1 & FAULT_VA_HIGH_BITS) << 44) | + ((u64)fault_data0 << 12); + + drm_dbg(>->i915->drm, "Unexpected fault\n" + "\tAddr: 0x%08x_%08x\n" + "\tAddress space: %s\n" + "\tEngine ID: %d\n" + "\tSource ID: %d\n" + "\tType: %d\n", + upper_32_bits(fault_addr), lower_32_bits(fault_addr), + fault_data1 & FAULT_GTT_SEL ? "GGTT" : "PPGTT", + GEN8_RING_FAULT_ENGINE_ID(fault), + RING_FAULT_SRCID(fault), + RING_FAULT_FAULT_TYPE(fault)); + } +} + static void gen8_check_faults(struct intel_gt *gt) { struct intel_uncore *uncore = gt->uncore; i915_reg_t fault_reg, fault_data0_reg, fault_data1_reg; u32 fault; - if (GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 50)) { - fault_reg = XEHP_RING_FAULT_REG; - fault_data0_reg = XEHP_FAULT_TLB_DATA0; - fault_data1_reg = XEHP_FAULT_TLB_DATA1; - } else if (GRAPHICS_VER(gt->i915) >= 12) { + if (GRAPHICS_VER(gt->i915) >= 12) { fault_reg = GEN12_RING_FAULT_REG; fault_data0_reg = GEN12_FAULT_TLB_DATA0; fault_data1_reg = GEN12_FAULT_TLB_DATA1; @@ -358,7 +394,9 @@ void intel_gt_check_and_clear_faults(struct intel_gt *gt) struct drm_i915_private *i915 = gt->i915; /* From GEN8 onwards we only have one 'All Engine Fault Register' */ - if (GRAPHICS_VER(i915) >= 8) + if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50)) + xehp_check_faults(gt); + else if (GRAPHICS_VER(i915) >= 8) gen8_check_faults(gt); else if (GRAPHICS_VER(i915) >= 6) gen6_check_faults(gt); diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 9ea2fe34e7d3..f2d53edcd2ee 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -1221,7 +1221,10 @@ static void engine_record_registers(struct intel_engine_coredump *ee) if (GRAPHICS_VER(i915) >= 6) { ee->rc_psmi = ENGINE_READ(engine, RING_PSMI_CTL); - if (GRAPHICS_VER(i915) >= 12) + if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50)) + ee->fault_reg = intel_gt_mcr_read_any(engine->gt, + XEHP_RING_FAULT_REG); + else if (GRAPHICS_VER(i915) >= 12) ee->fault_reg = intel_uncore_read(engine->uncore, GEN12_RING_FAULT_REG); else if (GRAPHICS_VER(i915) >= 8) @@ -1820,7 +1823,12 @@ static void gt_record_global_regs(struct intel_gt_coredump *gt) if (GRAPHICS_VER(i915) == 7) gt->err_int = intel_uncore_read(uncore, GEN7_ERR_INT); - if (GRAPHICS_VER(i915) >= 12) { + if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50)) { + gt->fault_data0 = intel_gt_mcr_read_any((struct intel_gt *)gt->_gt, + XEHP_FAULT_TLB_DATA0); + gt->fault_data1 = intel_gt_mcr_read_any((struct intel_gt *)gt->_gt, + XEHP_FAULT_TLB_DATA1); + } else if (GRAPHICS_VER(i915) >= 12) { gt->fault_data0 = intel_uncore_read(uncore, GEN12_FAULT_TLB_DATA0); gt->fault_data1 = intel_uncore_read(uncore, -- cgit From 3068bec83eea324b299105ec69a3f42c7968c6c0 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Fri, 14 Oct 2022 16:02:32 -0700 Subject: drm/i915/gt: Add intel_gt_mcr_wait_for_reg_fw() Xe_HP has some MCR registers that need to be polled for completion of operations like TLB invalidation. Those registers are in the GAM range, which rolls up the status from each unit into the 'primary' instance's value. This makes it useful to have a dedicated 'wait for register' function that handles this on MCR registers, similar to the __intel_wait_for_register_fw() function we already have for regular registers. Signed-off-by: Matt Roper Reviewed-by: Balasubramani Vivekanandan Link: https://patchwork.freedesktop.org/patch/msgid/20221014230239.1023689-8-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/gt/intel_gt_mcr.c | 55 ++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/gt/intel_gt_mcr.h | 7 +++++ 2 files changed, 62 insertions(+) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_mcr.c b/drivers/gpu/drm/i915/gt/intel_gt_mcr.c index 4dc360f4e344..1ed9bc4dccfd 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_mcr.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_mcr.c @@ -568,3 +568,58 @@ void intel_gt_mcr_get_ss_steering(struct intel_gt *gt, unsigned int dss, return; } } + +/** + * intel_gt_mcr_wait_for_reg_fw - wait until MCR register matches expected state + * @gt: GT structure + * @reg: the register to read + * @mask: mask to apply to register value + * @value: value to wait for + * @fast_timeout_us: fast timeout in microsecond for atomic/tight wait + * @slow_timeout_ms: slow timeout in millisecond + * + * This routine waits until the target register @reg contains the expected + * @value after applying the @mask, i.e. it waits until :: + * + * (intel_gt_mcr_read_any_fw(gt, reg) & mask) == value + * + * Otherwise, the wait will timeout after @slow_timeout_ms milliseconds. + * For atomic context @slow_timeout_ms must be zero and @fast_timeout_us + * must be not larger than 20,0000 microseconds. + * + * This function is basically an MCR-friendly version of + * __intel_wait_for_register_fw(). Generally this function will only be used + * on GAM registers which are a bit special --- although they're MCR registers, + * reads (e.g., waiting for status updates) are always directed to the primary + * instance. + * + * Note that this routine assumes the caller holds forcewake asserted, it is + * not suitable for very long waits. + * + * Return: 0 if the register matches the desired condition, or -ETIMEDOUT. + */ +int intel_gt_mcr_wait_for_reg_fw(struct intel_gt *gt, + i915_reg_t reg, + u32 mask, + u32 value, + unsigned int fast_timeout_us, + unsigned int slow_timeout_ms) +{ + u32 reg_value = 0; +#define done (((reg_value = intel_gt_mcr_read_any_fw(gt, reg)) & mask) == value) + int ret; + + /* Catch any overuse of this function */ + might_sleep_if(slow_timeout_ms); + GEM_BUG_ON(fast_timeout_us > 20000); + GEM_BUG_ON(!fast_timeout_us && !slow_timeout_ms); + + ret = -ETIMEDOUT; + if (fast_timeout_us && fast_timeout_us <= 20000) + ret = _wait_for_atomic(done, fast_timeout_us, 0); + if (ret && slow_timeout_ms) + ret = wait_for(done, slow_timeout_ms); + + return ret; +#undef done +} diff --git a/drivers/gpu/drm/i915/gt/intel_gt_mcr.h b/drivers/gpu/drm/i915/gt/intel_gt_mcr.h index 781b267478db..548f922cd9fa 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_mcr.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_mcr.h @@ -37,6 +37,13 @@ void intel_gt_mcr_report_steering(struct drm_printer *p, struct intel_gt *gt, void intel_gt_mcr_get_ss_steering(struct intel_gt *gt, unsigned int dss, unsigned int *group, unsigned int *instance); +int intel_gt_mcr_wait_for_reg_fw(struct intel_gt *gt, + i915_reg_t reg, + u32 mask, + u32 value, + unsigned int fast_timeout_us, + unsigned int slow_timeout_ms); + /* * Helper for for_each_ss_steering loop. On pre-Xe_HP platforms, subslice * presence is determined by using the group/instance as direct lookups in the -- cgit From a9e69428b1b4bb0fcf5a55f13d87557de723d7ed Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Fri, 14 Oct 2022 16:02:33 -0700 Subject: drm/i915: Define MCR registers explicitly Rather than using the same _MMIO() macro to define MCR registers as singleton registers, let's use a new MCR_REG() macro to make it clear that these registers are special and should be handled accordingly. For now MCR_REG() will still generate an i915_reg_t with the given offset, but we'll change that in future patches. Bspec: 66673, 66696, 66534, 67609 Signed-off-by: Matt Roper Reviewed-by: Balasubramani Vivekanandan Link: https://patchwork.freedesktop.org/patch/msgid/20221014230239.1023689-9-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/gt/intel_gt_regs.h | 134 ++++++++++++++++---------------- 1 file changed, 68 insertions(+), 66 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_regs.h b/drivers/gpu/drm/i915/gt/intel_gt_regs.h index cf965ade8d90..bd2bbacf2386 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_regs.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_regs.h @@ -8,6 +8,8 @@ #include "i915_reg_defs.h" +#define MCR_REG(offset) _MMIO(offset) + /* RPM unit config (Gen8+) */ #define RPM_CONFIG0 _MMIO(0xd00) #define GEN9_RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_SHIFT 3 @@ -330,12 +332,12 @@ #define GEN7_TLB_RD_ADDR _MMIO(0x4700) #define GEN12_PAT_INDEX(index) _MMIO(0x4800 + (index) * 4) -#define XEHP_PAT_INDEX(index) _MMIO(0x4800 + (index) * 4) +#define XEHP_PAT_INDEX(index) MCR_REG(0x4800 + (index) * 4) -#define XEHP_TILE0_ADDR_RANGE _MMIO(0x4900) +#define XEHP_TILE0_ADDR_RANGE MCR_REG(0x4900) #define XEHP_TILE_LMEM_RANGE_SHIFT 8 -#define XEHP_FLAT_CCS_BASE_ADDR _MMIO(0x4910) +#define XEHP_FLAT_CCS_BASE_ADDR MCR_REG(0x4910) #define XEHP_CCS_BASE_SHIFT 8 #define GAMTARBMODE _MMIO(0x4a08) @@ -385,18 +387,18 @@ #define CHICKEN_RASTER_2 _MMIO(0x6208) #define TBIMR_FAST_CLIP REG_BIT(5) -#define VFLSKPD _MMIO(0x62a8) +#define VFLSKPD MCR_REG(0x62a8) #define DIS_OVER_FETCH_CACHE REG_BIT(1) #define DIS_MULT_MISS_RD_SQUASH REG_BIT(0) #define GEN12_FF_MODE2 _MMIO(0x6604) -#define XEHP_FF_MODE2 _MMIO(0x6604) +#define XEHP_FF_MODE2 MCR_REG(0x6604) #define FF_MODE2_GS_TIMER_MASK REG_GENMASK(31, 24) #define FF_MODE2_GS_TIMER_224 REG_FIELD_PREP(FF_MODE2_GS_TIMER_MASK, 224) #define FF_MODE2_TDS_TIMER_MASK REG_GENMASK(23, 16) #define FF_MODE2_TDS_TIMER_128 REG_FIELD_PREP(FF_MODE2_TDS_TIMER_MASK, 4) -#define XEHPG_INSTDONE_GEOM_SVG _MMIO(0x666c) +#define XEHPG_INSTDONE_GEOM_SVG MCR_REG(0x666c) #define CACHE_MODE_0_GEN7 _MMIO(0x7000) /* IVB+ */ #define RC_OP_FLUSH_ENABLE (1 << 0) @@ -445,14 +447,14 @@ #define GEN8_HDC_CHICKEN1 _MMIO(0x7304) #define GEN11_COMMON_SLICE_CHICKEN3 _MMIO(0x7304) -#define XEHP_COMMON_SLICE_CHICKEN3 _MMIO(0x7304) +#define XEHP_COMMON_SLICE_CHICKEN3 MCR_REG(0x7304) #define DG1_FLOAT_POINT_BLEND_OPT_STRICT_MODE_EN REG_BIT(12) #define XEHP_DUAL_SIMD8_SEQ_MERGE_DISABLE REG_BIT(12) #define GEN11_BLEND_EMB_FIX_DISABLE_IN_RCC REG_BIT(11) #define GEN12_DISABLE_CPS_AWARE_COLOR_PIPE REG_BIT(9) #define GEN9_SLICE_COMMON_ECO_CHICKEN1 _MMIO(0x731c) -#define XEHP_SLICE_COMMON_ECO_CHICKEN1 _MMIO(0x731c) +#define XEHP_SLICE_COMMON_ECO_CHICKEN1 MCR_REG(0x731c) #define MSC_MSAA_REODER_BUF_BYPASS_DISABLE REG_BIT(14) #define GEN11_STATE_CACHE_REDIRECT_TO_CS (1 << 11) @@ -483,7 +485,7 @@ #define GEN8_RC6_CTX_INFO _MMIO(0x8504) -#define XEHP_SQCM _MMIO(0x8724) +#define XEHP_SQCM MCR_REG(0x8724) #define EN_32B_ACCESS REG_BIT(30) #define HSW_IDICR _MMIO(0x9008) @@ -644,7 +646,7 @@ #define GEN7_MISCCPCTL _MMIO(0x9424) #define GEN7_DOP_CLOCK_GATE_ENABLE (1 << 0) -#define GEN8_MISCCPCTL _MMIO(0x9424) +#define GEN8_MISCCPCTL MCR_REG(0x9424) #define GEN8_DOP_CLOCK_GATE_ENABLE REG_BIT(0) #define GEN12_DOP_CLOCK_GATE_RENDER_ENABLE REG_BIT(1) #define GEN8_DOP_CLOCK_GATE_CFCLK_ENABLE (1 << 2) @@ -700,7 +702,7 @@ #define LTCDD_CLKGATE_DIS REG_BIT(10) #define GEN11_SLICE_UNIT_LEVEL_CLKGATE _MMIO(0x94d4) -#define XEHP_SLICE_UNIT_LEVEL_CLKGATE _MMIO(0x94d4) +#define XEHP_SLICE_UNIT_LEVEL_CLKGATE MCR_REG(0x94d4) #define SARBUNIT_CLKGATE_DIS (1 << 5) #define RCCUNIT_CLKGATE_DIS (1 << 7) #define MSCUNIT_CLKGATE_DIS (1 << 10) @@ -708,27 +710,27 @@ #define L3_CLKGATE_DIS REG_BIT(16) #define L3_CR2X_CLKGATE_DIS REG_BIT(17) -#define SCCGCTL94DC _MMIO(0x94dc) +#define SCCGCTL94DC MCR_REG(0x94dc) #define CG3DDISURB REG_BIT(14) #define UNSLICE_UNIT_LEVEL_CLKGATE2 _MMIO(0x94e4) #define VSUNIT_CLKGATE_DIS_TGL REG_BIT(19) #define PSDUNIT_CLKGATE_DIS REG_BIT(5) -#define GEN11_SUBSLICE_UNIT_LEVEL_CLKGATE _MMIO(0x9524) +#define GEN11_SUBSLICE_UNIT_LEVEL_CLKGATE MCR_REG(0x9524) #define DSS_ROUTER_CLKGATE_DIS REG_BIT(28) #define GWUNIT_CLKGATE_DIS REG_BIT(16) -#define SUBSLICE_UNIT_LEVEL_CLKGATE2 _MMIO(0x9528) +#define SUBSLICE_UNIT_LEVEL_CLKGATE2 MCR_REG(0x9528) #define CPSSUNIT_CLKGATE_DIS REG_BIT(9) -#define SSMCGCTL9530 _MMIO(0x9530) +#define SSMCGCTL9530 MCR_REG(0x9530) #define RTFUNIT_CLKGATE_DIS REG_BIT(18) -#define GEN10_DFR_RATIO_EN_AND_CHICKEN _MMIO(0x9550) +#define GEN10_DFR_RATIO_EN_AND_CHICKEN MCR_REG(0x9550) #define DFR_DISABLE (1 << 9) -#define INF_UNIT_LEVEL_CLKGATE _MMIO(0x9560) +#define INF_UNIT_LEVEL_CLKGATE MCR_REG(0x9560) #define CGPSF_CLKGATE_DIS (1 << 3) #define MICRO_BP0_0 _MMIO(0x9800) @@ -940,7 +942,7 @@ /* MOCS (Memory Object Control State) registers */ #define GEN9_LNCFCMOCS(i) _MMIO(0xb020 + (i) * 4) /* L3 Cache Control */ -#define XEHP_LNCFCMOCS(i) _MMIO(0xb020 + (i) * 4) +#define XEHP_LNCFCMOCS(i) MCR_REG(0xb020 + (i) * 4) #define LNCFCMOCS_REG_COUNT 32 #define GEN7_L3CNTLREG3 _MMIO(0xb024) @@ -957,10 +959,10 @@ #define GEN7_L3LOG(slice, i) _MMIO(0xb070 + (slice) * 0x200 + (i) * 4) #define GEN7_L3LOG_SIZE 0x80 -#define XEHP_L3NODEARBCFG _MMIO(0xb0b4) +#define XEHP_L3NODEARBCFG MCR_REG(0xb0b4) #define XEHP_LNESPARE REG_BIT(19) -#define GEN8_L3SQCREG1 _MMIO(0xb100) +#define GEN8_L3SQCREG1 MCR_REG(0xb100) /* * Note that on CHV the following has an off-by-one error wrt. to BSpec. * Using the formula in BSpec leads to a hang, while the formula here works @@ -971,28 +973,28 @@ #define L3_HIGH_PRIO_CREDITS(x) (((x) >> 1) << 14) #define L3_PRIO_CREDITS_MASK ((0x1f << 19) | (0x1f << 14)) -#define GEN8_L3SQCREG4 _MMIO(0xb118) +#define GEN8_L3SQCREG4 MCR_REG(0xb118) #define GEN11_LQSC_CLEAN_EVICT_DISABLE (1 << 6) #define GEN8_LQSC_RO_PERF_DIS (1 << 27) #define GEN8_LQSC_FLUSH_COHERENT_LINES (1 << 21) #define GEN8_LQSQ_NONIA_COHERENT_ATOMICS_ENABLE REG_BIT(22) -#define GEN9_SCRATCH1 _MMIO(0xb11c) +#define GEN9_SCRATCH1 MCR_REG(0xb11c) #define EVICTION_PERF_FIX_ENABLE REG_BIT(8) -#define BDW_SCRATCH1 _MMIO(0xb11c) +#define BDW_SCRATCH1 MCR_REG(0xb11c) #define GEN9_LBS_SLA_RETRY_TIMER_DECREMENT_ENABLE (1 << 2) -#define GEN11_SCRATCH2 _MMIO(0xb140) +#define GEN11_SCRATCH2 MCR_REG(0xb140) #define GEN11_COHERENT_PARTIAL_WRITE_MERGE_ENABLE (1 << 19) -#define XEHP_L3SQCREG5 _MMIO(0xb158) +#define XEHP_L3SQCREG5 MCR_REG(0xb158) #define L3_PWM_TIMER_INIT_VAL_MASK REG_GENMASK(9, 0) -#define MLTICTXCTL _MMIO(0xb170) +#define MLTICTXCTL MCR_REG(0xb170) #define TDONRENDER REG_BIT(2) -#define XEHP_L3SCQREG7 _MMIO(0xb188) +#define XEHP_L3SCQREG7 MCR_REG(0xb188) #define BLEND_FILL_CACHING_OPT_DIS REG_BIT(3) #define XEHPC_L3SCRUB _MMIO(0xb18c) @@ -1000,7 +1002,7 @@ #define SCRUB_RATE_PER_BANK_MASK REG_GENMASK(2, 0) #define SCRUB_RATE_4B_PER_CLK REG_FIELD_PREP(SCRUB_RATE_PER_BANK_MASK, 0x6) -#define L3SQCREG1_CCS0 _MMIO(0xb200) +#define L3SQCREG1_CCS0 MCR_REG(0xb200) #define FLUSHALLNONCOH REG_BIT(5) #define GEN11_GLBLINVL _MMIO(0xb404) @@ -1025,14 +1027,14 @@ #define GEN9_BLT_MOCS(i) _MMIO(__GEN9_BCS0_MOCS0 + (i) * 4) #define GEN12_FAULT_TLB_DATA0 _MMIO(0xceb8) -#define XEHP_FAULT_TLB_DATA0 _MMIO(0xceb8) +#define XEHP_FAULT_TLB_DATA0 MCR_REG(0xceb8) #define GEN12_FAULT_TLB_DATA1 _MMIO(0xcebc) -#define XEHP_FAULT_TLB_DATA1 _MMIO(0xcebc) +#define XEHP_FAULT_TLB_DATA1 MCR_REG(0xcebc) #define FAULT_VA_HIGH_BITS (0xf << 0) #define FAULT_GTT_SEL (1 << 4) #define GEN12_RING_FAULT_REG _MMIO(0xcec4) -#define XEHP_RING_FAULT_REG _MMIO(0xcec4) +#define XEHP_RING_FAULT_REG MCR_REG(0xcec4) #define GEN8_RING_FAULT_ENGINE_ID(x) (((x) >> 12) & 0x7) #define RING_FAULT_GTTSEL_MASK (1 << 11) #define RING_FAULT_SRCID(x) (((x) >> 3) & 0xff) @@ -1040,21 +1042,21 @@ #define RING_FAULT_VALID (1 << 0) #define GEN12_GFX_TLB_INV_CR _MMIO(0xced8) -#define XEHP_GFX_TLB_INV_CR _MMIO(0xced8) +#define XEHP_GFX_TLB_INV_CR MCR_REG(0xced8) #define GEN12_VD_TLB_INV_CR _MMIO(0xcedc) -#define XEHP_VD_TLB_INV_CR _MMIO(0xcedc) +#define XEHP_VD_TLB_INV_CR MCR_REG(0xcedc) #define GEN12_VE_TLB_INV_CR _MMIO(0xcee0) -#define XEHP_VE_TLB_INV_CR _MMIO(0xcee0) +#define XEHP_VE_TLB_INV_CR MCR_REG(0xcee0) #define GEN12_BLT_TLB_INV_CR _MMIO(0xcee4) -#define XEHP_BLT_TLB_INV_CR _MMIO(0xcee4) +#define XEHP_BLT_TLB_INV_CR MCR_REG(0xcee4) #define GEN12_COMPCTX_TLB_INV_CR _MMIO(0xcf04) -#define XEHP_COMPCTX_TLB_INV_CR _MMIO(0xcf04) +#define XEHP_COMPCTX_TLB_INV_CR MCR_REG(0xcf04) -#define XEHP_MERT_MOD_CTRL _MMIO(0xcf28) -#define RENDER_MOD_CTRL _MMIO(0xcf2c) -#define COMP_MOD_CTRL _MMIO(0xcf30) -#define VDBX_MOD_CTRL _MMIO(0xcf34) -#define VEBX_MOD_CTRL _MMIO(0xcf38) +#define XEHP_MERT_MOD_CTRL MCR_REG(0xcf28) +#define RENDER_MOD_CTRL MCR_REG(0xcf2c) +#define COMP_MOD_CTRL MCR_REG(0xcf30) +#define VDBX_MOD_CTRL MCR_REG(0xcf34) +#define VEBX_MOD_CTRL MCR_REG(0xcf38) #define FORCE_MISS_FTLB REG_BIT(3) #define GEN12_GAMSTLB_CTRL _MMIO(0xcf4c) @@ -1069,52 +1071,52 @@ #define GEN12_GAM_DONE _MMIO(0xcf68) #define GEN7_HALF_SLICE_CHICKEN1 _MMIO(0xe100) /* IVB GT1 + VLV */ -#define GEN8_HALF_SLICE_CHICKEN1 _MMIO(0xe100) +#define GEN8_HALF_SLICE_CHICKEN1 MCR_REG(0xe100) #define GEN7_MAX_PS_THREAD_DEP (8 << 12) #define GEN7_SINGLE_SUBSCAN_DISPATCH_ENABLE (1 << 10) #define GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE (1 << 4) #define GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE (1 << 3) #define GEN7_SAMPLER_INSTDONE _MMIO(0xe160) -#define GEN8_SAMPLER_INSTDONE _MMIO(0xe160) +#define GEN8_SAMPLER_INSTDONE MCR_REG(0xe160) #define GEN7_ROW_INSTDONE _MMIO(0xe164) -#define GEN8_ROW_INSTDONE _MMIO(0xe164) +#define GEN8_ROW_INSTDONE MCR_REG(0xe164) -#define HALF_SLICE_CHICKEN2 _MMIO(0xe180) +#define HALF_SLICE_CHICKEN2 MCR_REG(0xe180) #define GEN8_ST_PO_DISABLE (1 << 13) #define HSW_HALF_SLICE_CHICKEN3 _MMIO(0xe184) -#define GEN8_HALF_SLICE_CHICKEN3 _MMIO(0xe184) +#define GEN8_HALF_SLICE_CHICKEN3 MCR_REG(0xe184) #define HSW_SAMPLE_C_PERFORMANCE (1 << 9) #define GEN8_CENTROID_PIXEL_OPT_DIS (1 << 8) #define GEN9_DISABLE_OCL_OOB_SUPPRESS_LOGIC (1 << 5) #define GEN8_SAMPLER_POWER_BYPASS_DIS (1 << 1) -#define GEN9_HALF_SLICE_CHICKEN5 _MMIO(0xe188) +#define GEN9_HALF_SLICE_CHICKEN5 MCR_REG(0xe188) #define GEN9_DG_MIRROR_FIX_ENABLE (1 << 5) #define GEN9_CCS_TLB_PREFETCH_ENABLE (1 << 3) -#define GEN10_SAMPLER_MODE _MMIO(0xe18c) +#define GEN10_SAMPLER_MODE MCR_REG(0xe18c) #define ENABLE_SMALLPL REG_BIT(15) #define SC_DISABLE_POWER_OPTIMIZATION_EBB REG_BIT(9) #define GEN11_SAMPLER_ENABLE_HEADLESS_MSG REG_BIT(5) -#define GEN9_HALF_SLICE_CHICKEN7 _MMIO(0xe194) +#define GEN9_HALF_SLICE_CHICKEN7 MCR_REG(0xe194) #define DG2_DISABLE_ROUND_ENABLE_ALLOW_FOR_SSLA REG_BIT(15) #define GEN9_SAMPLER_HASH_COMPRESSED_READ_ADDR REG_BIT(8) #define GEN9_ENABLE_YV12_BUGFIX REG_BIT(4) #define GEN9_ENABLE_GPGPU_PREEMPTION REG_BIT(2) -#define GEN10_CACHE_MODE_SS _MMIO(0xe420) +#define GEN10_CACHE_MODE_SS MCR_REG(0xe420) #define ENABLE_EU_COUNT_FOR_TDL_FLUSH REG_BIT(10) #define DISABLE_ECC REG_BIT(5) #define FLOAT_BLEND_OPTIMIZATION_ENABLE REG_BIT(4) #define ENABLE_PREFETCH_INTO_IC REG_BIT(3) -#define EU_PERF_CNTL0 _MMIO(0xe458) -#define EU_PERF_CNTL4 _MMIO(0xe45c) +#define EU_PERF_CNTL0 MCR_REG(0xe458) +#define EU_PERF_CNTL4 MCR_REG(0xe45c) -#define GEN9_ROW_CHICKEN4 _MMIO(0xe48c) +#define GEN9_ROW_CHICKEN4 MCR_REG(0xe48c) #define GEN12_DISABLE_GRF_CLEAR REG_BIT(13) #define XEHP_DIS_BBL_SYSPIPE REG_BIT(11) #define GEN12_DISABLE_TDL_PUSH REG_BIT(9) @@ -1126,7 +1128,7 @@ #define HSW_ROW_CHICKEN3 _MMIO(0xe49c) #define HSW_ROW_CHICKEN3_L3_GLOBAL_ATOMICS_DISABLE (1 << 6) -#define GEN8_ROW_CHICKEN _MMIO(0xe4f0) +#define GEN8_ROW_CHICKEN MCR_REG(0xe4f0) #define FLOW_CONTROL_ENABLE REG_BIT(15) #define UGM_BACKUP_MODE REG_BIT(13) #define MDQ_ARBITRATION_MODE REG_BIT(12) @@ -1138,39 +1140,39 @@ #define GEN7_ROW_CHICKEN2 _MMIO(0xe4f4) -#define GEN8_ROW_CHICKEN2 _MMIO(0xe4f4) +#define GEN8_ROW_CHICKEN2 MCR_REG(0xe4f4) #define GEN12_DISABLE_READ_SUPPRESSION REG_BIT(15) #define GEN12_DISABLE_EARLY_READ REG_BIT(14) #define GEN12_ENABLE_LARGE_GRF_MODE REG_BIT(12) #define GEN12_PUSH_CONST_DEREF_HOLD_DIS REG_BIT(8) -#define RT_CTRL _MMIO(0xe530) +#define RT_CTRL MCR_REG(0xe530) #define DIS_NULL_QUERY REG_BIT(10) #define STACKID_CTRL REG_GENMASK(6, 5) #define STACKID_CTRL_512 REG_FIELD_PREP(STACKID_CTRL, 0x2) -#define EU_PERF_CNTL1 _MMIO(0xe558) -#define EU_PERF_CNTL5 _MMIO(0xe55c) +#define EU_PERF_CNTL1 MCR_REG(0xe558) +#define EU_PERF_CNTL5 MCR_REG(0xe55c) -#define XEHP_HDC_CHICKEN0 _MMIO(0xe5f0) +#define XEHP_HDC_CHICKEN0 MCR_REG(0xe5f0) #define LSC_L1_FLUSH_CTL_3D_DATAPORT_FLUSH_EVENTS_MASK REG_GENMASK(13, 11) -#define ICL_HDC_MODE _MMIO(0xe5f4) +#define ICL_HDC_MODE MCR_REG(0xe5f4) -#define EU_PERF_CNTL2 _MMIO(0xe658) -#define EU_PERF_CNTL6 _MMIO(0xe65c) -#define EU_PERF_CNTL3 _MMIO(0xe758) +#define EU_PERF_CNTL2 MCR_REG(0xe658) +#define EU_PERF_CNTL6 MCR_REG(0xe65c) +#define EU_PERF_CNTL3 MCR_REG(0xe758) -#define LSC_CHICKEN_BIT_0 _MMIO(0xe7c8) +#define LSC_CHICKEN_BIT_0 MCR_REG(0xe7c8) #define DISABLE_D8_D16_COASLESCE REG_BIT(30) #define FORCE_1_SUB_MESSAGE_PER_FRAGMENT REG_BIT(15) -#define LSC_CHICKEN_BIT_0_UDW _MMIO(0xe7c8 + 4) +#define LSC_CHICKEN_BIT_0_UDW MCR_REG(0xe7c8 + 4) #define DIS_CHAIN_2XSIMD8 REG_BIT(55 - 32) #define FORCE_SLM_FENCE_SCOPE_TO_TILE REG_BIT(42 - 32) #define FORCE_UGM_FENCE_SCOPE_TO_TILE REG_BIT(41 - 32) #define MAXREQS_PER_BANK REG_GENMASK(39 - 32, 37 - 32) #define DISABLE_128B_EVICTION_COMMAND_UDW REG_BIT(36 - 32) -#define SARB_CHICKEN1 _MMIO(0xe90c) +#define SARB_CHICKEN1 MCR_REG(0xe90c) #define COMP_CKN_IN REG_GENMASK(30, 29) #define GEN7_ROW_CHICKEN2_GT2 _MMIO(0xf4f4) -- cgit From 46c507f03a46108e5a93acc06a060601ac9b83d6 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Fri, 14 Oct 2022 16:02:34 -0700 Subject: drm/i915/gt: Always use MCR functions on multicast registers Rather than relying on the implicit behavior of intel_uncore_*() functions, let's always use the intel_gt_mcr_*() functions to operate on multicast/replicated registers. v2: - Add TLB invalidation registers v3: - Switch more uncore operations in mmio_invalidate_full() to MCR operations for Xe_HP. (Bala) Cc: Balasubramani Vivekanandan Signed-off-by: Matt Roper Reviewed-by: Balasubramani Vivekanandan Link: https://patchwork.freedesktop.org/patch/msgid/20221014230239.1023689-10-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/gt/intel_gt.c | 58 +++++++++++++++++++++---------- drivers/gpu/drm/i915/gt/intel_mocs.c | 13 +++---- drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c | 12 ++++--- drivers/gpu/drm/i915/intel_pm.c | 19 +++++----- 4 files changed, 65 insertions(+), 37 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c b/drivers/gpu/drm/i915/gt/intel_gt.c index e14f159ad9fc..3df0d0336dbc 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt.c +++ b/drivers/gpu/drm/i915/gt/intel_gt.c @@ -1017,6 +1017,32 @@ get_reg_and_bit(const struct intel_engine_cs *engine, const bool gen8, return rb; } +/* + * HW architecture suggest typical invalidation time at 40us, + * with pessimistic cases up to 100us and a recommendation to + * cap at 1ms. We go a bit higher just in case. + */ +#define TLB_INVAL_TIMEOUT_US 100 +#define TLB_INVAL_TIMEOUT_MS 4 + +/* + * On Xe_HP the TLB invalidation registers are located at the same MMIO offsets + * but are now considered MCR registers. Since they exist within a GAM range, + * the primary instance of the register rolls up the status from each unit. + */ +static int wait_for_invalidate(struct intel_gt *gt, struct reg_and_bit rb) +{ + if (GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 50)) + return intel_gt_mcr_wait_for_reg_fw(gt, rb.reg, rb.bit, 0, + TLB_INVAL_TIMEOUT_US, + TLB_INVAL_TIMEOUT_MS); + else + return __intel_wait_for_register_fw(gt->uncore, rb.reg, rb.bit, 0, + TLB_INVAL_TIMEOUT_US, + TLB_INVAL_TIMEOUT_MS, + NULL); +} + static void mmio_invalidate_full(struct intel_gt *gt) { static const i915_reg_t gen8_regs[] = { @@ -1048,7 +1074,7 @@ static void mmio_invalidate_full(struct intel_gt *gt) unsigned int num = 0; if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50)) { - regs = xehp_regs; + regs = NULL; num = ARRAY_SIZE(xehp_regs); } else if (GRAPHICS_VER(i915) == 12) { regs = gen12_regs; @@ -1075,11 +1101,17 @@ static void mmio_invalidate_full(struct intel_gt *gt) if (!intel_engine_pm_is_awake(engine)) continue; - rb = get_reg_and_bit(engine, regs == gen8_regs, regs, num); - if (!i915_mmio_reg_offset(rb.reg)) - continue; + if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50)) { + intel_gt_mcr_multicast_write_fw(gt, + xehp_regs[engine->class], + BIT(engine->instance)); + } else { + rb = get_reg_and_bit(engine, regs == gen8_regs, regs, num); + if (!i915_mmio_reg_offset(rb.reg)) + continue; - intel_uncore_write_fw(uncore, rb.reg, rb.bit); + intel_uncore_write_fw(uncore, rb.reg, rb.bit); + } awake |= engine->mask; } @@ -1099,22 +1131,12 @@ static void mmio_invalidate_full(struct intel_gt *gt) for_each_engine_masked(engine, gt, awake, tmp) { struct reg_and_bit rb; - /* - * HW architecture suggest typical invalidation time at 40us, - * with pessimistic cases up to 100us and a recommendation to - * cap at 1ms. We go a bit higher just in case. - */ - const unsigned int timeout_us = 100; - const unsigned int timeout_ms = 4; - rb = get_reg_and_bit(engine, regs == gen8_regs, regs, num); - if (__intel_wait_for_register_fw(uncore, - rb.reg, rb.bit, 0, - timeout_us, timeout_ms, - NULL)) + + if (wait_for_invalidate(gt, rb)) drm_err_ratelimited(>->i915->drm, "%s TLB invalidation did not complete in %ums!\n", - engine->name, timeout_ms); + engine->name, TLB_INVAL_TIMEOUT_MS); } /* diff --git a/drivers/gpu/drm/i915/gt/intel_mocs.c b/drivers/gpu/drm/i915/gt/intel_mocs.c index ecfa5baa5e3f..49fdd509527a 100644 --- a/drivers/gpu/drm/i915/gt/intel_mocs.c +++ b/drivers/gpu/drm/i915/gt/intel_mocs.c @@ -7,6 +7,7 @@ #include "intel_engine.h" #include "intel_gt.h" +#include "intel_gt_mcr.h" #include "intel_gt_regs.h" #include "intel_mocs.h" #include "intel_ring.h" @@ -609,17 +610,17 @@ static u32 l3cc_combine(u16 low, u16 high) 0; \ i++) -static void init_l3cc_table(struct intel_uncore *uncore, +static void init_l3cc_table(struct intel_gt *gt, const struct drm_i915_mocs_table *table) { unsigned int i; u32 l3cc; for_each_l3cc(l3cc, table, i) - if (GRAPHICS_VER_FULL(uncore->i915) >= IP_VER(12, 50)) - intel_uncore_write_fw(uncore, XEHP_LNCFCMOCS(i), l3cc); + if (GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 50)) + intel_gt_mcr_multicast_write_fw(gt, XEHP_LNCFCMOCS(i), l3cc); else - intel_uncore_write_fw(uncore, GEN9_LNCFCMOCS(i), l3cc); + intel_uncore_write_fw(gt->uncore, GEN9_LNCFCMOCS(i), l3cc); } void intel_mocs_init_engine(struct intel_engine_cs *engine) @@ -639,7 +640,7 @@ void intel_mocs_init_engine(struct intel_engine_cs *engine) init_mocs_table(engine, &table); if (flags & HAS_RENDER_L3CC && engine->class == RENDER_CLASS) - init_l3cc_table(engine->uncore, &table); + init_l3cc_table(engine->gt, &table); } static u32 global_mocs_offset(void) @@ -675,7 +676,7 @@ void intel_mocs_init(struct intel_gt *gt) * memory transactions including guc transactions */ if (flags & HAS_RENDER_L3CC) - init_l3cc_table(gt->uncore, &table); + init_l3cc_table(gt, &table); } #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c index 9229243992c2..5b86b2e286e0 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c @@ -10,12 +10,15 @@ */ #include "gt/intel_gt.h" +#include "gt/intel_gt_mcr.h" #include "gt/intel_gt_regs.h" #include "intel_guc_fw.h" #include "i915_drv.h" -static void guc_prepare_xfer(struct intel_uncore *uncore) +static void guc_prepare_xfer(struct intel_gt *gt) { + struct intel_uncore *uncore = gt->uncore; + u32 shim_flags = GUC_ENABLE_READ_CACHE_LOGIC | GUC_ENABLE_READ_CACHE_FOR_SRAM_DATA | GUC_ENABLE_READ_CACHE_FOR_WOPCM_DATA | @@ -35,8 +38,9 @@ static void guc_prepare_xfer(struct intel_uncore *uncore) if (GRAPHICS_VER(uncore->i915) == 9) { /* DOP Clock Gating Enable for GuC clocks */ - intel_uncore_rmw(uncore, GEN8_MISCCPCTL, - 0, GEN8_DOP_CLOCK_GATE_GUC_ENABLE); + intel_gt_mcr_multicast_write(gt, GEN8_MISCCPCTL, + GEN8_DOP_CLOCK_GATE_GUC_ENABLE | + intel_gt_mcr_read_any(gt, GEN8_MISCCPCTL)); /* allows for 5us (in 10ns units) before GT can go to RC6 */ intel_uncore_write(uncore, GUC_ARAT_C6DIS, 0x1FF); @@ -168,7 +172,7 @@ int intel_guc_fw_upload(struct intel_guc *guc) struct intel_uncore *uncore = gt->uncore; int ret; - guc_prepare_xfer(uncore); + guc_prepare_xfer(gt); /* * Note that GuC needs the CSS header plus uKernel code to be copied diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 21bc2f356451..95f1e40b8972 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -30,6 +30,8 @@ #include "display/skl_watermark.h" #include "gt/intel_engine_regs.h" +#include "gt/intel_gt.h" +#include "gt/intel_gt_mcr.h" #include "gt/intel_gt_regs.h" #include "i915_drv.h" @@ -4325,22 +4327,22 @@ static void gen8_set_l3sqc_credits(struct drm_i915_private *dev_priv, u32 val; /* WaTempDisableDOPClkGating:bdw */ - misccpctl = intel_uncore_read(&dev_priv->uncore, GEN8_MISCCPCTL); - intel_uncore_write(&dev_priv->uncore, GEN8_MISCCPCTL, misccpctl & ~GEN8_DOP_CLOCK_GATE_ENABLE); + misccpctl = intel_gt_mcr_multicast_rmw(to_gt(dev_priv), GEN8_MISCCPCTL, + GEN8_DOP_CLOCK_GATE_ENABLE, 0); - val = intel_uncore_read(&dev_priv->uncore, GEN8_L3SQCREG1); + val = intel_gt_mcr_read_any(to_gt(dev_priv), GEN8_L3SQCREG1); val &= ~L3_PRIO_CREDITS_MASK; val |= L3_GENERAL_PRIO_CREDITS(general_prio_credits); val |= L3_HIGH_PRIO_CREDITS(high_prio_credits); - intel_uncore_write(&dev_priv->uncore, GEN8_L3SQCREG1, val); + intel_gt_mcr_multicast_write(to_gt(dev_priv), GEN8_L3SQCREG1, val); /* * Wait at least 100 clocks before re-enabling clock gating. * See the definition of L3SQCREG1 in BSpec. */ - intel_uncore_posting_read(&dev_priv->uncore, GEN8_L3SQCREG1); + intel_gt_mcr_read_any(to_gt(dev_priv), GEN8_L3SQCREG1); udelay(1); - intel_uncore_write(&dev_priv->uncore, GEN8_MISCCPCTL, misccpctl); + intel_gt_mcr_multicast_write(to_gt(dev_priv), GEN8_MISCCPCTL, misccpctl); } static void icl_init_clock_gating(struct drm_i915_private *dev_priv) @@ -4500,9 +4502,8 @@ static void skl_init_clock_gating(struct drm_i915_private *dev_priv) gen9_init_clock_gating(dev_priv); /* WaDisableDopClockGating:skl */ - intel_uncore_write(&dev_priv->uncore, GEN8_MISCCPCTL, - intel_uncore_read(&dev_priv->uncore, GEN8_MISCCPCTL) & - ~GEN8_DOP_CLOCK_GATE_ENABLE); + intel_gt_mcr_multicast_rmw(to_gt(dev_priv), GEN8_MISCCPCTL, + GEN8_DOP_CLOCK_GATE_ENABLE, 0); /* WAC6entrylatency:skl */ intel_uncore_write(&dev_priv->uncore, FBC_LLC_READ_CTRL, intel_uncore_read(&dev_priv->uncore, FBC_LLC_READ_CTRL) | -- cgit From cf35f6afb92643633f4ecbb386ab8a572cca0386 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Fri, 14 Oct 2022 16:02:35 -0700 Subject: drm/i915/guc: Handle save/restore of MCR registers explicitly MCR registers can be placed on the GuC's save/restore list, but at the moment they are always handled in a multicast manner (i.e., the GuC reads one instance to save the value and then does a multicast write to restore that single value to all instances). In the future the GuC will probably give us an alternate interface to do unicast per-instance save/restore operations, so we should be very clear about which registers on the list are MCR registers (and in the future which save/restore behavior we want for them). Signed-off-by: Matt Roper Reviewed-by: Balasubramani Vivekanandan Link: https://patchwork.freedesktop.org/patch/msgid/20221014230239.1023689-11-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c | 55 ++++++++++++++++++------------ 1 file changed, 34 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c index cc357fa0c270..de923fb82301 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c @@ -278,24 +278,16 @@ __mmio_reg_add(struct temp_regset *regset, struct guc_mmio_reg *reg) return slot; } -#define GUC_REGSET_STEERING(group, instance) ( \ - FIELD_PREP(GUC_REGSET_STEERING_GROUP, (group)) | \ - FIELD_PREP(GUC_REGSET_STEERING_INSTANCE, (instance)) | \ - GUC_REGSET_NEEDS_STEERING \ -) - static long __must_check guc_mmio_reg_add(struct intel_gt *gt, struct temp_regset *regset, - i915_reg_t reg, u32 flags) + u32 offset, u32 flags) { u32 count = regset->storage_used - (regset->registers - regset->storage); - u32 offset = i915_mmio_reg_offset(reg); struct guc_mmio_reg entry = { .offset = offset, .flags = flags, }; struct guc_mmio_reg *slot; - u8 group, inst; /* * The mmio list is built using separate lists within the driver. @@ -307,17 +299,6 @@ static long __must_check guc_mmio_reg_add(struct intel_gt *gt, sizeof(entry), guc_mmio_reg_cmp)) return 0; - /* - * The GuC doesn't have a default steering, so we need to explicitly - * steer all registers that need steering. However, we do not keep track - * of all the steering ranges, only of those that have a chance of using - * a non-default steering from the i915 pov. Instead of adding such - * tracking, it is easier to just program the default steering for all - * regs that don't need a non-default one. - */ - intel_gt_mcr_get_nonterminated_steering(gt, reg, &group, &inst); - entry.flags |= GUC_REGSET_STEERING(group, inst); - slot = __mmio_reg_add(regset, &entry); if (IS_ERR(slot)) return PTR_ERR(slot); @@ -335,6 +316,38 @@ static long __must_check guc_mmio_reg_add(struct intel_gt *gt, #define GUC_MMIO_REG_ADD(gt, regset, reg, masked) \ guc_mmio_reg_add(gt, \ + regset, \ + i915_mmio_reg_offset(reg), \ + (masked) ? GUC_REGSET_MASKED : 0) + +#define GUC_REGSET_STEERING(group, instance) ( \ + FIELD_PREP(GUC_REGSET_STEERING_GROUP, (group)) | \ + FIELD_PREP(GUC_REGSET_STEERING_INSTANCE, (instance)) | \ + GUC_REGSET_NEEDS_STEERING \ +) + +static long __must_check guc_mcr_reg_add(struct intel_gt *gt, + struct temp_regset *regset, + i915_reg_t reg, u32 flags) +{ + u8 group, inst; + + /* + * The GuC doesn't have a default steering, so we need to explicitly + * steer all registers that need steering. However, we do not keep track + * of all the steering ranges, only of those that have a chance of using + * a non-default steering from the i915 pov. Instead of adding such + * tracking, it is easier to just program the default steering for all + * regs that don't need a non-default one. + */ + intel_gt_mcr_get_nonterminated_steering(gt, reg, &group, &inst); + flags |= GUC_REGSET_STEERING(group, inst); + + return guc_mmio_reg_add(gt, regset, i915_mmio_reg_offset(reg), flags); +} + +#define GUC_MCR_REG_ADD(gt, regset, reg, masked) \ + guc_mcr_reg_add(gt, \ regset, \ (reg), \ (masked) ? GUC_REGSET_MASKED : 0) @@ -375,7 +388,7 @@ static int guc_mmio_regset_init(struct temp_regset *regset, /* add in local MOCS registers */ for (i = 0; i < LNCFCMOCS_REG_COUNT; i++) if (GRAPHICS_VER_FULL(engine->i915) >= IP_VER(12, 50)) - ret |= GUC_MMIO_REG_ADD(gt, regset, XEHP_LNCFCMOCS(i), false); + ret |= GUC_MCR_REG_ADD(gt, regset, XEHP_LNCFCMOCS(i), false); else ret |= GUC_MMIO_REG_ADD(gt, regset, GEN9_LNCFCMOCS(i), false); -- cgit From 9e49bda902bc3e88e3530b3b93a95f727e8aa141 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Fri, 14 Oct 2022 16:02:36 -0700 Subject: drm/i915/gt: Add MCR-specific workaround initializers Let's be more explicit about which of our workarounds are updating MCR registers. Signed-off-by: Matt Roper Reviewed-by: Balasubramani Vivekanandan Link: https://patchwork.freedesktop.org/patch/msgid/20221014230239.1023689-12-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/gt/intel_workarounds.c | 433 +++++++++++++--------- drivers/gpu/drm/i915/gt/intel_workarounds_types.h | 4 +- 2 files changed, 263 insertions(+), 174 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c index 96b9f02a2284..7671994d5b7a 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds.c +++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c @@ -166,12 +166,33 @@ static void wa_add(struct i915_wa_list *wal, i915_reg_t reg, _wa_add(wal, &wa); } +static void wa_mcr_add(struct i915_wa_list *wal, i915_reg_t reg, + u32 clear, u32 set, u32 read_mask, bool masked_reg) +{ + struct i915_wa wa = { + .reg = reg, + .clr = clear, + .set = set, + .read = read_mask, + .masked_reg = masked_reg, + .is_mcr = 1, + }; + + _wa_add(wal, &wa); +} + static void wa_write_clr_set(struct i915_wa_list *wal, i915_reg_t reg, u32 clear, u32 set) { wa_add(wal, reg, clear, set, clear, false); } +static void +wa_mcr_write_clr_set(struct i915_wa_list *wal, i915_reg_t reg, u32 clear, u32 set) +{ + wa_mcr_add(wal, reg, clear, set, clear, false); +} + static void wa_write(struct i915_wa_list *wal, i915_reg_t reg, u32 set) { @@ -184,12 +205,24 @@ wa_write_or(struct i915_wa_list *wal, i915_reg_t reg, u32 set) wa_write_clr_set(wal, reg, set, set); } +static void +wa_mcr_write_or(struct i915_wa_list *wal, i915_reg_t reg, u32 set) +{ + wa_mcr_write_clr_set(wal, reg, set, set); +} + static void wa_write_clr(struct i915_wa_list *wal, i915_reg_t reg, u32 clr) { wa_write_clr_set(wal, reg, clr, 0); } +static void +wa_mcr_write_clr(struct i915_wa_list *wal, i915_reg_t reg, u32 clr) +{ + wa_mcr_write_clr_set(wal, reg, clr, 0); +} + /* * WA operations on "masked register". A masked register has the upper 16 bits * documented as "masked" in b-spec. Its purpose is to allow writing to just a @@ -207,12 +240,24 @@ wa_masked_en(struct i915_wa_list *wal, i915_reg_t reg, u32 val) wa_add(wal, reg, 0, _MASKED_BIT_ENABLE(val), val, true); } +static void +wa_mcr_masked_en(struct i915_wa_list *wal, i915_reg_t reg, u32 val) +{ + wa_mcr_add(wal, reg, 0, _MASKED_BIT_ENABLE(val), val, true); +} + static void wa_masked_dis(struct i915_wa_list *wal, i915_reg_t reg, u32 val) { wa_add(wal, reg, 0, _MASKED_BIT_DISABLE(val), val, true); } +static void +wa_mcr_masked_dis(struct i915_wa_list *wal, i915_reg_t reg, u32 val) +{ + wa_mcr_add(wal, reg, 0, _MASKED_BIT_DISABLE(val), val, true); +} + static void wa_masked_field_set(struct i915_wa_list *wal, i915_reg_t reg, u32 mask, u32 val) @@ -220,6 +265,13 @@ wa_masked_field_set(struct i915_wa_list *wal, i915_reg_t reg, wa_add(wal, reg, 0, _MASKED_FIELD(mask, val), mask, true); } +static void +wa_mcr_masked_field_set(struct i915_wa_list *wal, i915_reg_t reg, + u32 mask, u32 val) +{ + wa_mcr_add(wal, reg, 0, _MASKED_FIELD(mask, val), mask, true); +} + static void gen6_ctx_workarounds_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) { @@ -241,8 +293,8 @@ static void gen8_ctx_workarounds_init(struct intel_engine_cs *engine, wa_masked_en(wal, RING_MI_MODE(RENDER_RING_BASE), ASYNC_FLIP_PERF_DISABLE); /* WaDisablePartialInstShootdown:bdw,chv */ - wa_masked_en(wal, GEN8_ROW_CHICKEN, - PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE); + wa_mcr_masked_en(wal, GEN8_ROW_CHICKEN, + PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE); /* Use Force Non-Coherent whenever executing a 3D context. This is a * workaround for a possible hang in the unlikely event a TLB @@ -288,18 +340,18 @@ static void bdw_ctx_workarounds_init(struct intel_engine_cs *engine, gen8_ctx_workarounds_init(engine, wal); /* WaDisableThreadStallDopClockGating:bdw (pre-production) */ - wa_masked_en(wal, GEN8_ROW_CHICKEN, STALL_DOP_GATING_DISABLE); + wa_mcr_masked_en(wal, GEN8_ROW_CHICKEN, STALL_DOP_GATING_DISABLE); /* WaDisableDopClockGating:bdw * * Also see the related UCGTCL1 write in bdw_init_clock_gating() * to disable EUTC clock gating. */ - wa_masked_en(wal, GEN8_ROW_CHICKEN2, - DOP_CLOCK_GATING_DISABLE); + wa_mcr_masked_en(wal, GEN8_ROW_CHICKEN2, + DOP_CLOCK_GATING_DISABLE); - wa_masked_en(wal, GEN8_HALF_SLICE_CHICKEN3, - GEN8_SAMPLER_POWER_BYPASS_DIS); + wa_mcr_masked_en(wal, GEN8_HALF_SLICE_CHICKEN3, + GEN8_SAMPLER_POWER_BYPASS_DIS); wa_masked_en(wal, HDC_CHICKEN0, /* WaForceContextSaveRestoreNonCoherent:bdw */ @@ -314,7 +366,7 @@ static void chv_ctx_workarounds_init(struct intel_engine_cs *engine, gen8_ctx_workarounds_init(engine, wal); /* WaDisableThreadStallDopClockGating:chv */ - wa_masked_en(wal, GEN8_ROW_CHICKEN, STALL_DOP_GATING_DISABLE); + wa_mcr_masked_en(wal, GEN8_ROW_CHICKEN, STALL_DOP_GATING_DISABLE); /* Improve HiZ throughput on CHV. */ wa_masked_en(wal, HIZ_CHICKEN, CHV_HZ_8X8_MODE_IN_1X); @@ -333,21 +385,21 @@ static void gen9_ctx_workarounds_init(struct intel_engine_cs *engine, */ wa_masked_en(wal, COMMON_SLICE_CHICKEN2, GEN9_PBE_COMPRESSED_HASH_SELECTION); - wa_masked_en(wal, GEN9_HALF_SLICE_CHICKEN7, - GEN9_SAMPLER_HASH_COMPRESSED_READ_ADDR); + wa_mcr_masked_en(wal, GEN9_HALF_SLICE_CHICKEN7, + GEN9_SAMPLER_HASH_COMPRESSED_READ_ADDR); } /* WaClearFlowControlGpgpuContextSave:skl,bxt,kbl,glk,cfl */ /* WaDisablePartialInstShootdown:skl,bxt,kbl,glk,cfl */ - wa_masked_en(wal, GEN8_ROW_CHICKEN, - FLOW_CONTROL_ENABLE | - PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE); + wa_mcr_masked_en(wal, GEN8_ROW_CHICKEN, + FLOW_CONTROL_ENABLE | + PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE); /* WaEnableYV12BugFixInHalfSliceChicken7:skl,bxt,kbl,glk,cfl */ /* WaEnableSamplerGPGPUPreemptionSupport:skl,bxt,kbl,cfl */ - wa_masked_en(wal, GEN9_HALF_SLICE_CHICKEN7, - GEN9_ENABLE_YV12_BUGFIX | - GEN9_ENABLE_GPGPU_PREEMPTION); + wa_mcr_masked_en(wal, GEN9_HALF_SLICE_CHICKEN7, + GEN9_ENABLE_YV12_BUGFIX | + GEN9_ENABLE_GPGPU_PREEMPTION); /* Wa4x4STCOptimizationDisable:skl,bxt,kbl,glk,cfl */ /* WaDisablePartialResolveInVc:skl,bxt,kbl,cfl */ @@ -356,8 +408,8 @@ static void gen9_ctx_workarounds_init(struct intel_engine_cs *engine, GEN9_PARTIAL_RESOLVE_IN_VC_DISABLE); /* WaCcsTlbPrefetchDisable:skl,bxt,kbl,glk,cfl */ - wa_masked_dis(wal, GEN9_HALF_SLICE_CHICKEN5, - GEN9_CCS_TLB_PREFETCH_ENABLE); + wa_mcr_masked_dis(wal, GEN9_HALF_SLICE_CHICKEN5, + GEN9_CCS_TLB_PREFETCH_ENABLE); /* WaForceContextSaveRestoreNonCoherent:skl,bxt,kbl,cfl */ wa_masked_en(wal, HDC_CHICKEN0, @@ -386,11 +438,11 @@ static void gen9_ctx_workarounds_init(struct intel_engine_cs *engine, IS_KABYLAKE(i915) || IS_COFFEELAKE(i915) || IS_COMETLAKE(i915)) - wa_masked_en(wal, GEN8_HALF_SLICE_CHICKEN3, - GEN8_SAMPLER_POWER_BYPASS_DIS); + wa_mcr_masked_en(wal, GEN8_HALF_SLICE_CHICKEN3, + GEN8_SAMPLER_POWER_BYPASS_DIS); /* WaDisableSTUnitPowerOptimization:skl,bxt,kbl,glk,cfl */ - wa_masked_en(wal, HALF_SLICE_CHICKEN2, GEN8_ST_PO_DISABLE); + wa_mcr_masked_en(wal, HALF_SLICE_CHICKEN2, GEN8_ST_PO_DISABLE); /* * Supporting preemption with fine-granularity requires changes in the @@ -469,8 +521,8 @@ static void bxt_ctx_workarounds_init(struct intel_engine_cs *engine, gen9_ctx_workarounds_init(engine, wal); /* WaDisableThreadStallDopClockGating:bxt */ - wa_masked_en(wal, GEN8_ROW_CHICKEN, - STALL_DOP_GATING_DISABLE); + wa_mcr_masked_en(wal, GEN8_ROW_CHICKEN, + STALL_DOP_GATING_DISABLE); /* WaToEnableHwFixForPushConstHWBug:bxt */ wa_masked_en(wal, COMMON_SLICE_CHICKEN2, @@ -490,8 +542,8 @@ static void kbl_ctx_workarounds_init(struct intel_engine_cs *engine, GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION); /* WaDisableSbeCacheDispatchPortSharing:kbl */ - wa_masked_en(wal, GEN8_HALF_SLICE_CHICKEN1, - GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE); + wa_mcr_masked_en(wal, GEN8_HALF_SLICE_CHICKEN1, + GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE); } static void glk_ctx_workarounds_init(struct intel_engine_cs *engine, @@ -514,8 +566,8 @@ static void cfl_ctx_workarounds_init(struct intel_engine_cs *engine, GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION); /* WaDisableSbeCacheDispatchPortSharing:cfl */ - wa_masked_en(wal, GEN8_HALF_SLICE_CHICKEN1, - GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE); + wa_mcr_masked_en(wal, GEN8_HALF_SLICE_CHICKEN1, + GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE); } static void icl_ctx_workarounds_init(struct intel_engine_cs *engine, @@ -534,13 +586,13 @@ static void icl_ctx_workarounds_init(struct intel_engine_cs *engine, * (the register is whitelisted in hardware now, so UMDs can opt in * for coherency if they have a good reason). */ - wa_masked_en(wal, ICL_HDC_MODE, HDC_FORCE_NON_COHERENT); + wa_mcr_masked_en(wal, ICL_HDC_MODE, HDC_FORCE_NON_COHERENT); /* WaEnableFloatBlendOptimization:icl */ - wa_add(wal, GEN10_CACHE_MODE_SS, 0, - _MASKED_BIT_ENABLE(FLOAT_BLEND_OPTIMIZATION_ENABLE), - 0 /* write-only, so skip validation */, - true); + wa_mcr_add(wal, GEN10_CACHE_MODE_SS, 0, + _MASKED_BIT_ENABLE(FLOAT_BLEND_OPTIMIZATION_ENABLE), + 0 /* write-only, so skip validation */, + true); /* WaDisableGPGPUMidThreadPreemption:icl */ wa_masked_field_set(wal, GEN8_CS_CHICKEN1, @@ -548,8 +600,8 @@ static void icl_ctx_workarounds_init(struct intel_engine_cs *engine, GEN9_PREEMPT_GPGPU_THREAD_GROUP_LEVEL); /* allow headerless messages for preemptible GPGPU context */ - wa_masked_en(wal, GEN10_SAMPLER_MODE, - GEN11_SAMPLER_ENABLE_HEADLESS_MSG); + wa_mcr_masked_en(wal, GEN10_SAMPLER_MODE, + GEN11_SAMPLER_ENABLE_HEADLESS_MSG); /* Wa_1604278689:icl,ehl */ wa_write(wal, IVB_FBC_RT_BASE, 0xFFFFFFFF & ~ILK_FBC_RT_VALID); @@ -558,7 +610,7 @@ static void icl_ctx_workarounds_init(struct intel_engine_cs *engine, 0xFFFFFFFF); /* Wa_1406306137:icl,ehl */ - wa_masked_en(wal, GEN9_ROW_CHICKEN4, GEN11_DIS_PICK_2ND_EU); + wa_mcr_masked_en(wal, GEN9_ROW_CHICKEN4, GEN11_DIS_PICK_2ND_EU); } /* @@ -569,13 +621,13 @@ static void dg2_ctx_gt_tuning_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) { wa_masked_en(wal, CHICKEN_RASTER_2, TBIMR_FAST_CLIP); - wa_write_clr_set(wal, XEHP_L3SQCREG5, L3_PWM_TIMER_INIT_VAL_MASK, - REG_FIELD_PREP(L3_PWM_TIMER_INIT_VAL_MASK, 0x7f)); - wa_add(wal, - XEHP_FF_MODE2, - FF_MODE2_TDS_TIMER_MASK, - FF_MODE2_TDS_TIMER_128, - 0, false); + wa_mcr_write_clr_set(wal, XEHP_L3SQCREG5, L3_PWM_TIMER_INIT_VAL_MASK, + REG_FIELD_PREP(L3_PWM_TIMER_INIT_VAL_MASK, 0x7f)); + wa_mcr_add(wal, + XEHP_FF_MODE2, + FF_MODE2_TDS_TIMER_MASK, + FF_MODE2_TDS_TIMER_128, + 0, false); } /* @@ -664,27 +716,27 @@ static void dg2_ctx_workarounds_init(struct intel_engine_cs *engine, /* Wa_16011186671:dg2_g11 */ if (IS_DG2_GRAPHICS_STEP(engine->i915, G11, STEP_A0, STEP_B0)) { - wa_masked_dis(wal, VFLSKPD, DIS_MULT_MISS_RD_SQUASH); - wa_masked_en(wal, VFLSKPD, DIS_OVER_FETCH_CACHE); + wa_mcr_masked_dis(wal, VFLSKPD, DIS_MULT_MISS_RD_SQUASH); + wa_mcr_masked_en(wal, VFLSKPD, DIS_OVER_FETCH_CACHE); } if (IS_DG2_GRAPHICS_STEP(engine->i915, G10, STEP_A0, STEP_B0)) { /* Wa_14010469329:dg2_g10 */ - wa_masked_en(wal, XEHP_COMMON_SLICE_CHICKEN3, - XEHP_DUAL_SIMD8_SEQ_MERGE_DISABLE); + wa_mcr_masked_en(wal, XEHP_COMMON_SLICE_CHICKEN3, + XEHP_DUAL_SIMD8_SEQ_MERGE_DISABLE); /* * Wa_22010465075:dg2_g10 * Wa_22010613112:dg2_g10 * Wa_14010698770:dg2_g10 */ - wa_masked_en(wal, XEHP_COMMON_SLICE_CHICKEN3, - GEN12_DISABLE_CPS_AWARE_COLOR_PIPE); + wa_mcr_masked_en(wal, XEHP_COMMON_SLICE_CHICKEN3, + GEN12_DISABLE_CPS_AWARE_COLOR_PIPE); } /* Wa_16013271637:dg2 */ - wa_masked_en(wal, XEHP_SLICE_COMMON_ECO_CHICKEN1, - MSC_MSAA_REODER_BUF_BYPASS_DISABLE); + wa_mcr_masked_en(wal, XEHP_SLICE_COMMON_ECO_CHICKEN1, + MSC_MSAA_REODER_BUF_BYPASS_DISABLE); /* Wa_14014947963:dg2 */ if (IS_DG2_GRAPHICS_STEP(engine->i915, G10, STEP_B0, STEP_FOREVER) || @@ -1264,9 +1316,9 @@ icl_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) PSDUNIT_CLKGATE_DIS); /* Wa_1406680159:icl,ehl */ - wa_write_or(wal, - GEN11_SUBSLICE_UNIT_LEVEL_CLKGATE, - GWUNIT_CLKGATE_DIS); + wa_mcr_write_or(wal, + GEN11_SUBSLICE_UNIT_LEVEL_CLKGATE, + GWUNIT_CLKGATE_DIS); /* Wa_1607087056:icl,ehl,jsl */ if (IS_ICELAKE(i915) || @@ -1279,7 +1331,7 @@ icl_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) * This is not a documented workaround, but rather an optimization * to reduce sampler power. */ - wa_write_clr(wal, GEN10_DFR_RATIO_EN_AND_CHICKEN, DFR_DISABLE); + wa_mcr_write_clr(wal, GEN10_DFR_RATIO_EN_AND_CHICKEN, DFR_DISABLE); } /* @@ -1313,7 +1365,7 @@ gen12_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) wa_14011060649(gt, wal); /* Wa_14011059788:tgl,rkl,adl-s,dg1,adl-p */ - wa_write_or(wal, GEN10_DFR_RATIO_EN_AND_CHICKEN, DFR_DISABLE); + wa_mcr_write_or(wal, GEN10_DFR_RATIO_EN_AND_CHICKEN, DFR_DISABLE); } static void @@ -1325,9 +1377,9 @@ tgl_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) /* Wa_1409420604:tgl */ if (IS_TGL_UY_GRAPHICS_STEP(i915, STEP_A0, STEP_B0)) - wa_write_or(wal, - SUBSLICE_UNIT_LEVEL_CLKGATE2, - CPSSUNIT_CLKGATE_DIS); + wa_mcr_write_or(wal, + SUBSLICE_UNIT_LEVEL_CLKGATE2, + CPSSUNIT_CLKGATE_DIS); /* Wa_1607087056:tgl also know as BUG:1409180338 */ if (IS_TGL_UY_GRAPHICS_STEP(i915, STEP_A0, STEP_B0)) @@ -1356,9 +1408,9 @@ dg1_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) /* Wa_1409420604:dg1 */ if (IS_DG1(i915)) - wa_write_or(wal, - SUBSLICE_UNIT_LEVEL_CLKGATE2, - CPSSUNIT_CLKGATE_DIS); + wa_mcr_write_or(wal, + SUBSLICE_UNIT_LEVEL_CLKGATE2, + CPSSUNIT_CLKGATE_DIS); /* Wa_1408615072:dg1 */ /* Empirical testing shows this register is unaffected by engine reset. */ @@ -1375,7 +1427,7 @@ xehpsdv_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) xehp_init_mcr(gt, wal); /* Wa_1409757795:xehpsdv */ - wa_write_or(wal, SCCGCTL94DC, CG3DDISURB); + wa_mcr_write_or(wal, SCCGCTL94DC, CG3DDISURB); /* Wa_16011155590:xehpsdv */ if (IS_XEHPSDV_GRAPHICS_STEP(i915, STEP_A0, STEP_B0)) @@ -1455,8 +1507,8 @@ dg2_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) CG3DDISCFEG_CLKGATE_DIS); /* Wa_14011006942:dg2 */ - wa_write_or(wal, GEN11_SUBSLICE_UNIT_LEVEL_CLKGATE, - DSS_ROUTER_CLKGATE_DIS); + wa_mcr_write_or(wal, GEN11_SUBSLICE_UNIT_LEVEL_CLKGATE, + DSS_ROUTER_CLKGATE_DIS); } if (IS_DG2_GRAPHICS_STEP(gt->i915, G10, STEP_A0, STEP_B0)) { @@ -1467,7 +1519,7 @@ dg2_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) wa_write_or(wal, UNSLCGCTL9444, LTCDD_CLKGATE_DIS); /* Wa_14011371254:dg2_g10 */ - wa_write_or(wal, XEHP_SLICE_UNIT_LEVEL_CLKGATE, NODEDSS_CLKGATE_DIS); + wa_mcr_write_or(wal, XEHP_SLICE_UNIT_LEVEL_CLKGATE, NODEDSS_CLKGATE_DIS); /* Wa_14011431319:dg2_g10 */ wa_write_or(wal, UNSLCGCTL9440, GAMTLBOACS_CLKGATE_DIS | @@ -1503,21 +1555,21 @@ dg2_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) GAMEDIA_CLKGATE_DIS); /* Wa_14011028019:dg2_g10 */ - wa_write_or(wal, SSMCGCTL9530, RTFUNIT_CLKGATE_DIS); + wa_mcr_write_or(wal, SSMCGCTL9530, RTFUNIT_CLKGATE_DIS); } /* Wa_14014830051:dg2 */ - wa_write_clr(wal, SARB_CHICKEN1, COMP_CKN_IN); + wa_mcr_write_clr(wal, SARB_CHICKEN1, COMP_CKN_IN); /* * The following are not actually "workarounds" but rather * recommended tuning settings documented in the bspec's * performance guide section. */ - wa_write_or(wal, XEHP_SQCM, EN_32B_ACCESS); + wa_mcr_write_or(wal, XEHP_SQCM, EN_32B_ACCESS); /* Wa_14015795083 */ - wa_write_clr(wal, GEN8_MISCCPCTL, GEN12_DOP_CLOCK_GATE_RENDER_ENABLE); + wa_mcr_write_clr(wal, GEN8_MISCCPCTL, GEN12_DOP_CLOCK_GATE_RENDER_ENABLE); } static void @@ -1526,7 +1578,7 @@ pvc_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) pvc_init_mcr(gt, wal); /* Wa_14015795083 */ - wa_write_clr(wal, GEN8_MISCCPCTL, GEN12_DOP_CLOCK_GATE_RENDER_ENABLE); + wa_mcr_write_clr(wal, GEN8_MISCCPCTL, GEN12_DOP_CLOCK_GATE_RENDER_ENABLE); } static void @@ -1638,14 +1690,25 @@ wa_list_apply(struct intel_gt *gt, const struct i915_wa_list *wal) u32 val, old = 0; /* open-coded rmw due to steering */ - old = wa->clr ? intel_gt_mcr_read_any_fw(gt, wa->reg) : 0; + if (wa->clr) + old = wa->is_mcr ? + intel_gt_mcr_read_any_fw(gt, wa->reg) : + intel_uncore_read_fw(uncore, wa->reg); val = (old & ~wa->clr) | wa->set; - if (val != old || !wa->clr) - intel_uncore_write_fw(uncore, wa->reg, val); + if (val != old || !wa->clr) { + if (wa->is_mcr) + intel_gt_mcr_multicast_write_fw(gt, wa->reg, val); + else + intel_uncore_write_fw(uncore, wa->reg, val); + } + + if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)) { + u32 val = wa->is_mcr ? + intel_gt_mcr_read_any_fw(gt, wa->reg) : + intel_uncore_read_fw(uncore, wa->reg); - if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)) - wa_verify(wa, intel_gt_mcr_read_any_fw(gt, wa->reg), - wal->name, "application"); + wa_verify(wa, val, wal->name, "application"); + } } intel_uncore_forcewake_put__locked(uncore, fw); @@ -1674,8 +1737,9 @@ static bool wa_list_verify(struct intel_gt *gt, intel_uncore_forcewake_get__locked(uncore, fw); for (i = 0, wa = wal->list; i < wal->count; i++, wa++) - ok &= wa_verify(wa, - intel_gt_mcr_read_any_fw(gt, wa->reg), + ok &= wa_verify(wa, wa->is_mcr ? + intel_gt_mcr_read_any_fw(gt, wa->reg) : + intel_uncore_read_fw(uncore, wa->reg), wal->name, from); intel_uncore_forcewake_put__locked(uncore, fw); @@ -1721,12 +1785,36 @@ whitelist_reg_ext(struct i915_wa_list *wal, i915_reg_t reg, u32 flags) _wa_add(wal, &wa); } +static void +whitelist_mcr_reg_ext(struct i915_wa_list *wal, i915_reg_t reg, u32 flags) +{ + struct i915_wa wa = { + .reg = reg, + .is_mcr = 1, + }; + + if (GEM_DEBUG_WARN_ON(wal->count >= RING_MAX_NONPRIV_SLOTS)) + return; + + if (GEM_DEBUG_WARN_ON(!is_nonpriv_flags_valid(flags))) + return; + + wa.reg.reg |= flags; + _wa_add(wal, &wa); +} + static void whitelist_reg(struct i915_wa_list *wal, i915_reg_t reg) { whitelist_reg_ext(wal, reg, RING_FORCE_TO_NONPRIV_ACCESS_RW); } +static void +whitelist_mcr_reg(struct i915_wa_list *wal, i915_reg_t reg) +{ + whitelist_mcr_reg_ext(wal, reg, RING_FORCE_TO_NONPRIV_ACCESS_RW); +} + static void gen9_whitelist_build(struct i915_wa_list *w) { /* WaVFEStateAfterPipeControlwithMediaStateClear:skl,bxt,glk,cfl */ @@ -1752,7 +1840,7 @@ static void skl_whitelist_build(struct intel_engine_cs *engine) gen9_whitelist_build(w); /* WaDisableLSQCROPERFforOCL:skl */ - whitelist_reg(w, GEN8_L3SQCREG4); + whitelist_mcr_reg(w, GEN8_L3SQCREG4); } static void bxt_whitelist_build(struct intel_engine_cs *engine) @@ -1773,7 +1861,7 @@ static void kbl_whitelist_build(struct intel_engine_cs *engine) gen9_whitelist_build(w); /* WaDisableLSQCROPERFforOCL:kbl */ - whitelist_reg(w, GEN8_L3SQCREG4); + whitelist_mcr_reg(w, GEN8_L3SQCREG4); } static void glk_whitelist_build(struct intel_engine_cs *engine) @@ -1838,10 +1926,10 @@ static void icl_whitelist_build(struct intel_engine_cs *engine) switch (engine->class) { case RENDER_CLASS: /* WaAllowUMDToModifyHalfSliceChicken7:icl */ - whitelist_reg(w, GEN9_HALF_SLICE_CHICKEN7); + whitelist_mcr_reg(w, GEN9_HALF_SLICE_CHICKEN7); /* WaAllowUMDToModifySamplerMode:icl */ - whitelist_reg(w, GEN10_SAMPLER_MODE); + whitelist_mcr_reg(w, GEN10_SAMPLER_MODE); /* WaEnableStateCacheRedirectToCS:icl */ whitelist_reg(w, GEN9_SLICE_COMMON_ECO_CHICKEN1); @@ -2117,21 +2205,21 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) if (IS_DG2_GRAPHICS_STEP(i915, G11, STEP_A0, STEP_B0)) { /* Wa_14013392000:dg2_g11 */ - wa_masked_en(wal, GEN8_ROW_CHICKEN2, GEN12_ENABLE_LARGE_GRF_MODE); + wa_mcr_masked_en(wal, GEN8_ROW_CHICKEN2, GEN12_ENABLE_LARGE_GRF_MODE); } if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_B0, STEP_FOREVER) || IS_DG2_G11(i915) || IS_DG2_G12(i915)) { /* Wa_1509727124:dg2 */ - wa_masked_en(wal, GEN10_SAMPLER_MODE, - SC_DISABLE_POWER_OPTIMIZATION_EBB); + wa_mcr_masked_en(wal, GEN10_SAMPLER_MODE, + SC_DISABLE_POWER_OPTIMIZATION_EBB); } if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_A0, STEP_B0) || IS_DG2_GRAPHICS_STEP(i915, G11, STEP_A0, STEP_B0)) { /* Wa_14012419201:dg2 */ - wa_masked_en(wal, GEN9_ROW_CHICKEN4, - GEN12_DISABLE_HDR_PAST_PAYLOAD_HOLD_FIX); + wa_mcr_masked_en(wal, GEN9_ROW_CHICKEN4, + GEN12_DISABLE_HDR_PAST_PAYLOAD_HOLD_FIX); } if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_B0, STEP_C0) || @@ -2140,13 +2228,13 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) * Wa_22012826095:dg2 * Wa_22013059131:dg2 */ - wa_write_clr_set(wal, LSC_CHICKEN_BIT_0_UDW, - MAXREQS_PER_BANK, - REG_FIELD_PREP(MAXREQS_PER_BANK, 2)); + wa_mcr_write_clr_set(wal, LSC_CHICKEN_BIT_0_UDW, + MAXREQS_PER_BANK, + REG_FIELD_PREP(MAXREQS_PER_BANK, 2)); /* Wa_22013059131:dg2 */ - wa_write_or(wal, LSC_CHICKEN_BIT_0, - FORCE_1_SUB_MESSAGE_PER_FRAGMENT); + wa_mcr_write_or(wal, LSC_CHICKEN_BIT_0, + FORCE_1_SUB_MESSAGE_PER_FRAGMENT); } /* Wa_1308578152:dg2_g10 when first gslice is fused off */ @@ -2159,19 +2247,19 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_B0, STEP_FOREVER) || IS_DG2_G11(i915) || IS_DG2_G12(i915)) { /* Wa_22013037850:dg2 */ - wa_write_or(wal, LSC_CHICKEN_BIT_0_UDW, - DISABLE_128B_EVICTION_COMMAND_UDW); + wa_mcr_write_or(wal, LSC_CHICKEN_BIT_0_UDW, + DISABLE_128B_EVICTION_COMMAND_UDW); /* Wa_22012856258:dg2 */ - wa_masked_en(wal, GEN8_ROW_CHICKEN2, - GEN12_DISABLE_READ_SUPPRESSION); + wa_mcr_masked_en(wal, GEN8_ROW_CHICKEN2, + GEN12_DISABLE_READ_SUPPRESSION); /* * Wa_22010960976:dg2 * Wa_14013347512:dg2 */ - wa_masked_dis(wal, XEHP_HDC_CHICKEN0, - LSC_L1_FLUSH_CTL_3D_DATAPORT_FLUSH_EVENTS_MASK); + wa_mcr_masked_dis(wal, XEHP_HDC_CHICKEN0, + LSC_L1_FLUSH_CTL_3D_DATAPORT_FLUSH_EVENTS_MASK); } if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_A0, STEP_B0)) { @@ -2179,8 +2267,8 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) * Wa_1608949956:dg2_g10 * Wa_14010198302:dg2_g10 */ - wa_masked_en(wal, GEN8_ROW_CHICKEN, - MDQ_ARBITRATION_MODE | UGM_BACKUP_MODE); + wa_mcr_masked_en(wal, GEN8_ROW_CHICKEN, + MDQ_ARBITRATION_MODE | UGM_BACKUP_MODE); /* * Wa_14010918519:dg2_g10 @@ -2188,31 +2276,31 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) * LSC_CHICKEN_BIT_0 always reads back as 0 is this stepping, * so ignoring verification. */ - wa_add(wal, LSC_CHICKEN_BIT_0_UDW, 0, - FORCE_SLM_FENCE_SCOPE_TO_TILE | FORCE_UGM_FENCE_SCOPE_TO_TILE, - 0, false); + wa_mcr_add(wal, LSC_CHICKEN_BIT_0_UDW, 0, + FORCE_SLM_FENCE_SCOPE_TO_TILE | FORCE_UGM_FENCE_SCOPE_TO_TILE, + 0, false); } if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_A0, STEP_B0)) { /* Wa_22010430635:dg2 */ - wa_masked_en(wal, - GEN9_ROW_CHICKEN4, - GEN12_DISABLE_GRF_CLEAR); + wa_mcr_masked_en(wal, + GEN9_ROW_CHICKEN4, + GEN12_DISABLE_GRF_CLEAR); /* Wa_14010648519:dg2 */ - wa_write_or(wal, XEHP_L3NODEARBCFG, XEHP_LNESPARE); + wa_mcr_write_or(wal, XEHP_L3NODEARBCFG, XEHP_LNESPARE); } /* Wa_14013202645:dg2 */ if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_B0, STEP_C0) || IS_DG2_GRAPHICS_STEP(i915, G11, STEP_A0, STEP_B0)) - wa_write_or(wal, RT_CTRL, DIS_NULL_QUERY); + wa_mcr_write_or(wal, RT_CTRL, DIS_NULL_QUERY); /* Wa_22012532006:dg2 */ if (IS_DG2_GRAPHICS_STEP(engine->i915, G10, STEP_A0, STEP_C0) || IS_DG2_GRAPHICS_STEP(engine->i915, G11, STEP_A0, STEP_B0)) - wa_masked_en(wal, GEN9_HALF_SLICE_CHICKEN7, - DG2_DISABLE_ROUND_ENABLE_ALLOW_FOR_SSLA); + wa_mcr_masked_en(wal, GEN9_HALF_SLICE_CHICKEN7, + DG2_DISABLE_ROUND_ENABLE_ALLOW_FOR_SSLA); if (IS_DG2_GRAPHICS_STEP(engine->i915, G10, STEP_A0, STEP_B0)) { /* Wa_14010680813:dg2_g10 */ @@ -2223,17 +2311,16 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) if (IS_DG2_GRAPHICS_STEP(engine->i915, G10, STEP_A0, STEP_B0) || IS_DG2_GRAPHICS_STEP(engine->i915, G11, STEP_A0, STEP_B0)) { /* Wa_14012362059:dg2 */ - wa_write_or(wal, XEHP_MERT_MOD_CTRL, FORCE_MISS_FTLB); + wa_mcr_write_or(wal, XEHP_MERT_MOD_CTRL, FORCE_MISS_FTLB); } if (IS_DG2_GRAPHICS_STEP(i915, G11, STEP_B0, STEP_FOREVER) || IS_DG2_G10(i915)) { /* Wa_22014600077:dg2 */ - wa_add(wal, GEN10_CACHE_MODE_SS, 0, - _MASKED_BIT_ENABLE(ENABLE_EU_COUNT_FOR_TDL_FLUSH), - 0 /* Wa_14012342262 :write-only reg, so skip - verification */, - true); + wa_mcr_add(wal, GEN10_CACHE_MODE_SS, 0, + _MASKED_BIT_ENABLE(ENABLE_EU_COUNT_FOR_TDL_FLUSH), + 0 /* Wa_14012342262 write-only reg, so skip verification */, + true); } if (IS_DG1_GRAPHICS_STEP(i915, STEP_A0, STEP_B0) || @@ -2260,7 +2347,7 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) if (IS_ALDERLAKE_P(i915) || IS_ALDERLAKE_S(i915) || IS_DG1(i915) || IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915)) { /* Wa_1606931601:tgl,rkl,dg1,adl-s,adl-p */ - wa_masked_en(wal, GEN8_ROW_CHICKEN2, GEN12_DISABLE_EARLY_READ); + wa_mcr_masked_en(wal, GEN8_ROW_CHICKEN2, GEN12_DISABLE_EARLY_READ); /* * Wa_1407928979:tgl A* @@ -2289,14 +2376,14 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) IS_DG1_GRAPHICS_STEP(i915, STEP_A0, STEP_B0) || IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915)) { /* Wa_1409804808:tgl,rkl,dg1[a0],adl-s,adl-p */ - wa_masked_en(wal, GEN8_ROW_CHICKEN2, - GEN12_PUSH_CONST_DEREF_HOLD_DIS); + wa_mcr_masked_en(wal, GEN8_ROW_CHICKEN2, + GEN12_PUSH_CONST_DEREF_HOLD_DIS); /* * Wa_1409085225:tgl * Wa_14010229206:tgl,rkl,dg1[a0],adl-s,adl-p */ - wa_masked_en(wal, GEN9_ROW_CHICKEN4, GEN12_DISABLE_TDL_PUSH); + wa_mcr_masked_en(wal, GEN9_ROW_CHICKEN4, GEN12_DISABLE_TDL_PUSH); } if (IS_DG1_GRAPHICS_STEP(i915, STEP_A0, STEP_B0) || @@ -2320,9 +2407,9 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) if (IS_DG1(i915) || IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915) || IS_ALDERLAKE_S(i915) || IS_ALDERLAKE_P(i915)) { /* Wa_1406941453:tgl,rkl,dg1,adl-s,adl-p */ - wa_masked_en(wal, - GEN10_SAMPLER_MODE, - ENABLE_SMALLPL); + wa_mcr_masked_en(wal, + GEN10_SAMPLER_MODE, + ENABLE_SMALLPL); } if (GRAPHICS_VER(i915) == 11) { @@ -2356,9 +2443,9 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) * Wa_1405733216:icl * Formerly known as WaDisableCleanEvicts */ - wa_write_or(wal, - GEN8_L3SQCREG4, - GEN11_LQSC_CLEAN_EVICT_DISABLE); + wa_mcr_write_or(wal, + GEN8_L3SQCREG4, + GEN11_LQSC_CLEAN_EVICT_DISABLE); /* Wa_1606682166:icl */ wa_write_or(wal, @@ -2366,10 +2453,10 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) GEN7_DISABLE_SAMPLER_PREFETCH); /* Wa_1409178092:icl */ - wa_write_clr_set(wal, - GEN11_SCRATCH2, - GEN11_COHERENT_PARTIAL_WRITE_MERGE_ENABLE, - 0); + wa_mcr_write_clr_set(wal, + GEN11_SCRATCH2, + GEN11_COHERENT_PARTIAL_WRITE_MERGE_ENABLE, + 0); /* WaEnable32PlaneMode:icl */ wa_masked_en(wal, GEN9_CSFE_CHICKEN1_RCS, @@ -2479,30 +2566,30 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) GEN9_PREEMPT_GPGPU_SYNC_SWITCH_DISABLE); /* WaEnableLbsSlaRetryTimerDecrement:skl,bxt,kbl,glk,cfl */ - wa_write_or(wal, - BDW_SCRATCH1, - GEN9_LBS_SLA_RETRY_TIMER_DECREMENT_ENABLE); + wa_mcr_write_or(wal, + BDW_SCRATCH1, + GEN9_LBS_SLA_RETRY_TIMER_DECREMENT_ENABLE); /* WaProgramL3SqcReg1DefaultForPerf:bxt,glk */ if (IS_GEN9_LP(i915)) - wa_write_clr_set(wal, - GEN8_L3SQCREG1, - L3_PRIO_CREDITS_MASK, - L3_GENERAL_PRIO_CREDITS(62) | - L3_HIGH_PRIO_CREDITS(2)); + wa_mcr_write_clr_set(wal, + GEN8_L3SQCREG1, + L3_PRIO_CREDITS_MASK, + L3_GENERAL_PRIO_CREDITS(62) | + L3_HIGH_PRIO_CREDITS(2)); /* WaOCLCoherentLineFlush:skl,bxt,kbl,cfl */ - wa_write_or(wal, - GEN8_L3SQCREG4, - GEN8_LQSC_FLUSH_COHERENT_LINES); + wa_mcr_write_or(wal, + GEN8_L3SQCREG4, + GEN8_LQSC_FLUSH_COHERENT_LINES); /* Disable atomics in L3 to prevent unrecoverable hangs */ wa_write_clr_set(wal, GEN9_SCRATCH_LNCF1, GEN9_LNCF_NONIA_COHERENT_ATOMICS_ENABLE, 0); - wa_write_clr_set(wal, GEN8_L3SQCREG4, - GEN8_LQSQ_NONIA_COHERENT_ATOMICS_ENABLE, 0); - wa_write_clr_set(wal, GEN9_SCRATCH1, - EVICTION_PERF_FIX_ENABLE, 0); + wa_mcr_write_clr_set(wal, GEN8_L3SQCREG4, + GEN8_LQSQ_NONIA_COHERENT_ATOMICS_ENABLE, 0); + wa_mcr_write_clr_set(wal, GEN9_SCRATCH1, + EVICTION_PERF_FIX_ENABLE, 0); } if (IS_HASWELL(i915)) { @@ -2716,7 +2803,7 @@ ccs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) { if (IS_PVC_CT_STEP(engine->i915, STEP_A0, STEP_C0)) { /* Wa_14014999345:pvc */ - wa_masked_en(wal, GEN10_CACHE_MODE_SS, DISABLE_ECC); + wa_mcr_masked_en(wal, GEN10_CACHE_MODE_SS, DISABLE_ECC); } } @@ -2742,8 +2829,8 @@ add_render_compute_tuning_settings(struct drm_i915_private *i915, } if (IS_DG2(i915)) { - wa_write_or(wal, XEHP_L3SCQREG7, BLEND_FILL_CACHING_OPT_DIS); - wa_write_clr_set(wal, RT_CTRL, STACKID_CTRL, STACKID_CTRL_512); + wa_mcr_write_or(wal, XEHP_L3SCQREG7, BLEND_FILL_CACHING_OPT_DIS); + wa_mcr_write_clr_set(wal, RT_CTRL, STACKID_CTRL, STACKID_CTRL_512); /* * This is also listed as Wa_22012654132 for certain DG2 @@ -2754,10 +2841,10 @@ add_render_compute_tuning_settings(struct drm_i915_private *i915, * back for verification on DG2 (due to Wa_14012342262), so * we need to explicitly skip the readback. */ - wa_add(wal, GEN10_CACHE_MODE_SS, 0, - _MASKED_BIT_ENABLE(ENABLE_PREFETCH_INTO_IC), - 0 /* write-only, so skip validation */, - true); + wa_mcr_add(wal, GEN10_CACHE_MODE_SS, 0, + _MASKED_BIT_ENABLE(ENABLE_PREFETCH_INTO_IC), + 0 /* write-only, so skip validation */, + true); } /* @@ -2766,8 +2853,8 @@ add_render_compute_tuning_settings(struct drm_i915_private *i915, * platforms. */ if (INTEL_INFO(i915)->tuning_thread_rr_after_dep) - wa_masked_field_set(wal, GEN9_ROW_CHICKEN4, THREAD_EX_ARB_MODE, - THREAD_EX_ARB_MODE_RR_AFTER_DEP); + wa_mcr_masked_field_set(wal, GEN9_ROW_CHICKEN4, THREAD_EX_ARB_MODE, + THREAD_EX_ARB_MODE_RR_AFTER_DEP); } /* @@ -2793,30 +2880,30 @@ general_render_compute_wa_init(struct intel_engine_cs *engine, struct i915_wa_li if (IS_XEHPSDV(i915)) { /* Wa_1409954639 */ - wa_masked_en(wal, - GEN8_ROW_CHICKEN, - SYSTOLIC_DOP_CLOCK_GATING_DIS); + wa_mcr_masked_en(wal, + GEN8_ROW_CHICKEN, + SYSTOLIC_DOP_CLOCK_GATING_DIS); /* Wa_1607196519 */ - wa_masked_en(wal, - GEN9_ROW_CHICKEN4, - GEN12_DISABLE_GRF_CLEAR); + wa_mcr_masked_en(wal, + GEN9_ROW_CHICKEN4, + GEN12_DISABLE_GRF_CLEAR); /* Wa_14010670810:xehpsdv */ - wa_write_or(wal, XEHP_L3NODEARBCFG, XEHP_LNESPARE); + wa_mcr_write_or(wal, XEHP_L3NODEARBCFG, XEHP_LNESPARE); /* Wa_14010449647:xehpsdv */ - wa_masked_en(wal, GEN8_HALF_SLICE_CHICKEN1, - GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE); + wa_mcr_masked_en(wal, GEN8_HALF_SLICE_CHICKEN1, + GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE); /* Wa_18011725039:xehpsdv */ if (IS_XEHPSDV_GRAPHICS_STEP(i915, STEP_A1, STEP_B0)) { - wa_masked_dis(wal, MLTICTXCTL, TDONRENDER); - wa_write_or(wal, L3SQCREG1_CCS0, FLUSHALLNONCOH); + wa_mcr_masked_dis(wal, MLTICTXCTL, TDONRENDER); + wa_mcr_write_or(wal, L3SQCREG1_CCS0, FLUSHALLNONCOH); } /* Wa_14012362059:xehpsdv */ - wa_write_or(wal, XEHP_MERT_MOD_CTRL, FORCE_MISS_FTLB); + wa_mcr_write_or(wal, XEHP_MERT_MOD_CTRL, FORCE_MISS_FTLB); /* Wa_14014368820:xehpsdv */ wa_write_or(wal, GEN12_GAMCNTRL_CTRL, INVALIDATION_BROADCAST_MODE_DIS | @@ -2825,19 +2912,19 @@ general_render_compute_wa_init(struct intel_engine_cs *engine, struct i915_wa_li if (IS_DG2(i915) || IS_PONTEVECCHIO(i915)) { /* Wa_14015227452:dg2,pvc */ - wa_masked_en(wal, GEN9_ROW_CHICKEN4, XEHP_DIS_BBL_SYSPIPE); + wa_mcr_masked_en(wal, GEN9_ROW_CHICKEN4, XEHP_DIS_BBL_SYSPIPE); /* Wa_22014226127:dg2,pvc */ - wa_write_or(wal, LSC_CHICKEN_BIT_0, DISABLE_D8_D16_COASLESCE); + wa_mcr_write_or(wal, LSC_CHICKEN_BIT_0, DISABLE_D8_D16_COASLESCE); /* Wa_16015675438:dg2,pvc */ wa_masked_en(wal, FF_SLICE_CS_CHICKEN2, GEN12_PERF_FIX_BALANCING_CFE_DISABLE); /* Wa_18018781329:dg2,pvc */ - wa_write_or(wal, RENDER_MOD_CTRL, FORCE_MISS_FTLB); - wa_write_or(wal, COMP_MOD_CTRL, FORCE_MISS_FTLB); - wa_write_or(wal, VDBX_MOD_CTRL, FORCE_MISS_FTLB); - wa_write_or(wal, VEBX_MOD_CTRL, FORCE_MISS_FTLB); + wa_mcr_write_or(wal, RENDER_MOD_CTRL, FORCE_MISS_FTLB); + wa_mcr_write_or(wal, COMP_MOD_CTRL, FORCE_MISS_FTLB); + wa_mcr_write_or(wal, VDBX_MOD_CTRL, FORCE_MISS_FTLB); + wa_mcr_write_or(wal, VEBX_MOD_CTRL, FORCE_MISS_FTLB); } if (IS_DG2(i915)) { @@ -2845,7 +2932,7 @@ general_render_compute_wa_init(struct intel_engine_cs *engine, struct i915_wa_li * Wa_16011620976:dg2_g11 * Wa_22015475538:dg2 */ - wa_write_or(wal, LSC_CHICKEN_BIT_0_UDW, DIS_CHAIN_2XSIMD8); + wa_mcr_write_or(wal, LSC_CHICKEN_BIT_0_UDW, DIS_CHAIN_2XSIMD8); } } diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds_types.h b/drivers/gpu/drm/i915/gt/intel_workarounds_types.h index 8a4b6de4e754..f05b37e56fa9 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds_types.h +++ b/drivers/gpu/drm/i915/gt/intel_workarounds_types.h @@ -15,7 +15,9 @@ struct i915_wa { u32 clr; u32 set; u32 read; - bool masked_reg; + + u32 masked_reg:1; + u32 is_mcr:1; }; struct i915_wa_list { -- cgit From 58bc2453ab8a4b5e1f2969e09c12ab69b8aaaf98 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Fri, 14 Oct 2022 16:02:37 -0700 Subject: drm/i915: Define multicast registers as a new type Rather than treating multicast registers as 'i915_reg_t' let's define them as a completely new type. This will allow the compiler to help us make sure we're using multicast-aware functions to operate on multicast registers. This plan does break down a bit in places where we're just maintaining heterogeneous lists of registers (e.g., various MMIO whitelists used by perf, GVT, etc.) rather than performing reads/writes. We only really care about the offset in those cases, so for now we can "cast" the registers as non-MCR, leaving us with a list of i915_reg_t's, but we may want to look for better ways to store mixed collections of i915_reg_t and i915_mcr_reg_t in the future. v2: - Add TLB invalidation registers v3: - Make type checking of i915_mmio_reg_offset() stricter. It will accept either i915_reg_t or i915_mcr_reg_t, but will now raise a compile error if any other type is passed, even if that type contains a 'reg' field. (Jani) - Drop a ton of GVT changes; allowing i915_mmio_reg_offset() to take either an i915_reg_t or an i915_mcr_reg_t means that the huge lists of MMIO_D*() macros used in GVT will continue to work without modification. We need only make changes to structures that have an explicit i915_reg_t in them now. Cc: Jani Nikula Signed-off-by: Matt Roper Reviewed-by: Balasubramani Vivekanandan Link: https://patchwork.freedesktop.org/patch/msgid/20221014230239.1023689-13-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/gt/intel_gt.c | 16 +++++-- drivers/gpu/drm/i915/gt/intel_gt_mcr.c | 51 ++++++++++++++--------- drivers/gpu/drm/i915/gt/intel_gt_mcr.h | 18 ++++---- drivers/gpu/drm/i915/gt/intel_gt_regs.h | 27 ++++++++---- drivers/gpu/drm/i915/gt/intel_workarounds.c | 32 +++++++------- drivers/gpu/drm/i915/gt/intel_workarounds_types.h | 5 ++- drivers/gpu/drm/i915/gt/selftest_workarounds.c | 2 +- drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c | 2 +- drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c | 4 +- drivers/gpu/drm/i915/gvt/handlers.c | 2 +- drivers/gpu/drm/i915/gvt/mmio_context.c | 14 +++---- drivers/gpu/drm/i915/i915_reg_defs.h | 27 ++++++------ 12 files changed, 117 insertions(+), 83 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c b/drivers/gpu/drm/i915/gt/intel_gt.c index 3df0d0336dbc..27dbb9e4bd6c 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt.c +++ b/drivers/gpu/drm/i915/gt/intel_gt.c @@ -991,7 +991,10 @@ void intel_gt_info_print(const struct intel_gt_info *info, } struct reg_and_bit { - i915_reg_t reg; + union { + i915_reg_t reg; + i915_mcr_reg_t mcr_reg; + }; u32 bit; }; @@ -1033,7 +1036,7 @@ get_reg_and_bit(const struct intel_engine_cs *engine, const bool gen8, static int wait_for_invalidate(struct intel_gt *gt, struct reg_and_bit rb) { if (GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 50)) - return intel_gt_mcr_wait_for_reg_fw(gt, rb.reg, rb.bit, 0, + return intel_gt_mcr_wait_for_reg_fw(gt, rb.mcr_reg, rb.bit, 0, TLB_INVAL_TIMEOUT_US, TLB_INVAL_TIMEOUT_MS); else @@ -1058,7 +1061,7 @@ static void mmio_invalidate_full(struct intel_gt *gt) [COPY_ENGINE_CLASS] = GEN12_BLT_TLB_INV_CR, [COMPUTE_CLASS] = GEN12_COMPCTX_TLB_INV_CR, }; - static const i915_reg_t xehp_regs[] = { + static const i915_mcr_reg_t xehp_regs[] = { [RENDER_CLASS] = XEHP_GFX_TLB_INV_CR, [VIDEO_DECODE_CLASS] = XEHP_VD_TLB_INV_CR, [VIDEO_ENHANCEMENT_CLASS] = XEHP_VE_TLB_INV_CR, @@ -1131,7 +1134,12 @@ static void mmio_invalidate_full(struct intel_gt *gt) for_each_engine_masked(engine, gt, awake, tmp) { struct reg_and_bit rb; - rb = get_reg_and_bit(engine, regs == gen8_regs, regs, num); + if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50)) { + rb.mcr_reg = xehp_regs[engine->class]; + rb.bit = BIT(engine->instance); + } else { + rb = get_reg_and_bit(engine, regs == gen8_regs, regs, num); + } if (wait_for_invalidate(gt, rb)) drm_err_ratelimited(>->i915->drm, diff --git a/drivers/gpu/drm/i915/gt/intel_gt_mcr.c b/drivers/gpu/drm/i915/gt/intel_gt_mcr.c index 1ed9bc4dccfd..349074bf365f 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_mcr.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_mcr.c @@ -150,6 +150,19 @@ void intel_gt_mcr_init(struct intel_gt *gt) } } +/* + * Although the rest of the driver should use MCR-specific functions to + * read/write MCR registers, we still use the regular intel_uncore_* functions + * internally to implement those, so we need a way for the functions in this + * file to "cast" an i915_mcr_reg_t into an i915_reg_t. + */ +static i915_reg_t mcr_reg_cast(const i915_mcr_reg_t mcr) +{ + i915_reg_t r = { .reg = mcr.reg }; + + return r; +} + /* * rw_with_mcr_steering_fw - Access a register with specific MCR steering * @uncore: pointer to struct intel_uncore @@ -164,7 +177,7 @@ void intel_gt_mcr_init(struct intel_gt *gt) * Caller needs to make sure the relevant forcewake wells are up. */ static u32 rw_with_mcr_steering_fw(struct intel_uncore *uncore, - i915_reg_t reg, u8 rw_flag, + i915_mcr_reg_t reg, u8 rw_flag, int group, int instance, u32 value) { u32 mcr_mask, mcr_ss, mcr, old_mcr, val = 0; @@ -201,9 +214,9 @@ static u32 rw_with_mcr_steering_fw(struct intel_uncore *uncore, intel_uncore_write_fw(uncore, GEN8_MCR_SELECTOR, mcr); if (rw_flag == FW_REG_READ) - val = intel_uncore_read_fw(uncore, reg); + val = intel_uncore_read_fw(uncore, mcr_reg_cast(reg)); else - intel_uncore_write_fw(uncore, reg, value); + intel_uncore_write_fw(uncore, mcr_reg_cast(reg), value); mcr &= ~mcr_mask; mcr |= old_mcr & mcr_mask; @@ -214,14 +227,14 @@ static u32 rw_with_mcr_steering_fw(struct intel_uncore *uncore, } static u32 rw_with_mcr_steering(struct intel_uncore *uncore, - i915_reg_t reg, u8 rw_flag, + i915_mcr_reg_t reg, u8 rw_flag, int group, int instance, u32 value) { enum forcewake_domains fw_domains; u32 val; - fw_domains = intel_uncore_forcewake_for_reg(uncore, reg, + fw_domains = intel_uncore_forcewake_for_reg(uncore, mcr_reg_cast(reg), rw_flag); fw_domains |= intel_uncore_forcewake_for_reg(uncore, GEN8_MCR_SELECTOR, @@ -249,7 +262,7 @@ static u32 rw_with_mcr_steering(struct intel_uncore *uncore, * group/instance. */ u32 intel_gt_mcr_read(struct intel_gt *gt, - i915_reg_t reg, + i915_mcr_reg_t reg, int group, int instance) { return rw_with_mcr_steering(gt->uncore, reg, FW_REG_READ, group, instance, 0); @@ -266,7 +279,7 @@ u32 intel_gt_mcr_read(struct intel_gt *gt, * Write an MCR register in unicast mode after steering toward a specific * group/instance. */ -void intel_gt_mcr_unicast_write(struct intel_gt *gt, i915_reg_t reg, u32 value, +void intel_gt_mcr_unicast_write(struct intel_gt *gt, i915_mcr_reg_t reg, u32 value, int group, int instance) { rw_with_mcr_steering(gt->uncore, reg, FW_REG_WRITE, group, instance, value); @@ -281,9 +294,9 @@ void intel_gt_mcr_unicast_write(struct intel_gt *gt, i915_reg_t reg, u32 value, * Write an MCR register in multicast mode to update all instances. */ void intel_gt_mcr_multicast_write(struct intel_gt *gt, - i915_reg_t reg, u32 value) + i915_mcr_reg_t reg, u32 value) { - intel_uncore_write(gt->uncore, reg, value); + intel_uncore_write(gt->uncore, mcr_reg_cast(reg), value); } /** @@ -297,9 +310,9 @@ void intel_gt_mcr_multicast_write(struct intel_gt *gt, * domains; use intel_gt_mcr_multicast_write() in cases where forcewake should * be obtained automatically. */ -void intel_gt_mcr_multicast_write_fw(struct intel_gt *gt, i915_reg_t reg, u32 value) +void intel_gt_mcr_multicast_write_fw(struct intel_gt *gt, i915_mcr_reg_t reg, u32 value) { - intel_uncore_write_fw(gt->uncore, reg, value); + intel_uncore_write_fw(gt->uncore, mcr_reg_cast(reg), value); } /** @@ -320,7 +333,7 @@ void intel_gt_mcr_multicast_write_fw(struct intel_gt *gt, i915_reg_t reg, u32 va * * Returns the old (unmodified) value read. */ -u32 intel_gt_mcr_multicast_rmw(struct intel_gt *gt, i915_reg_t reg, +u32 intel_gt_mcr_multicast_rmw(struct intel_gt *gt, i915_mcr_reg_t reg, u32 clear, u32 set) { u32 val = intel_gt_mcr_read_any(gt, reg); @@ -345,7 +358,7 @@ u32 intel_gt_mcr_multicast_rmw(struct intel_gt *gt, i915_reg_t reg, * for @type steering too. */ static bool reg_needs_read_steering(struct intel_gt *gt, - i915_reg_t reg, + i915_mcr_reg_t reg, enum intel_steering_type type) { const u32 offset = i915_mmio_reg_offset(reg); @@ -428,7 +441,7 @@ static void get_nonterminated_steering(struct intel_gt *gt, * steering. */ void intel_gt_mcr_get_nonterminated_steering(struct intel_gt *gt, - i915_reg_t reg, + i915_mcr_reg_t reg, u8 *group, u8 *instance) { int type; @@ -457,7 +470,7 @@ void intel_gt_mcr_get_nonterminated_steering(struct intel_gt *gt, * * Returns the value from a non-terminated instance of @reg. */ -u32 intel_gt_mcr_read_any_fw(struct intel_gt *gt, i915_reg_t reg) +u32 intel_gt_mcr_read_any_fw(struct intel_gt *gt, i915_mcr_reg_t reg) { int type; u8 group, instance; @@ -471,7 +484,7 @@ u32 intel_gt_mcr_read_any_fw(struct intel_gt *gt, i915_reg_t reg) } } - return intel_uncore_read_fw(gt->uncore, reg); + return intel_uncore_read_fw(gt->uncore, mcr_reg_cast(reg)); } /** @@ -484,7 +497,7 @@ u32 intel_gt_mcr_read_any_fw(struct intel_gt *gt, i915_reg_t reg) * * Returns the value from a non-terminated instance of @reg. */ -u32 intel_gt_mcr_read_any(struct intel_gt *gt, i915_reg_t reg) +u32 intel_gt_mcr_read_any(struct intel_gt *gt, i915_mcr_reg_t reg) { int type; u8 group, instance; @@ -498,7 +511,7 @@ u32 intel_gt_mcr_read_any(struct intel_gt *gt, i915_reg_t reg) } } - return intel_uncore_read(gt->uncore, reg); + return intel_uncore_read(gt->uncore, mcr_reg_cast(reg)); } static void report_steering_type(struct drm_printer *p, @@ -599,7 +612,7 @@ void intel_gt_mcr_get_ss_steering(struct intel_gt *gt, unsigned int dss, * Return: 0 if the register matches the desired condition, or -ETIMEDOUT. */ int intel_gt_mcr_wait_for_reg_fw(struct intel_gt *gt, - i915_reg_t reg, + i915_mcr_reg_t reg, u32 mask, u32 value, unsigned int fast_timeout_us, diff --git a/drivers/gpu/drm/i915/gt/intel_gt_mcr.h b/drivers/gpu/drm/i915/gt/intel_gt_mcr.h index 548f922cd9fa..3fb0502bff22 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_mcr.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_mcr.h @@ -11,24 +11,24 @@ void intel_gt_mcr_init(struct intel_gt *gt); u32 intel_gt_mcr_read(struct intel_gt *gt, - i915_reg_t reg, + i915_mcr_reg_t reg, int group, int instance); -u32 intel_gt_mcr_read_any_fw(struct intel_gt *gt, i915_reg_t reg); -u32 intel_gt_mcr_read_any(struct intel_gt *gt, i915_reg_t reg); +u32 intel_gt_mcr_read_any_fw(struct intel_gt *gt, i915_mcr_reg_t reg); +u32 intel_gt_mcr_read_any(struct intel_gt *gt, i915_mcr_reg_t reg); void intel_gt_mcr_unicast_write(struct intel_gt *gt, - i915_reg_t reg, u32 value, + i915_mcr_reg_t reg, u32 value, int group, int instance); void intel_gt_mcr_multicast_write(struct intel_gt *gt, - i915_reg_t reg, u32 value); + i915_mcr_reg_t reg, u32 value); void intel_gt_mcr_multicast_write_fw(struct intel_gt *gt, - i915_reg_t reg, u32 value); + i915_mcr_reg_t reg, u32 value); -u32 intel_gt_mcr_multicast_rmw(struct intel_gt *gt, i915_reg_t reg, +u32 intel_gt_mcr_multicast_rmw(struct intel_gt *gt, i915_mcr_reg_t reg, u32 clear, u32 set); void intel_gt_mcr_get_nonterminated_steering(struct intel_gt *gt, - i915_reg_t reg, + i915_mcr_reg_t reg, u8 *group, u8 *instance); void intel_gt_mcr_report_steering(struct drm_printer *p, struct intel_gt *gt, @@ -38,7 +38,7 @@ void intel_gt_mcr_get_ss_steering(struct intel_gt *gt, unsigned int dss, unsigned int *group, unsigned int *instance); int intel_gt_mcr_wait_for_reg_fw(struct intel_gt *gt, - i915_reg_t reg, + i915_mcr_reg_t reg, u32 mask, u32 value, unsigned int fast_timeout_us, diff --git a/drivers/gpu/drm/i915/gt/intel_gt_regs.h b/drivers/gpu/drm/i915/gt/intel_gt_regs.h index bd2bbacf2386..1116bc3dba51 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_regs.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_regs.h @@ -8,7 +8,18 @@ #include "i915_reg_defs.h" -#define MCR_REG(offset) _MMIO(offset) +#define MCR_REG(offset) ((const i915_mcr_reg_t){ .reg = (offset) }) + +/* + * The perf control registers are technically multicast registers, but the + * driver never needs to read/write them directly; we only use them to build + * lists of registers (where they're mixed in with other non-MCR registers) + * and then operate on the offset directly. For now we'll just define them + * as non-multicast so we can place them on the same list, but we may want + * to try to come up with a better way to handle heterogeneous lists of + * registers in the future. + */ +#define PERF_REG(offset) _MMIO(offset) /* RPM unit config (Gen8+) */ #define RPM_CONFIG0 _MMIO(0xd00) @@ -1113,8 +1124,8 @@ #define FLOAT_BLEND_OPTIMIZATION_ENABLE REG_BIT(4) #define ENABLE_PREFETCH_INTO_IC REG_BIT(3) -#define EU_PERF_CNTL0 MCR_REG(0xe458) -#define EU_PERF_CNTL4 MCR_REG(0xe45c) +#define EU_PERF_CNTL0 PERF_REG(0xe458) +#define EU_PERF_CNTL4 PERF_REG(0xe45c) #define GEN9_ROW_CHICKEN4 MCR_REG(0xe48c) #define GEN12_DISABLE_GRF_CLEAR REG_BIT(13) @@ -1151,16 +1162,16 @@ #define STACKID_CTRL REG_GENMASK(6, 5) #define STACKID_CTRL_512 REG_FIELD_PREP(STACKID_CTRL, 0x2) -#define EU_PERF_CNTL1 MCR_REG(0xe558) -#define EU_PERF_CNTL5 MCR_REG(0xe55c) +#define EU_PERF_CNTL1 PERF_REG(0xe558) +#define EU_PERF_CNTL5 PERF_REG(0xe55c) #define XEHP_HDC_CHICKEN0 MCR_REG(0xe5f0) #define LSC_L1_FLUSH_CTL_3D_DATAPORT_FLUSH_EVENTS_MASK REG_GENMASK(13, 11) #define ICL_HDC_MODE MCR_REG(0xe5f4) -#define EU_PERF_CNTL2 MCR_REG(0xe658) -#define EU_PERF_CNTL6 MCR_REG(0xe65c) -#define EU_PERF_CNTL3 MCR_REG(0xe758) +#define EU_PERF_CNTL2 PERF_REG(0xe658) +#define EU_PERF_CNTL6 PERF_REG(0xe65c) +#define EU_PERF_CNTL3 PERF_REG(0xe758) #define LSC_CHICKEN_BIT_0 MCR_REG(0xe7c8) #define DISABLE_D8_D16_COASLESCE REG_BIT(30) diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c index 7671994d5b7a..dadb60e6a58f 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds.c +++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c @@ -166,11 +166,11 @@ static void wa_add(struct i915_wa_list *wal, i915_reg_t reg, _wa_add(wal, &wa); } -static void wa_mcr_add(struct i915_wa_list *wal, i915_reg_t reg, +static void wa_mcr_add(struct i915_wa_list *wal, i915_mcr_reg_t reg, u32 clear, u32 set, u32 read_mask, bool masked_reg) { struct i915_wa wa = { - .reg = reg, + .mcr_reg = reg, .clr = clear, .set = set, .read = read_mask, @@ -188,7 +188,7 @@ wa_write_clr_set(struct i915_wa_list *wal, i915_reg_t reg, u32 clear, u32 set) } static void -wa_mcr_write_clr_set(struct i915_wa_list *wal, i915_reg_t reg, u32 clear, u32 set) +wa_mcr_write_clr_set(struct i915_wa_list *wal, i915_mcr_reg_t reg, u32 clear, u32 set) { wa_mcr_add(wal, reg, clear, set, clear, false); } @@ -206,7 +206,7 @@ wa_write_or(struct i915_wa_list *wal, i915_reg_t reg, u32 set) } static void -wa_mcr_write_or(struct i915_wa_list *wal, i915_reg_t reg, u32 set) +wa_mcr_write_or(struct i915_wa_list *wal, i915_mcr_reg_t reg, u32 set) { wa_mcr_write_clr_set(wal, reg, set, set); } @@ -218,7 +218,7 @@ wa_write_clr(struct i915_wa_list *wal, i915_reg_t reg, u32 clr) } static void -wa_mcr_write_clr(struct i915_wa_list *wal, i915_reg_t reg, u32 clr) +wa_mcr_write_clr(struct i915_wa_list *wal, i915_mcr_reg_t reg, u32 clr) { wa_mcr_write_clr_set(wal, reg, clr, 0); } @@ -241,7 +241,7 @@ wa_masked_en(struct i915_wa_list *wal, i915_reg_t reg, u32 val) } static void -wa_mcr_masked_en(struct i915_wa_list *wal, i915_reg_t reg, u32 val) +wa_mcr_masked_en(struct i915_wa_list *wal, i915_mcr_reg_t reg, u32 val) { wa_mcr_add(wal, reg, 0, _MASKED_BIT_ENABLE(val), val, true); } @@ -253,7 +253,7 @@ wa_masked_dis(struct i915_wa_list *wal, i915_reg_t reg, u32 val) } static void -wa_mcr_masked_dis(struct i915_wa_list *wal, i915_reg_t reg, u32 val) +wa_mcr_masked_dis(struct i915_wa_list *wal, i915_mcr_reg_t reg, u32 val) { wa_mcr_add(wal, reg, 0, _MASKED_BIT_DISABLE(val), val, true); } @@ -266,7 +266,7 @@ wa_masked_field_set(struct i915_wa_list *wal, i915_reg_t reg, } static void -wa_mcr_masked_field_set(struct i915_wa_list *wal, i915_reg_t reg, +wa_mcr_masked_field_set(struct i915_wa_list *wal, i915_mcr_reg_t reg, u32 mask, u32 val) { wa_mcr_add(wal, reg, 0, _MASKED_FIELD(mask, val), mask, true); @@ -1692,19 +1692,19 @@ wa_list_apply(struct intel_gt *gt, const struct i915_wa_list *wal) /* open-coded rmw due to steering */ if (wa->clr) old = wa->is_mcr ? - intel_gt_mcr_read_any_fw(gt, wa->reg) : + intel_gt_mcr_read_any_fw(gt, wa->mcr_reg) : intel_uncore_read_fw(uncore, wa->reg); val = (old & ~wa->clr) | wa->set; if (val != old || !wa->clr) { if (wa->is_mcr) - intel_gt_mcr_multicast_write_fw(gt, wa->reg, val); + intel_gt_mcr_multicast_write_fw(gt, wa->mcr_reg, val); else intel_uncore_write_fw(uncore, wa->reg, val); } if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)) { u32 val = wa->is_mcr ? - intel_gt_mcr_read_any_fw(gt, wa->reg) : + intel_gt_mcr_read_any_fw(gt, wa->mcr_reg) : intel_uncore_read_fw(uncore, wa->reg); wa_verify(wa, val, wal->name, "application"); @@ -1738,7 +1738,7 @@ static bool wa_list_verify(struct intel_gt *gt, for (i = 0, wa = wal->list; i < wal->count; i++, wa++) ok &= wa_verify(wa, wa->is_mcr ? - intel_gt_mcr_read_any_fw(gt, wa->reg) : + intel_gt_mcr_read_any_fw(gt, wa->mcr_reg) : intel_uncore_read_fw(uncore, wa->reg), wal->name, from); @@ -1786,10 +1786,10 @@ whitelist_reg_ext(struct i915_wa_list *wal, i915_reg_t reg, u32 flags) } static void -whitelist_mcr_reg_ext(struct i915_wa_list *wal, i915_reg_t reg, u32 flags) +whitelist_mcr_reg_ext(struct i915_wa_list *wal, i915_mcr_reg_t reg, u32 flags) { struct i915_wa wa = { - .reg = reg, + .mcr_reg = reg, .is_mcr = 1, }; @@ -1799,7 +1799,7 @@ whitelist_mcr_reg_ext(struct i915_wa_list *wal, i915_reg_t reg, u32 flags) if (GEM_DEBUG_WARN_ON(!is_nonpriv_flags_valid(flags))) return; - wa.reg.reg |= flags; + wa.mcr_reg.reg |= flags; _wa_add(wal, &wa); } @@ -1810,7 +1810,7 @@ whitelist_reg(struct i915_wa_list *wal, i915_reg_t reg) } static void -whitelist_mcr_reg(struct i915_wa_list *wal, i915_reg_t reg) +whitelist_mcr_reg(struct i915_wa_list *wal, i915_mcr_reg_t reg) { whitelist_mcr_reg_ext(wal, reg, RING_FORCE_TO_NONPRIV_ACCESS_RW); } diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds_types.h b/drivers/gpu/drm/i915/gt/intel_workarounds_types.h index f05b37e56fa9..7c8b01d00043 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds_types.h +++ b/drivers/gpu/drm/i915/gt/intel_workarounds_types.h @@ -11,7 +11,10 @@ #include "i915_reg_defs.h" struct i915_wa { - i915_reg_t reg; + union { + i915_reg_t reg; + i915_mcr_reg_t mcr_reg; + }; u32 clr; u32 set; u32 read; diff --git a/drivers/gpu/drm/i915/gt/selftest_workarounds.c b/drivers/gpu/drm/i915/gt/selftest_workarounds.c index 67a9aab801dd..21b1edc052f8 100644 --- a/drivers/gpu/drm/i915/gt/selftest_workarounds.c +++ b/drivers/gpu/drm/i915/gt/selftest_workarounds.c @@ -991,7 +991,7 @@ static bool pardon_reg(struct drm_i915_private *i915, i915_reg_t reg) /* Alas, we must pardon some whitelists. Mistakes already made */ static const struct regmask pardon[] = { { GEN9_CTX_PREEMPT_REG, 9 }, - { GEN8_L3SQCREG4, 9 }, + { _MMIO(0xb118), 9 }, /* GEN8_L3SQCREG4 */ }; return find_reg(i915, reg, pardon, ARRAY_SIZE(pardon)); diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c index de923fb82301..34ef4f36e660 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c @@ -328,7 +328,7 @@ static long __must_check guc_mmio_reg_add(struct intel_gt *gt, static long __must_check guc_mcr_reg_add(struct intel_gt *gt, struct temp_regset *regset, - i915_reg_t reg, u32 flags) + i915_mcr_reg_t reg, u32 flags) { u8 group, inst; diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c index 9495a7928bc8..d5c03e7a7843 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c @@ -240,7 +240,7 @@ static void guc_capture_free_extlists(struct __guc_mmio_reg_descr_group *reglist struct __ext_steer_reg { const char *name; - i915_reg_t reg; + i915_mcr_reg_t reg; }; static const struct __ext_steer_reg xe_extregs[] = { @@ -252,7 +252,7 @@ static void __fill_ext_reg(struct __guc_mmio_reg_descr *ext, const struct __ext_steer_reg *extlist, int slice_id, int subslice_id) { - ext->reg = extlist->reg; + ext->reg = _MMIO(i915_mmio_reg_offset(extlist->reg)); ext->flags = FIELD_PREP(GUC_REGSET_STEERING_GROUP, slice_id); ext->flags |= FIELD_PREP(GUC_REGSET_STEERING_INSTANCE, subslice_id); ext->regname = extlist->name; diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c index 683f88f5d669..41ab6c99e3a0 100644 --- a/drivers/gpu/drm/i915/gvt/handlers.c +++ b/drivers/gpu/drm/i915/gvt/handlers.c @@ -734,7 +734,7 @@ static i915_reg_t force_nonpriv_white_list[] = { _MMIO(0x770c), _MMIO(0x83a8), _MMIO(0xb110), - GEN8_L3SQCREG4,//_MMIO(0xb118) + _MMIO(0xb118), _MMIO(0xe100), _MMIO(0xe18c), _MMIO(0xe48c), diff --git a/drivers/gpu/drm/i915/gvt/mmio_context.c b/drivers/gpu/drm/i915/gvt/mmio_context.c index 485ff6c8e558..5197e15cb78e 100644 --- a/drivers/gpu/drm/i915/gvt/mmio_context.c +++ b/drivers/gpu/drm/i915/gvt/mmio_context.c @@ -106,15 +106,15 @@ static struct engine_mmio gen9_engine_mmio_list[] __cacheline_aligned = { {RCS0, GEN8_CS_CHICKEN1, 0xffff, true}, /* 0x2580 */ {RCS0, COMMON_SLICE_CHICKEN2, 0xffff, true}, /* 0x7014 */ {RCS0, GEN9_CS_DEBUG_MODE1, 0xffff, false}, /* 0x20ec */ - {RCS0, GEN8_L3SQCREG4, 0, false}, /* 0xb118 */ - {RCS0, GEN9_SCRATCH1, 0, false}, /* 0xb11c */ + {RCS0, _MMIO(0xb118), 0, false}, /* GEN8_L3SQCREG4 */ + {RCS0, _MMIO(0xb11c), 0, false}, /* GEN9_SCRATCH1 */ {RCS0, GEN9_SCRATCH_LNCF1, 0, false}, /* 0xb008 */ {RCS0, GEN7_HALF_SLICE_CHICKEN1, 0xffff, true}, /* 0xe100 */ - {RCS0, HALF_SLICE_CHICKEN2, 0xffff, true}, /* 0xe180 */ - {RCS0, GEN8_HALF_SLICE_CHICKEN3, 0xffff, true}, /* 0xe184 */ - {RCS0, GEN9_HALF_SLICE_CHICKEN5, 0xffff, true}, /* 0xe188 */ - {RCS0, GEN9_HALF_SLICE_CHICKEN7, 0xffff, true}, /* 0xe194 */ - {RCS0, GEN8_ROW_CHICKEN, 0xffff, true}, /* 0xe4f0 */ + {RCS0, _MMIO(0xe180), 0xffff, true}, /* HALF_SLICE_CHICKEN2 */ + {RCS0, _MMIO(0xe184), 0xffff, true}, /* GEN8_HALF_SLICE_CHICKEN3 */ + {RCS0, _MMIO(0xe188), 0xffff, true}, /* GEN9_HALF_SLICE_CHICKEN5 */ + {RCS0, _MMIO(0xe194), 0xffff, true}, /* GEN9_HALF_SLICE_CHICKEN7 */ + {RCS0, _MMIO(0xe4f0), 0xffff, true}, /* GEN8_ROW_CHICKEN */ {RCS0, TRVATTL3PTRDW(0), 0, true}, /* 0x4de0 */ {RCS0, TRVATTL3PTRDW(1), 0, true}, /* 0x4de4 */ {RCS0, TRNULLDETCT, 0, true}, /* 0x4de8 */ diff --git a/drivers/gpu/drm/i915/i915_reg_defs.h b/drivers/gpu/drm/i915/i915_reg_defs.h index 8f486f77609f..f1859046a9c4 100644 --- a/drivers/gpu/drm/i915/i915_reg_defs.h +++ b/drivers/gpu/drm/i915/i915_reg_defs.h @@ -104,22 +104,21 @@ typedef struct { #define _MMIO(r) ((const i915_reg_t){ .reg = (r) }) -#define INVALID_MMIO_REG _MMIO(0) - -static __always_inline u32 i915_mmio_reg_offset(i915_reg_t reg) -{ - return reg.reg; -} +typedef struct { + u32 reg; +} i915_mcr_reg_t; -static inline bool i915_mmio_reg_equal(i915_reg_t a, i915_reg_t b) -{ - return i915_mmio_reg_offset(a) == i915_mmio_reg_offset(b); -} +#define INVALID_MMIO_REG _MMIO(0) -static inline bool i915_mmio_reg_valid(i915_reg_t reg) -{ - return !i915_mmio_reg_equal(reg, INVALID_MMIO_REG); -} +/* + * These macros can be used on either i915_reg_t or i915_mcr_reg_t since they're + * simply operations on the register's offset and don't care about the MCR vs + * non-MCR nature of the register. + */ +#define i915_mmio_reg_offset(r) \ + _Generic((r), i915_reg_t: (r).reg, i915_mcr_reg_t: (r).reg) +#define i915_mmio_reg_equal(a, b) (i915_mmio_reg_offset(a) == i915_mmio_reg_offset(b)) +#define i915_mmio_reg_valid(r) (!i915_mmio_reg_equal(r, INVALID_MMIO_REG)) #define VLV_DISPLAY_BASE 0x180000 -- cgit From f32898c94a105c221e6fe957aee833e7fc98f95f Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Fri, 14 Oct 2022 16:02:38 -0700 Subject: drm/i915/xelpg: Add multicast steering MTL's graphics IP (Xe_LPG) once again changes the multicast register types and steering details. Key changes from past platforms: * The number of instances of some MCR types (NODE, OAAL2, and GAM) vary according to the MTL subplatform and cannot be read from fuse registers. However steering to instance #0 will always provided a non-terminated value, so we can lump these all into a single "instance0" table. * The MCR steering register (and its bitfields) has changed. Unlike past platforms, we will be explicitly steering all types of MCR accesses, including those for "SLICE" and "DSS" ranges; we no longer rely on implicit steering. On previous platforms, various hardware/firmware agents that needed to access registers typically had their own steering control registers, allowing them to perform multicast steering without clobbering the CPU/kernel steering. Starting with MTL, more of these agents now share a single steering register (0xFD4) and it is no longer safe for us to assume that the value will remain unchanged from how we initialized it during startup. There is also a slight chance of race conditions between the driver and a hardware/firmware agent, so the hardware provides a semaphore register that can be used to coordinate access to the steering register. Support for the semaphore register will be introduced in a future patch. v2: - Use Xe_LPG terminology instead of "MTL 3D" since it's the IP version we're matching on now rather than the platform. - Don't combine l3bank and mslice masks into a union. It's not related to the other changes here and we might still need both of them on some future platform. - Separate debug dumping of steering settings to a separate helper function. (Tvrtko) - Update debug dumping to include DSS ranges (and future-proof it so that any new ranges added on future platforms will also be dumped). - Restore MULTICAST bit at the end of rw_with_mcr_steering_fw() if we cleared it. Also force the MULTICAST bit to true at the beginning of multicast writes just to be safe. (Bala) Bspec: 67788, 67112 Cc: Radhakrishna Sripada Cc: Balasubramani Vivekanandan Signed-off-by: Matt Roper Reviewed-by: Balasubramani Vivekanandan Link: https://patchwork.freedesktop.org/patch/msgid/20221014230239.1023689-14-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/gt/intel_gt_mcr.c | 135 ++++++++++++++++++++++++---- drivers/gpu/drm/i915/gt/intel_gt_regs.h | 5 ++ drivers/gpu/drm/i915/gt/intel_gt_types.h | 1 + drivers/gpu/drm/i915/gt/intel_workarounds.c | 33 +++++-- drivers/gpu/drm/i915/i915_pci.c | 1 + 5 files changed, 154 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_mcr.c b/drivers/gpu/drm/i915/gt/intel_gt_mcr.c index 349074bf365f..23a1ef9659bf 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_mcr.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_mcr.c @@ -41,6 +41,7 @@ static const char * const intel_steering_types[] = { "MSLICE", "LNCF", "GAM", + "DSS", "INSTANCE 0", }; @@ -99,9 +100,40 @@ static const struct intel_mmio_range pvc_instance0_steering_table[] = { {}, }; +static const struct intel_mmio_range xelpg_instance0_steering_table[] = { + { 0x000B00, 0x000BFF }, /* SQIDI */ + { 0x001000, 0x001FFF }, /* SQIDI */ + { 0x004000, 0x0048FF }, /* GAM */ + { 0x008700, 0x0087FF }, /* SQIDI */ + { 0x00B000, 0x00B0FF }, /* NODE */ + { 0x00C800, 0x00CFFF }, /* GAM */ + { 0x00D880, 0x00D8FF }, /* NODE */ + { 0x00DD00, 0x00DDFF }, /* OAAL2 */ + {}, +}; + +static const struct intel_mmio_range xelpg_l3bank_steering_table[] = { + { 0x00B100, 0x00B3FF }, + {}, +}; + +/* DSS steering is used for SLICE ranges as well */ +static const struct intel_mmio_range xelpg_dss_steering_table[] = { + { 0x005200, 0x0052FF }, /* SLICE */ + { 0x005500, 0x007FFF }, /* SLICE */ + { 0x008140, 0x00815F }, /* SLICE (0x8140-0x814F), DSS (0x8150-0x815F) */ + { 0x0094D0, 0x00955F }, /* SLICE (0x94D0-0x951F), DSS (0x9520-0x955F) */ + { 0x009680, 0x0096FF }, /* DSS */ + { 0x00D800, 0x00D87F }, /* SLICE */ + { 0x00DC00, 0x00DCFF }, /* SLICE */ + { 0x00DE80, 0x00E8FF }, /* DSS (0xE000-0xE0FF reserved) */ +}; + void intel_gt_mcr_init(struct intel_gt *gt) { struct drm_i915_private *i915 = gt->i915; + unsigned long fuse; + int i; /* * An mslice is unavailable only if both the meml3 for the slice is @@ -119,7 +151,22 @@ void intel_gt_mcr_init(struct intel_gt *gt) drm_warn(&i915->drm, "mslice mask all zero!\n"); } - if (IS_PONTEVECCHIO(i915)) { + if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 70) && + gt->type == GT_PRIMARY) { + fuse = REG_FIELD_GET(GT_L3_EXC_MASK, + intel_uncore_read(gt->uncore, XEHP_FUSE4)); + + /* + * Despite the register field being named "exclude mask" the + * bits actually represent enabled banks (two banks per bit). + */ + for_each_set_bit(i, &fuse, 3) + gt->info.l3bank_mask |= 0x3 << 2 * i; + + gt->steering_table[INSTANCE0] = xelpg_instance0_steering_table; + gt->steering_table[L3BANK] = xelpg_l3bank_steering_table; + gt->steering_table[DSS] = xelpg_dss_steering_table; + } else if (IS_PONTEVECCHIO(i915)) { gt->steering_table[INSTANCE0] = pvc_instance0_steering_table; } else if (IS_DG2(i915)) { gt->steering_table[MSLICE] = xehpsdv_mslice_steering_table; @@ -184,7 +231,19 @@ static u32 rw_with_mcr_steering_fw(struct intel_uncore *uncore, lockdep_assert_held(&uncore->lock); - if (GRAPHICS_VER(uncore->i915) >= 11) { + if (GRAPHICS_VER_FULL(uncore->i915) >= IP_VER(12, 70)) { + /* + * Always leave the hardware in multicast mode when doing reads + * (see comment about Wa_22013088509 below) and only change it + * to unicast mode when doing writes of a specific instance. + * + * No need to save old steering reg value. + */ + intel_uncore_write_fw(uncore, MTL_MCR_SELECTOR, + REG_FIELD_PREP(MTL_MCR_GROUPID, group) | + REG_FIELD_PREP(MTL_MCR_INSTANCEID, instance) | + (rw_flag == FW_REG_READ) ? GEN11_MCR_MULTICAST : 0); + } else if (GRAPHICS_VER(uncore->i915) >= 11) { mcr_mask = GEN11_MCR_SLICE_MASK | GEN11_MCR_SUBSLICE_MASK; mcr_ss = GEN11_MCR_SLICE(group) | GEN11_MCR_SUBSLICE(instance); @@ -202,26 +261,40 @@ static u32 rw_with_mcr_steering_fw(struct intel_uncore *uncore, */ if (rw_flag == FW_REG_WRITE) mcr_mask |= GEN11_MCR_MULTICAST; + + mcr = intel_uncore_read_fw(uncore, GEN8_MCR_SELECTOR); + old_mcr = mcr; + + mcr &= ~mcr_mask; + mcr |= mcr_ss; + intel_uncore_write_fw(uncore, GEN8_MCR_SELECTOR, mcr); } else { mcr_mask = GEN8_MCR_SLICE_MASK | GEN8_MCR_SUBSLICE_MASK; mcr_ss = GEN8_MCR_SLICE(group) | GEN8_MCR_SUBSLICE(instance); - } - old_mcr = mcr = intel_uncore_read_fw(uncore, GEN8_MCR_SELECTOR); + mcr = intel_uncore_read_fw(uncore, GEN8_MCR_SELECTOR); + old_mcr = mcr; - mcr &= ~mcr_mask; - mcr |= mcr_ss; - intel_uncore_write_fw(uncore, GEN8_MCR_SELECTOR, mcr); + mcr &= ~mcr_mask; + mcr |= mcr_ss; + intel_uncore_write_fw(uncore, GEN8_MCR_SELECTOR, mcr); + } if (rw_flag == FW_REG_READ) val = intel_uncore_read_fw(uncore, mcr_reg_cast(reg)); else intel_uncore_write_fw(uncore, mcr_reg_cast(reg), value); - mcr &= ~mcr_mask; - mcr |= old_mcr & mcr_mask; - - intel_uncore_write_fw(uncore, GEN8_MCR_SELECTOR, mcr); + /* + * For pre-MTL platforms, we need to restore the old value of the + * steering control register to ensure that implicit steering continues + * to behave as expected. For MTL and beyond, we need only reinstate + * the 'multicast' bit (and only if we did a write that cleared it). + */ + if (GRAPHICS_VER_FULL(uncore->i915) >= IP_VER(12, 70) && rw_flag == FW_REG_WRITE) + intel_uncore_write_fw(uncore, MTL_MCR_SELECTOR, GEN11_MCR_MULTICAST); + else if (GRAPHICS_VER_FULL(uncore->i915) < IP_VER(12, 70)) + intel_uncore_write_fw(uncore, GEN8_MCR_SELECTOR, old_mcr); return val; } @@ -296,6 +369,13 @@ void intel_gt_mcr_unicast_write(struct intel_gt *gt, i915_mcr_reg_t reg, u32 val void intel_gt_mcr_multicast_write(struct intel_gt *gt, i915_mcr_reg_t reg, u32 value) { + /* + * Ensure we have multicast behavior, just in case some non-i915 agent + * left the hardware in unicast mode. + */ + if (GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 70)) + intel_uncore_write_fw(gt->uncore, MTL_MCR_SELECTOR, GEN11_MCR_MULTICAST); + intel_uncore_write(gt->uncore, mcr_reg_cast(reg), value); } @@ -312,6 +392,13 @@ void intel_gt_mcr_multicast_write(struct intel_gt *gt, */ void intel_gt_mcr_multicast_write_fw(struct intel_gt *gt, i915_mcr_reg_t reg, u32 value) { + /* + * Ensure we have multicast behavior, just in case some non-i915 agent + * left the hardware in unicast mode. + */ + if (GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 70)) + intel_uncore_write_fw(gt->uncore, MTL_MCR_SELECTOR, GEN11_MCR_MULTICAST); + intel_uncore_write_fw(gt->uncore, mcr_reg_cast(reg), value); } @@ -389,6 +476,8 @@ static void get_nonterminated_steering(struct intel_gt *gt, enum intel_steering_type type, u8 *group, u8 *instance) { + u32 dss; + switch (type) { case L3BANK: *group = 0; /* unused */ @@ -412,6 +501,11 @@ static void get_nonterminated_steering(struct intel_gt *gt, *group = IS_DG2(gt->i915) ? 1 : 0; *instance = 0; break; + case DSS: + dss = intel_sseu_find_first_xehp_dss(>->info.sseu, 0, 0); + *group = dss / GEN_DSS_PER_GSLICE; + *instance = dss % GEN_DSS_PER_GSLICE; + break; case INSTANCE0: /* * There are a lot of MCR types for which instance (0, 0) @@ -544,11 +638,20 @@ static void report_steering_type(struct drm_printer *p, void intel_gt_mcr_report_steering(struct drm_printer *p, struct intel_gt *gt, bool dump_table) { - drm_printf(p, "Default steering: group=0x%x, instance=0x%x\n", - gt->default_steering.groupid, - gt->default_steering.instanceid); - - if (IS_PONTEVECCHIO(gt->i915)) { + /* + * Starting with MTL we no longer have default steering; + * all ranges are explicitly steered. + */ + if (GRAPHICS_VER_FULL(gt->i915) < IP_VER(12, 70)) + drm_printf(p, "Default steering: group=0x%x, instance=0x%x\n", + gt->default_steering.groupid, + gt->default_steering.instanceid); + + if (GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 70)) { + for (int i = 0; i < NUM_STEERING_TYPES; i++) + if (gt->steering_table[i]) + report_steering_type(p, gt, i, dump_table); + } else if (IS_PONTEVECCHIO(gt->i915)) { report_steering_type(p, gt, INSTANCE0, dump_table); } else if (HAS_MSLICE_STEERING(gt->i915)) { report_steering_type(p, gt, MSLICE, dump_table); diff --git a/drivers/gpu/drm/i915/gt/intel_gt_regs.h b/drivers/gpu/drm/i915/gt/intel_gt_regs.h index 1116bc3dba51..1c3a46ee876d 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_regs.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_regs.h @@ -56,6 +56,7 @@ #define FORCEWAKE_ACK_GT_MTL _MMIO(0xdfc) #define MCFG_MCR_SELECTOR _MMIO(0xfd0) +#define MTL_MCR_SELECTOR _MMIO(0xfd4) #define SF_MCR_SELECTOR _MMIO(0xfd8) #define GEN8_MCR_SELECTOR _MMIO(0xfdc) #define GAM_MCR_SELECTOR _MMIO(0xfe0) @@ -68,6 +69,8 @@ #define GEN11_MCR_SLICE_MASK GEN11_MCR_SLICE(0xf) #define GEN11_MCR_SUBSLICE(subslice) (((subslice) & 0x7) << 24) #define GEN11_MCR_SUBSLICE_MASK GEN11_MCR_SUBSLICE(0x7) +#define MTL_MCR_GROUPID REG_GENMASK(11, 8) +#define MTL_MCR_INSTANCEID REG_GENMASK(3, 0) #define IPEIR_I965 _MMIO(0x2064) #define IPEHR_I965 _MMIO(0x2068) @@ -528,6 +531,8 @@ #define GEN6_MBCTL_BOOT_FETCH_MECH (1 << 0) /* Fuse readout registers for GT */ +#define XEHP_FUSE4 _MMIO(0x9114) +#define GT_L3_EXC_MASK REG_GENMASK(6, 4) #define GEN10_MIRROR_FUSE3 _MMIO(0x9118) #define GEN10_L3BANK_PAIR_COUNT 4 #define GEN10_L3BANK_MASK 0x0F diff --git a/drivers/gpu/drm/i915/gt/intel_gt_types.h b/drivers/gpu/drm/i915/gt/intel_gt_types.h index 30003d68fd51..0bb73d110a84 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_types.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_types.h @@ -60,6 +60,7 @@ enum intel_steering_type { MSLICE, LNCF, GAM, + DSS, /* * On some platforms there are multiple types of MCR registers that diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c index dadb60e6a58f..711a31935857 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds.c +++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c @@ -1128,18 +1128,23 @@ static void __set_mcr_steering(struct i915_wa_list *wal, wa_write_clr_set(wal, steering_reg, mcr_mask, mcr); } -static void __add_mcr_wa(struct intel_gt *gt, struct i915_wa_list *wal, - unsigned int slice, unsigned int subslice) +static void debug_dump_steering(struct intel_gt *gt) { struct drm_printer p = drm_debug_printer("MCR Steering:"); + if (drm_debug_enabled(DRM_UT_DRIVER)) + intel_gt_mcr_report_steering(&p, gt, false); +} + +static void __add_mcr_wa(struct intel_gt *gt, struct i915_wa_list *wal, + unsigned int slice, unsigned int subslice) +{ __set_mcr_steering(wal, GEN8_MCR_SELECTOR, slice, subslice); gt->default_steering.groupid = slice; gt->default_steering.instanceid = subslice; - if (drm_debug_enabled(DRM_UT_DRIVER)) - intel_gt_mcr_report_steering(&p, gt, false); + debug_dump_steering(gt); } static void @@ -1581,12 +1586,30 @@ pvc_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) wa_mcr_write_clr(wal, GEN8_MISCCPCTL, GEN12_DOP_CLOCK_GATE_RENDER_ENABLE); } +static void +xelpg_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) +{ + /* FIXME: Actual workarounds will be added in future patch(es) */ + + /* + * Unlike older platforms, we no longer setup implicit steering here; + * all MCR accesses are explicitly steered. + */ + debug_dump_steering(gt); +} + static void gt_init_workarounds(struct intel_gt *gt, struct i915_wa_list *wal) { struct drm_i915_private *i915 = gt->i915; - if (IS_PONTEVECCHIO(i915)) + /* FIXME: Media GT handling will be added in an upcoming patch */ + if (gt->type == GT_MEDIA) + return; + + if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 70)) + xelpg_gt_workarounds_init(gt, wal); + else if (IS_PONTEVECCHIO(i915)) pvc_gt_workarounds_init(gt, wal); else if (IS_DG2(i915)) dg2_gt_workarounds_init(gt, wal); diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c index f1344db626f5..4757ad0173da 100644 --- a/drivers/gpu/drm/i915/i915_pci.c +++ b/drivers/gpu/drm/i915/i915_pci.c @@ -1142,6 +1142,7 @@ static const struct intel_device_info mtl_info = { .display.has_modular_fia = 1, .extra_gt_list = xelpmp_extra_gt, .has_flat_ccs = 0, + .has_mslice_steering = 0, .has_snoop = 1, .__runtime.memory_regions = REGION_SMEM | REGION_STOLEN_LMEM, .__runtime.platform_engine_mask = BIT(RCS0) | BIT(BCS0) | BIT(CCS0), -- cgit From a7ec65fc7e83f342d1392cac69e4f60c7a7cc4ba Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Fri, 14 Oct 2022 16:02:39 -0700 Subject: drm/i915/xelpmp: Add multicast steering for media GT MTL's media IP (Xe_LPM+) only has a single type of steering ("OAADDRM") which selects between media slice 0 and media slice 1. We'll always steer to media slice 0 unless it is fused off (which is the case when VD0, VE0, and SFC0 are all reported as unavailable). Bspec: 67789 Signed-off-by: Matt Roper Reviewed-by: Balasubramani Vivekanandan Link: https://patchwork.freedesktop.org/patch/msgid/20221014230239.1023689-15-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/gt/intel_gt_mcr.c | 18 ++++++++++++++++-- drivers/gpu/drm/i915/gt/intel_gt_types.h | 1 + drivers/gpu/drm/i915/gt/intel_workarounds.c | 17 +++++++++++++++-- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_mcr.c b/drivers/gpu/drm/i915/gt/intel_gt_mcr.c index 23a1ef9659bf..0d2811724b00 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_mcr.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_mcr.c @@ -42,6 +42,7 @@ static const char * const intel_steering_types[] = { "LNCF", "GAM", "DSS", + "OADDRM", "INSTANCE 0", }; @@ -129,6 +130,11 @@ static const struct intel_mmio_range xelpg_dss_steering_table[] = { { 0x00DE80, 0x00E8FF }, /* DSS (0xE000-0xE0FF reserved) */ }; +static const struct intel_mmio_range xelpmp_oaddrm_steering_table[] = { + { 0x393200, 0x39323F }, + { 0x393400, 0x3934FF }, +}; + void intel_gt_mcr_init(struct intel_gt *gt) { struct drm_i915_private *i915 = gt->i915; @@ -151,8 +157,9 @@ void intel_gt_mcr_init(struct intel_gt *gt) drm_warn(&i915->drm, "mslice mask all zero!\n"); } - if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 70) && - gt->type == GT_PRIMARY) { + if (MEDIA_VER(i915) >= 13 && gt->type == GT_MEDIA) { + gt->steering_table[OADDRM] = xelpmp_oaddrm_steering_table; + } else if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 70)) { fuse = REG_FIELD_GET(GT_L3_EXC_MASK, intel_uncore_read(gt->uncore, XEHP_FUSE4)); @@ -514,6 +521,13 @@ static void get_nonterminated_steering(struct intel_gt *gt, *group = 0; *instance = 0; break; + case OADDRM: + if ((VDBOX_MASK(gt) | VEBOX_MASK(gt) | gt->info.sfc_mask) & BIT(0)) + *group = 0; + else + *group = 1; + *instance = 0; + break; default: MISSING_CASE(type); *group = 0; diff --git a/drivers/gpu/drm/i915/gt/intel_gt_types.h b/drivers/gpu/drm/i915/gt/intel_gt_types.h index 0bb73d110a84..64aa2ba624fc 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_types.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_types.h @@ -61,6 +61,7 @@ enum intel_steering_type { LNCF, GAM, DSS, + OADDRM, /* * On some platforms there are multiple types of MCR registers that diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c index 711a31935857..bae960486872 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds.c +++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c @@ -1598,14 +1598,27 @@ xelpg_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) debug_dump_steering(gt); } +static void +xelpmp_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) +{ + /* FIXME: Actual workarounds will be added in future patch(es) */ + + debug_dump_steering(gt); +} + static void gt_init_workarounds(struct intel_gt *gt, struct i915_wa_list *wal) { struct drm_i915_private *i915 = gt->i915; - /* FIXME: Media GT handling will be added in an upcoming patch */ - if (gt->type == GT_MEDIA) + if (gt->type == GT_MEDIA) { + if (MEDIA_VER(i915) >= 13) + xelpmp_gt_workarounds_init(gt, wal); + else + MISSING_CASE(MEDIA_VER(i915)); + return; + } if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 70)) xelpg_gt_workarounds_init(gt, wal); -- cgit From 847eec69f01a28ca44f5ac7e1d71d3a60263d680 Mon Sep 17 00:00:00 2001 From: José Roberto de Souza Date: Mon, 17 Oct 2022 06:24:32 -0700 Subject: drm/i915: Extend Wa_1607297627 to Alderlake-P MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Workaround 1607297627 was missed for Alderlake-P, so here extending it to it and adding the fixes tag so this WA is backported to all stable kernels. v2: - fixed subject - added Fixes tag BSpec: 54369 Cc: # v5.17+ Fixes: dfb924e33927 ("drm/i915/adlp: Remove require_force_probe protection") Reviewed-by: Lucas De Marchi Cc: Tvrtko Ursulin Signed-off-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20221017132432.112850-1-jose.souza@intel.com --- drivers/gpu/drm/i915/gt/intel_workarounds.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c index 31e129329fb0..a79798777887 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds.c +++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c @@ -2293,11 +2293,11 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) } if (IS_DG1_GRAPHICS_STEP(i915, STEP_A0, STEP_B0) || - IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915)) { + IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915) || IS_ALDERLAKE_P(i915)) { /* * Wa_1607030317:tgl * Wa_1607186500:tgl - * Wa_1607297627:tgl,rkl,dg1[a0] + * Wa_1607297627:tgl,rkl,dg1[a0],adlp * * On TGL and RKL there are multiple entries for this WA in the * BSpec; some indicate this is an A0-only WA, others indicate -- cgit From 21f213e67ecb7488c0fda145d7956e09ecdd43a9 Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Thu, 13 Oct 2022 13:32:45 -0700 Subject: drm/i915/huc: bump timeout for delayed load and reduce print verbosity We're observing sporadic HuC delayed load timeouts in CI, due to mei_pxp binding completing later than we expected. HuC is still loaded when the bind occurs, but in the meantime i915 has started allowing submission to the VCS engines even if HuC is not there. In most of the cases I've observed, the timeout was due to the init/resume of another driver between i915 and mei hitting errors and thus adding an extra delay, but HuC was still loaded before userspace could submit, because the whole resume process time was increased by the delays. Given that there is no upper bound to the delay that can be introduced by other drivers, I've reached the following compromise with the media team: 1) i915 is going to bump the timeout to 5s, to reduce the probability of reaching it. We still expect HuC to be loaded before userspace starts submitting, so increasing the timeout should have no impact on normal operations, but in case something weird happens we don't want to stall video submissions for too long. 2) The media driver will cope with the failing submissions that manage to go through between i915 init/resume complete and HuC loading, if any ever happen. This could cause a small corruption of video playback immediately after a resume (we should be safe on boot because the media driver polls the HUC_STATUS ioctl before starting submissions). Since we're accepting the timeout as a valid outcome, I'm also reducing the print verbosity from error to notice. v2: use separate prints for MEI GSC and MEI PXP init timeouts (John) v3: add MISSING_CASE to the if-else chain (John) References: https://gitlab.freedesktop.org/drm/intel/-/issues/7033 Fixes: 27536e03271d ("drm/i915/huc: track delayed HuC load with a fence") Signed-off-by: Daniele Ceraolo Spurio Cc: Tony Ye Cc: John Harrison Reviewed-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20221013203245.1801788-1-daniele.ceraolospurio@intel.com --- drivers/gpu/drm/i915/gt/uc/intel_huc.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_huc.c b/drivers/gpu/drm/i915/gt/uc/intel_huc.c index 4d1cc383b681..fbc8bae14f76 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_huc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_huc.c @@ -52,10 +52,12 @@ * guaranteed for this to happen during boot, so the big timeout is a safety net * that we never expect to need. * MEI-PXP + HuC load usually takes ~300ms, but if the GSC needs to be resumed - * and/or reset, this can take longer. + * and/or reset, this can take longer. Note that the kernel might schedule + * other work between the i915 init/resume and the MEI one, which can add to + * the delay. */ #define GSC_INIT_TIMEOUT_MS 10000 -#define PXP_INIT_TIMEOUT_MS 2000 +#define PXP_INIT_TIMEOUT_MS 5000 static int sw_fence_dummy_notify(struct i915_sw_fence *sf, enum i915_sw_fence_notify state) @@ -104,8 +106,14 @@ static enum hrtimer_restart huc_delayed_load_timer_callback(struct hrtimer *hrti struct intel_huc *huc = container_of(hrtimer, struct intel_huc, delayed_load.timer); if (!intel_huc_is_authenticated(huc)) { - drm_err(&huc_to_gt(huc)->i915->drm, - "timed out waiting for GSC init to load HuC\n"); + if (huc->delayed_load.status == INTEL_HUC_WAITING_ON_GSC) + drm_notice(&huc_to_gt(huc)->i915->drm, + "timed out waiting for MEI GSC init to load HuC\n"); + else if (huc->delayed_load.status == INTEL_HUC_WAITING_ON_PXP) + drm_notice(&huc_to_gt(huc)->i915->drm, + "timed out waiting for MEI PXP init to load HuC\n"); + else + MISSING_CASE(huc->delayed_load.status); __gsc_init_error(huc); } -- cgit From 97074216917b4188f0af3e52cc5b3f2b277bbbca Mon Sep 17 00:00:00 2001 From: Yifan Zhang Date: Sun, 9 Oct 2022 14:35:20 +0800 Subject: drm/amdgpu: add tmz support for GC 11.0.1 this patch to add tmz support for GC 11.0.1. Signed-off-by: Yifan Zhang Reviewed-by: Tim Huang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c index 34233a74248c..9c0d9baab4e2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c @@ -542,6 +542,7 @@ void amdgpu_gmc_tmz_set(struct amdgpu_device *adev) case IP_VERSION(10, 3, 1): /* YELLOW_CARP*/ case IP_VERSION(10, 3, 3): + case IP_VERSION(11, 0, 1): /* Don't enable it by default yet. */ if (amdgpu_tmz < 1) { -- cgit From bfa8cb055fef348c896b70b9ac13d1838665031a Mon Sep 17 00:00:00 2001 From: Yifan Zhang Date: Sun, 9 Oct 2022 14:37:06 +0800 Subject: drm/amdgpu: allow secure submission on gfx11 and sdma6 This patch to allow secure submission on gfx11 and sdma6. Signed-off-by: Yifan Zhang Reviewed-by: Tim Huang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 1 + drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c index 251109723ab6..257b2e4de600 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c @@ -6058,6 +6058,7 @@ static const struct amdgpu_ring_funcs gfx_v11_0_ring_funcs_gfx = { .align_mask = 0xff, .nop = PACKET3(PACKET3_NOP, 0x3FFF), .support_64bit_ptrs = true, + .secure_submission_supported = true, .vmhub = AMDGPU_GFXHUB_0, .get_rptr = gfx_v11_0_ring_get_rptr_gfx, .get_wptr = gfx_v11_0_ring_get_wptr_gfx, diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c index da3beb0bf2fa..d9ae69be5ea4 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c @@ -1523,6 +1523,7 @@ static const struct amdgpu_ring_funcs sdma_v6_0_ring_funcs = { .align_mask = 0xf, .nop = SDMA_PKT_NOP_HEADER_OP(SDMA_OP_NOP), .support_64bit_ptrs = true, + .secure_submission_supported = true, .vmhub = AMDGPU_GFXHUB_0, .get_rptr = sdma_v6_0_ring_get_rptr, .get_wptr = sdma_v6_0_ring_get_wptr, -- cgit From 7a94c8602fbe585fac636dae355cf73b53d50866 Mon Sep 17 00:00:00 2001 From: Hawking Zhang Date: Tue, 17 May 2022 22:10:41 +0800 Subject: drm/amdgpu: extend HWIP_MAX_INSTANCE to 28 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit more ip instances are available Acked-by: Christian König Signed-off-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index ae9371b172e3..3ce91f660c3f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -678,7 +678,7 @@ enum amd_hw_ip_block_type { MAX_HWIP }; -#define HWIP_MAX_INSTANCE 11 +#define HWIP_MAX_INSTANCE 28 #define HW_ID_MAX 300 #define IP_VERSION(mj, mn, rv) (((mj) << 16) | ((mn) << 8) | (rv)) -- cgit From e9ff000b5a2a6b2f34828ebcfb0a829ce2dcdc2a Mon Sep 17 00:00:00 2001 From: Hawking Zhang Date: Tue, 31 Aug 2021 15:30:08 +0800 Subject: drm/amdgpu: update psp_fw_type enum in amdgpu_ucode header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To match with the definition in psp firmware Acked-by: Christian König Signed-off-by: Hawking Zhang Reviewed-by: Le Ma Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h index 1c36235b4539..552e06929229 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h @@ -125,6 +125,7 @@ enum psp_fw_type { PSP_FW_TYPE_PSP_INTF_DRV, PSP_FW_TYPE_PSP_DBG_DRV, PSP_FW_TYPE_PSP_RAS_DRV, + PSP_FW_TYPE_MAX_INDEX, }; /* version_major=2, version_minor=0 */ -- cgit From 886f1816c2ad9e5bf594549cc4977df7a533dde9 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 3 Oct 2022 15:00:47 -0400 Subject: drm/amdgpu: convert vega20_ih.c to IP version checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For consistency with newer asics. Acked-by: Christian König Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/vega20_ih.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/vega20_ih.c b/drivers/gpu/drm/amd/amdgpu/vega20_ih.c index 59dfca093155..1706081d054d 100644 --- a/drivers/gpu/drm/amd/amdgpu/vega20_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/vega20_ih.c @@ -267,7 +267,7 @@ static void vega20_ih_reroute_ih(struct amdgpu_device *adev) /* vega20 ih reroute will go through psp this * function is used for newer asics starting arcturus */ - if (adev->asic_type >= CHIP_ARCTURUS) { + if (adev->ip_versions[OSSSYS_HWIP][0] >= IP_VERSION(4, 2, 1)) { /* Reroute to IH ring 1 for VMC */ WREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_INDEX, 0x12); tmp = RREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_DATA); @@ -308,7 +308,7 @@ static int vega20_ih_irq_init(struct amdgpu_device *adev) adev->nbio.funcs->ih_control(adev); - if (adev->asic_type == CHIP_ARCTURUS && + if ((adev->ip_versions[OSSSYS_HWIP][0] == IP_VERSION(4, 2, 1)) && adev->firmware.load_type == AMDGPU_FW_LOAD_DIRECT) { ih_chicken = RREG32_SOC15(OSSSYS, 0, mmIH_CHICKEN); if (adev->irq.ih.use_bus_addr) { @@ -321,7 +321,7 @@ static int vega20_ih_irq_init(struct amdgpu_device *adev) /* psp firmware won't program IH_CHICKEN for aldebaran * driver needs to program it properly according to * MC_SPACE type in IH_RB_CNTL */ - if (adev->asic_type == CHIP_ALDEBARAN) { + if (adev->ip_versions[OSSSYS_HWIP][0] == IP_VERSION(4, 4, 0)) { ih_chicken = RREG32_SOC15(OSSSYS, 0, mmIH_CHICKEN_ALDEBARAN); if (adev->irq.ih.use_bus_addr) { ih_chicken = REG_SET_FIELD(ih_chicken, IH_CHICKEN, -- cgit From eb1670787eb7b9fe339631605dda1a53603a7699 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 3 Oct 2022 15:09:57 -0400 Subject: drm/amdgpu: convert amdgpu_amdkfd_gpuvm.c to IP version checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For consistency with the rest of the code. Acked-by: Christian König Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index 978d3970b5cc..8ad01e1ee4c6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -418,9 +418,9 @@ static uint64_t get_pte_flags(struct amdgpu_device *adev, struct kgd_mem *mem) if (mem->alloc_flags & KFD_IOC_ALLOC_MEM_FLAGS_EXECUTABLE) mapping_flags |= AMDGPU_VM_PAGE_EXECUTABLE; - switch (adev->asic_type) { - case CHIP_ARCTURUS: - case CHIP_ALDEBARAN: + switch (adev->ip_versions[GC_HWIP][0]) { + case IP_VERSION(9, 4, 1): + case IP_VERSION(9, 4, 2): if (mem->alloc_flags & KFD_IOC_ALLOC_MEM_FLAGS_VRAM) { if (bo_adev == adev) { if (uncached) @@ -429,7 +429,7 @@ static uint64_t get_pte_flags(struct amdgpu_device *adev, struct kgd_mem *mem) mapping_flags |= AMDGPU_VM_MTYPE_CC; else mapping_flags |= AMDGPU_VM_MTYPE_RW; - if (adev->asic_type == CHIP_ALDEBARAN && + if ((adev->ip_versions[GC_HWIP][0] == IP_VERSION(9, 4, 2)) && adev->gmc.xgmi.connected_to_cpu) snoop = true; } else { -- cgit From 7fe441d8b77a1e4fe09099092945d27607dda69b Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 12 Oct 2022 15:37:07 +0800 Subject: drm/amdgpu/si_dma: remove unused variable in si_dma_stop() After commit 571c05365892 ("drm/amdgpu: switch sdma buffer function tear down to a helper"), the variable 'ring' is not used anymore, it can be removed. Signed-off-by: Yang Yingliang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/si_dma.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/si_dma.c b/drivers/gpu/drm/amd/amdgpu/si_dma.c index 4d5e718540aa..abca8b529721 100644 --- a/drivers/gpu/drm/amd/amdgpu/si_dma.c +++ b/drivers/gpu/drm/amd/amdgpu/si_dma.c @@ -112,14 +112,12 @@ static void si_dma_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq, static void si_dma_stop(struct amdgpu_device *adev) { - struct amdgpu_ring *ring; u32 rb_cntl; unsigned i; amdgpu_sdma_unset_buffer_funcs_helper(adev); for (i = 0; i < adev->sdma.num_instances; i++) { - ring = &adev->sdma.instance[i].ring; /* dma0 */ rb_cntl = RREG32(DMA_RB_CNTL + sdma_offsets[i]); rb_cntl &= ~DMA_RB_ENABLE; -- cgit From a7310d8de3ba60a6ec4294392daf747b8333b3b2 Mon Sep 17 00:00:00 2001 From: Danijel Slivka Date: Tue, 4 Oct 2022 15:39:44 +0200 Subject: drm/amdgpu: set vm_update_mode=0 as default for Sienna Cichlid in SRIOV case For asic with VF MMIO access protection avoid using CPU for VM table updates. CPU pagetable updates have issues with HDP flush as VF MMIO access protection blocks write to mmBIF_BX_DEV0_EPF0_VF0_HDP_MEM_COHERENCY_FLUSH_CNTL register during sriov runtime. v3: introduce virtualization capability flag AMDGPU_VF_MMIO_ACCESS_PROTECT which indicates that VF MMIO write access is not allowed in sriov runtime Signed-off-by: Danijel Slivka Reviewed-by: Felix Kuehling Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c | 6 ++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h | 4 ++++ drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 6 +++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c index e4af40b9a8aa..9c765b04aae3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c @@ -726,6 +726,12 @@ void amdgpu_detect_virtualization(struct amdgpu_device *adev) adev->virt.caps |= AMDGPU_PASSTHROUGH_MODE; } + if (amdgpu_sriov_vf(adev) && adev->asic_type == CHIP_SIENNA_CICHLID) + /* VF MMIO access (except mailbox range) from CPU + * will be blocked during sriov runtime + */ + adev->virt.caps |= AMDGPU_VF_MMIO_ACCESS_PROTECT; + /* we have the ability to check now */ if (amdgpu_sriov_vf(adev)) { switch (adev->asic_type) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h index d94c31e68a14..49c4347d154c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h @@ -31,6 +31,7 @@ #define AMDGPU_SRIOV_CAPS_IS_VF (1 << 2) /* this GPU is a virtual function */ #define AMDGPU_PASSTHROUGH_MODE (1 << 3) /* thw whole GPU is pass through for VM */ #define AMDGPU_SRIOV_CAPS_RUNTIME (1 << 4) /* is out of full access mode */ +#define AMDGPU_VF_MMIO_ACCESS_PROTECT (1 << 5) /* MMIO write access is not allowed in sriov runtime */ /* flags for indirect register access path supported by rlcg for sriov */ #define AMDGPU_RLCG_GC_WRITE_LEGACY (0x8 << 28) @@ -297,6 +298,9 @@ struct amdgpu_video_codec_info; #define amdgpu_passthrough(adev) \ ((adev)->virt.caps & AMDGPU_PASSTHROUGH_MODE) +#define amdgpu_sriov_vf_mmio_access_protection(adev) \ +((adev)->virt.caps & AMDGPU_VF_MMIO_ACCESS_PROTECT) + static inline bool is_virtual_machine(void) { #if defined(CONFIG_X86) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 83b0c5d86e48..2291aa14d888 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -2338,7 +2338,11 @@ void amdgpu_vm_manager_init(struct amdgpu_device *adev) */ #ifdef CONFIG_X86_64 if (amdgpu_vm_update_mode == -1) { - if (amdgpu_gmc_vram_full_visible(&adev->gmc)) + /* For asic with VF MMIO access protection + * avoid using CPU for VM table updates + */ + if (amdgpu_gmc_vram_full_visible(&adev->gmc) && + !amdgpu_sriov_vf_mmio_access_protection(adev)) adev->vm_manager.vm_update_mode = AMDGPU_VM_USE_CPU_FOR_COMPUTE; else -- cgit From 6aa5893926371ebc6c2b6ca6ad37b2aec3a11d29 Mon Sep 17 00:00:00 2001 From: Victor Zhao Date: Thu, 13 Oct 2022 10:42:04 +0800 Subject: Revert "drm/amdgpu: add debugfs amdgpu_reset_level" This reverts commit 5bd8d53f6fa53eab5433698d1362dae2aa53c1cc. This commit breaks the reset logic for aldebaran, revert it for now. Will move the mask inside the reset handler. Fixes: 5bd8d53f6fa53e ("drm/amdgpu: add debugfs amdgpu_reset_level") Signed-off-by: Victor Zhao Reviewed-by: Lijo Lazar Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 4 ---- drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c | 2 -- drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c | 8 -------- drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c | 3 --- 4 files changed, 17 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 3ce91f660c3f..0e6ddf05c23c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -274,9 +274,6 @@ extern int amdgpu_vcnfw_log; #define AMDGPU_RESET_VCE (1 << 13) #define AMDGPU_RESET_VCE1 (1 << 14) -#define AMDGPU_RESET_LEVEL_SOFT_RECOVERY (1 << 0) -#define AMDGPU_RESET_LEVEL_MODE2 (1 << 1) - /* max cursor sizes (in pixels) */ #define CIK_CURSOR_WIDTH 128 #define CIK_CURSOR_HEIGHT 128 @@ -1065,7 +1062,6 @@ struct amdgpu_device { struct work_struct reset_work; - uint32_t amdgpu_reset_level_mask; bool job_hang; }; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c index 6066aebf491c..de61a85c4b02 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c @@ -1954,8 +1954,6 @@ int amdgpu_debugfs_init(struct amdgpu_device *adev) return PTR_ERR(ent); } - debugfs_create_u32("amdgpu_reset_level", 0600, root, &adev->amdgpu_reset_level_mask); - /* Register debugfs entries for amdgpu_ttm */ amdgpu_ttm_debugfs_init(adev); amdgpu_debugfs_pm_init(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c index 9da5ead50c90..831fb222139c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c @@ -37,8 +37,6 @@ int amdgpu_reset_init(struct amdgpu_device *adev) { int ret = 0; - adev->amdgpu_reset_level_mask = 0x1; - switch (adev->ip_versions[MP1_HWIP][0]) { case IP_VERSION(13, 0, 2): ret = aldebaran_reset_init(adev); @@ -76,9 +74,6 @@ int amdgpu_reset_prepare_hwcontext(struct amdgpu_device *adev, { struct amdgpu_reset_handler *reset_handler = NULL; - if (!(adev->amdgpu_reset_level_mask & AMDGPU_RESET_LEVEL_MODE2)) - return -ENOSYS; - if (test_bit(AMDGPU_SKIP_MODE2_RESET, &reset_context->flags)) return -ENOSYS; @@ -98,9 +93,6 @@ int amdgpu_reset_perform_reset(struct amdgpu_device *adev, int ret; struct amdgpu_reset_handler *reset_handler = NULL; - if (!(adev->amdgpu_reset_level_mask & AMDGPU_RESET_LEVEL_MODE2)) - return -ENOSYS; - if (test_bit(AMDGPU_SKIP_MODE2_RESET, &reset_context->flags)) return -ENOSYS; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c index 3e316b013fd9..d3558c34d406 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c @@ -405,9 +405,6 @@ bool amdgpu_ring_soft_recovery(struct amdgpu_ring *ring, unsigned int vmid, { ktime_t deadline = ktime_add_us(ktime_get(), 10000); - if (!(ring->adev->amdgpu_reset_level_mask & AMDGPU_RESET_LEVEL_SOFT_RECOVERY)) - return false; - if (amdgpu_sriov_vf(ring->adev) || !ring->funcs->soft_recovery || !fence) return false; -- cgit From b98a1648d6616d288e888c6dc6dcd4fa543585b3 Mon Sep 17 00:00:00 2001 From: Victor Zhao Date: Thu, 13 Oct 2022 11:06:33 +0800 Subject: Revert "drm/amdgpu: let mode2 reset fallback to default when failure" This reverts commit dac6b80818ac2353631c5a33d140d8d5508e2957. This commit reverted the AMDGPU_SKIP_MODE2_RESET as it conflicts with the original design of reset handler. Will redesign it. Fixes: dac6b80818ac23 ("drm/amdgpu: let mode2 reset fallback to default when failure") Signed-off-by: Victor Zhao Reviewed-by: Lijo Lazar Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 1 - drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 7 +------ drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 1 - drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c | 1 - drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c | 6 ------ drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h | 3 +-- drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c | 1 - drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c | 1 - drivers/gpu/drm/amd/amdgpu/mxgpu_vi.c | 1 - 9 files changed, 2 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 03bbfaa51cbc..0561812aa0a4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -134,7 +134,6 @@ static void amdgpu_amdkfd_reset_work(struct work_struct *work) reset_context.method = AMD_RESET_METHOD_NONE; reset_context.reset_req_dev = adev; clear_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags); - clear_bit(AMDGPU_SKIP_MODE2_RESET, &reset_context.flags); amdgpu_device_gpu_recover(adev, NULL, &reset_context); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index ab8f970b2849..bb73fb420ffc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -5210,7 +5210,6 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, reset_context->job = job; reset_context->hive = hive; - /* * Build list of devices to reset. * In case we are in XGMI hive mode, resort the device list @@ -5337,11 +5336,8 @@ retry: /* Rest of adevs pre asic reset from XGMI hive. */ amdgpu_ras_resume(adev); } else { r = amdgpu_do_asic_reset(device_list_handle, reset_context); - if (r && r == -EAGAIN) { - set_bit(AMDGPU_SKIP_MODE2_RESET, &reset_context->flags); - adev->asic_reset_res = 0; + if (r && r == -EAGAIN) goto retry; - } if (!r && gpu_reset_for_dev_remove) goto recover_end; @@ -5777,7 +5773,6 @@ pci_ers_result_t amdgpu_pci_slot_reset(struct pci_dev *pdev) reset_context.reset_req_dev = adev; set_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags); set_bit(AMDGPU_SKIP_HW_RESET, &reset_context.flags); - set_bit(AMDGPU_SKIP_MODE2_RESET, &reset_context.flags); adev->no_hw_access = true; r = amdgpu_device_pre_asic_reset(adev, &reset_context); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c index 46c99331d7f1..cd968e781077 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c @@ -72,7 +72,6 @@ static enum drm_gpu_sched_stat amdgpu_job_timedout(struct drm_sched_job *s_job) reset_context.method = AMD_RESET_METHOD_NONE; reset_context.reset_req_dev = adev; clear_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags); - clear_bit(AMDGPU_SKIP_MODE2_RESET, &reset_context.flags); r = amdgpu_device_gpu_recover(ring->adev, job, &reset_context); if (r) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index 2dad7aa9a03b..75f1402101f4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -1950,7 +1950,6 @@ static void amdgpu_ras_do_recovery(struct work_struct *work) reset_context.method = AMD_RESET_METHOD_NONE; reset_context.reset_req_dev = adev; clear_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags); - clear_bit(AMDGPU_SKIP_MODE2_RESET, &reset_context.flags); amdgpu_device_gpu_recover(ras->adev, NULL, &reset_context); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c index 831fb222139c..f778466bb9db 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c @@ -74,9 +74,6 @@ int amdgpu_reset_prepare_hwcontext(struct amdgpu_device *adev, { struct amdgpu_reset_handler *reset_handler = NULL; - if (test_bit(AMDGPU_SKIP_MODE2_RESET, &reset_context->flags)) - return -ENOSYS; - if (adev->reset_cntl && adev->reset_cntl->get_reset_handler) reset_handler = adev->reset_cntl->get_reset_handler( adev->reset_cntl, reset_context); @@ -93,9 +90,6 @@ int amdgpu_reset_perform_reset(struct amdgpu_device *adev, int ret; struct amdgpu_reset_handler *reset_handler = NULL; - if (test_bit(AMDGPU_SKIP_MODE2_RESET, &reset_context->flags)) - return -ENOSYS; - if (adev->reset_cntl) reset_handler = adev->reset_cntl->get_reset_handler( adev->reset_cntl, reset_context); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h index f5318fedf2f0..f4a501ff87d9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h @@ -30,8 +30,7 @@ enum AMDGPU_RESET_FLAGS { AMDGPU_NEED_FULL_RESET = 0, AMDGPU_SKIP_HW_RESET = 1, - AMDGPU_SKIP_MODE2_RESET = 2, - AMDGPU_RESET_FOR_DEVICE_REMOVE = 3, + AMDGPU_RESET_FOR_DEVICE_REMOVE = 2, }; struct amdgpu_reset_context { diff --git a/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c b/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c index a2f04b249132..12906ba74462 100644 --- a/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c +++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c @@ -290,7 +290,6 @@ flr_done: reset_context.method = AMD_RESET_METHOD_NONE; reset_context.reset_req_dev = adev; clear_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags); - clear_bit(AMDGPU_SKIP_MODE2_RESET, &reset_context.flags); amdgpu_device_gpu_recover(adev, NULL, &reset_context); } diff --git a/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c b/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c index a977f0027928..e07757eea7ad 100644 --- a/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c +++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c @@ -317,7 +317,6 @@ flr_done: reset_context.method = AMD_RESET_METHOD_NONE; reset_context.reset_req_dev = adev; clear_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags); - clear_bit(AMDGPU_SKIP_MODE2_RESET, &reset_context.flags); amdgpu_device_gpu_recover(adev, NULL, &reset_context); } diff --git a/drivers/gpu/drm/amd/amdgpu/mxgpu_vi.c b/drivers/gpu/drm/amd/amdgpu/mxgpu_vi.c index fd14fa9b9cd7..288c414babdf 100644 --- a/drivers/gpu/drm/amd/amdgpu/mxgpu_vi.c +++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_vi.c @@ -529,7 +529,6 @@ static void xgpu_vi_mailbox_flr_work(struct work_struct *work) reset_context.method = AMD_RESET_METHOD_NONE; reset_context.reset_req_dev = adev; clear_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags); - clear_bit(AMDGPU_SKIP_MODE2_RESET, &reset_context.flags); amdgpu_device_gpu_recover(adev, NULL, &reset_context); } -- cgit From 16e311612456df01308585b89227854b1f495041 Mon Sep 17 00:00:00 2001 From: Victor Zhao Date: Thu, 13 Oct 2022 15:53:19 +0800 Subject: drm/amdgpu: Refactor mode2 reset logic for v11.0.7 - refactor mode2 on v11.0.7 to align with aldebaran - comment out using mode2 reset as default for now, will introduce another controller to replace previous reset_level_mask v2: squash in unused variable removal (Alex) Signed-off-by: Victor Zhao Reviewed-by: Lijo Lazar Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/sienna_cichlid.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/sienna_cichlid.c b/drivers/gpu/drm/amd/amdgpu/sienna_cichlid.c index 7aa570c1ce4a..81a6d5b94987 100644 --- a/drivers/gpu/drm/amd/amdgpu/sienna_cichlid.c +++ b/drivers/gpu/drm/amd/amdgpu/sienna_cichlid.c @@ -31,12 +31,23 @@ #include "amdgpu_psp.h" #include "amdgpu_xgmi.h" +static bool sienna_cichlid_is_mode2_default(struct amdgpu_reset_control *reset_ctl) +{ +#if 0 + struct amdgpu_device *adev = (struct amdgpu_device *)reset_ctl->handle; + + if (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(11, 0, 7) && + adev->pm.fw_version >= 0x3a5500 && !amdgpu_sriov_vf(adev)) + return true; +#endif + return false; +} + static struct amdgpu_reset_handler * sienna_cichlid_get_reset_handler(struct amdgpu_reset_control *reset_ctl, struct amdgpu_reset_context *reset_context) { struct amdgpu_reset_handler *handler; - struct amdgpu_device *adev = (struct amdgpu_device *)reset_ctl->handle; if (reset_context->method != AMD_RESET_METHOD_NONE) { list_for_each_entry(handler, &reset_ctl->reset_handlers, @@ -44,15 +55,13 @@ sienna_cichlid_get_reset_handler(struct amdgpu_reset_control *reset_ctl, if (handler->reset_method == reset_context->method) return handler; } - } else { - list_for_each_entry(handler, &reset_ctl->reset_handlers, + } + + if (sienna_cichlid_is_mode2_default(reset_ctl)) { + list_for_each_entry (handler, &reset_ctl->reset_handlers, handler_list) { - if (handler->reset_method == AMD_RESET_METHOD_MODE2 && - adev->pm.fw_version >= 0x3a5500 && - !amdgpu_sriov_vf(adev)) { - reset_context->method = AMD_RESET_METHOD_MODE2; + if (handler->reset_method == AMD_RESET_METHOD_MODE2) return handler; - } } } -- cgit From e5b781c56d46c44c52caa915f1b65064f2f7c1ba Mon Sep 17 00:00:00 2001 From: Asher Song Date: Fri, 14 Oct 2022 11:36:33 +0800 Subject: drm/amdgpu: Revert "drm/amdgpu: getting fan speed pwm for vega10 properly" This reverts commit 16fb4dca95daa9d8e037201166a58de8284f4268. Unfortunately, that commit causes fan monitors can't be read and written properly. Fixes: 16fb4dca95daa9 ("drm/amdgpu: getting fan speed pwm for vega10 properly") Signed-off-by: Asher Song Reviewed-by: Guchun Chen Signed-off-by: Alex Deucher --- .../drm/amd/pm/powerplay/hwmgr/vega10_thermal.c | 25 +++++++++++----------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_thermal.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_thermal.c index 190af79f3236..dad3e3741a4e 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_thermal.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_thermal.c @@ -67,21 +67,22 @@ int vega10_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr, int vega10_fan_ctrl_get_fan_speed_pwm(struct pp_hwmgr *hwmgr, uint32_t *speed) { - struct amdgpu_device *adev = hwmgr->adev; - uint32_t duty100, duty; - uint64_t tmp64; + uint32_t current_rpm; + uint32_t percent = 0; - duty100 = REG_GET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL1), - CG_FDO_CTRL1, FMAX_DUTY100); - duty = REG_GET_FIELD(RREG32_SOC15(THM, 0, mmCG_THERMAL_STATUS), - CG_THERMAL_STATUS, FDO_PWM_DUTY); + if (hwmgr->thermal_controller.fanInfo.bNoFan) + return 0; - if (!duty100) - return -EINVAL; + if (vega10_get_current_rpm(hwmgr, ¤t_rpm)) + return -1; + + if (hwmgr->thermal_controller. + advanceFanControlParameters.usMaxFanRPM != 0) + percent = current_rpm * 255 / + hwmgr->thermal_controller. + advanceFanControlParameters.usMaxFanRPM; - tmp64 = (uint64_t)duty * 255; - do_div(tmp64, duty100); - *speed = MIN((uint32_t)tmp64, 255); + *speed = MIN(percent, 255); return 0; } -- cgit From 8a7b97672dfdb97691dfb15e350b38339f7c69f3 Mon Sep 17 00:00:00 2001 From: Kenneth Feng Date: Sat, 30 Jul 2022 10:58:37 +0800 Subject: drm/amd/pm: temporarily disable thermal alert on smu_v13_0_10 temporarily disable thermal alert on smu_v13_0_10 due to kfd test fail. will enable it again after confirming the thermal hardware setting. Signed-off-by: Kenneth Feng Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 13c5c7f1ecb9..3d436e7f6e95 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -1312,10 +1312,12 @@ static int smu_smc_hw_setup(struct smu_context *smu) return ret; } - ret = smu_enable_thermal_alert(smu); - if (ret) { - dev_err(adev->dev, "Failed to enable thermal alert!\n"); - return ret; + if (adev->ip_versions[MP1_HWIP][0] != IP_VERSION(13, 0, 10)) { + ret = smu_enable_thermal_alert(smu); + if (ret) { + dev_err(adev->dev, "Failed to enable thermal alert!\n"); + return ret; + } } ret = smu_notify_display_change(smu); -- cgit From e77422a5d4518109511334e6c2274422fa1559c8 Mon Sep 17 00:00:00 2001 From: Kenneth Feng Date: Wed, 7 Sep 2022 15:40:34 +0800 Subject: drm/amd/pm: remove the pptable id override on smu_v13_0_10 remove the pptable id override on smu_v13_0_10, and the id is fetched from vbios now. Signed-off-by: Kenneth Feng Reviewed-by: Likun Gao Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c index 93fffdbab4f0..d9323293179a 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c @@ -454,9 +454,6 @@ int smu_v13_0_setup_pptable(struct smu_context *smu) dev_info(adev->dev, "override pptable id %d\n", pptable_id); } else { pptable_id = smu->smu_table.boot_values.pp_table_id; - - if (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 10)) - pptable_id = 6666; } /* force using vbios pptable in sriov mode */ -- cgit From 4ecdb30ec49d76ccb803c9b9c1464fcf27d6d041 Mon Sep 17 00:00:00 2001 From: Kenneth Feng Date: Wed, 7 Sep 2022 17:05:34 +0800 Subject: drm/amd/amdgpu: enable gfx clock gating features on smu_v13_0_10 enable gfx clock gating features on smu_v13_0_10 Signed-off-by: Kenneth Feng Reviewed-by: Jack Gui Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 1 + drivers/gpu/drm/amd/amdgpu/soc21.c | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c index 257b2e4de600..73106f53246d 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c @@ -5076,6 +5076,7 @@ static int gfx_v11_0_set_clockgating_state(void *handle, case IP_VERSION(11, 0, 0): case IP_VERSION(11, 0, 1): case IP_VERSION(11, 0, 2): + case IP_VERSION(11, 0, 3): gfx_v11_0_update_gfx_clock_gating(adev, state == AMD_CG_STATE_GATE); break; diff --git a/drivers/gpu/drm/amd/amdgpu/soc21.c b/drivers/gpu/drm/amd/amdgpu/soc21.c index 795706b3b092..fdd842a3fcb6 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc21.c +++ b/drivers/gpu/drm/amd/amdgpu/soc21.c @@ -636,7 +636,11 @@ static int soc21_common_early_init(void *handle) break; case IP_VERSION(11, 0, 3): adev->cg_flags = AMD_CG_SUPPORT_VCN_MGCG | - AMD_CG_SUPPORT_JPEG_MGCG; + AMD_CG_SUPPORT_JPEG_MGCG | + AMD_CG_SUPPORT_GFX_CGCG | + AMD_CG_SUPPORT_GFX_CGLS | + AMD_CG_SUPPORT_REPEATER_FGCG | + AMD_CG_SUPPORT_GFX_MGCG; adev->pg_flags = AMD_PG_SUPPORT_VCN | AMD_PG_SUPPORT_VCN_DPG | AMD_PG_SUPPORT_JPEG; -- cgit From 7faf684b15f5533142ebeed5ec09d5ea9d9239c4 Mon Sep 17 00:00:00 2001 From: Kenneth Feng Date: Mon, 26 Sep 2022 17:15:04 +0800 Subject: drm/amd/pm: skip loading pptable from driver on secure board for smu_v13_0_10 skip loading pptable from driver on secure board since it's loaded from psp. Signed-off-by: Kenneth Feng Reviewed-by: Guan Yu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c index d9323293179a..c4552ade8d44 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c @@ -211,7 +211,8 @@ int smu_v13_0_init_pptable_microcode(struct smu_context *smu) return 0; if ((adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 7)) || - (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 0))) + (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 0)) || + (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 10))) return 0; /* override pptable_id from driver parameter */ -- cgit From bbce8cdb8390c4cae8ebe99f13a82c846995e8d9 Mon Sep 17 00:00:00 2001 From: Likun Gao Date: Mon, 25 Jul 2022 20:02:40 +0800 Subject: drm/amdgpu: skip mes self test for gc 11.0.3 Temporary disable mes self teset for gc 11.0.3. Signed-off-by: Likun Gao Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/mes_v11_0.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c index 5cec6b259b7f..133804e6018a 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c @@ -1296,7 +1296,8 @@ static int mes_v11_0_late_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - if (!amdgpu_in_reset(adev)) + if (!amdgpu_in_reset(adev) && + (adev->ip_versions[GC_HWIP][0] != IP_VERSION(11, 0, 3))) amdgpu_mes_self_test(adev); return 0; -- cgit From 2e26bf1e461fb934cbd5e34142068705ceba1fc1 Mon Sep 17 00:00:00 2001 From: YiPeng Chai Date: Tue, 27 Sep 2022 13:16:27 +0800 Subject: drm/amdgpu: Enable gmc soft reset on gmc_v11_0_3 Enable gmc soft reset on gmc_v11_0_3. Signed-off-by: YiPeng Chai Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/soc21.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/amdgpu/soc21.c b/drivers/gpu/drm/amd/amdgpu/soc21.c index fdd842a3fcb6..e08044008186 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc21.c +++ b/drivers/gpu/drm/amd/amdgpu/soc21.c @@ -423,6 +423,7 @@ static bool soc21_need_full_reset(struct amdgpu_device *adev) case IP_VERSION(11, 0, 0): return amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__UMC); case IP_VERSION(11, 0, 2): + case IP_VERSION(11, 0, 3): return false; default: return true; -- cgit From 073285efde229ae82d3b853c7f4bcca81f97a55f Mon Sep 17 00:00:00 2001 From: YiPeng Chai Date: Tue, 27 Sep 2022 14:06:42 +0800 Subject: drm/amdgpu: Enable ras support for mp0 v13_0_0 and v13_0_10 V1: Enable ras support for CHIP_IP_DISCOVERY asic type. V2: 1. Change commit comment. 2. Enable ras support for mp0 v13_0_0 and v13_0_10. Signed-off-by: YiPeng Chai Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index 75f1402101f4..4a8f73cc4cb5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -2267,6 +2267,16 @@ static int amdgpu_ras_recovery_fini(struct amdgpu_device *adev) static bool amdgpu_ras_asic_supported(struct amdgpu_device *adev) { + if (adev->asic_type == CHIP_IP_DISCOVERY) { + switch (adev->ip_versions[MP0_HWIP][0]) { + case IP_VERSION(13, 0, 0): + case IP_VERSION(13, 0, 10): + return true; + default: + return false; + } + } + return adev->asic_type == CHIP_VEGA10 || adev->asic_type == CHIP_VEGA20 || adev->asic_type == CHIP_ARCTURUS || -- cgit From 82835055c62fa49b50dc00736743e8f99ed93638 Mon Sep 17 00:00:00 2001 From: YiPeng Chai Date: Wed, 28 Sep 2022 15:52:02 +0800 Subject: drm/amdgpu: Add sriov vf ras support in amdgpu_ras_asic_supported V2: Add sriov vf ras support in amdgpu_ras_asic_supported. Signed-off-by: YiPeng Chai Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index 4a8f73cc4cb5..a4b47e1bd111 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -2267,6 +2267,15 @@ static int amdgpu_ras_recovery_fini(struct amdgpu_device *adev) static bool amdgpu_ras_asic_supported(struct amdgpu_device *adev) { + if (amdgpu_sriov_vf(adev)) { + switch (adev->ip_versions[MP0_HWIP][0]) { + case IP_VERSION(13, 0, 2): + return true; + default: + return false; + } + } + if (adev->asic_type == CHIP_IP_DISCOVERY) { switch (adev->ip_versions[MP0_HWIP][0]) { case IP_VERSION(13, 0, 0): @@ -2320,11 +2329,6 @@ static void amdgpu_ras_check_supported(struct amdgpu_device *adev) !amdgpu_ras_asic_supported(adev)) return; - /* If driver run on sriov guest side, only enable ras for aldebaran */ - if (amdgpu_sriov_vf(adev) && - adev->ip_versions[MP1_HWIP][0] != IP_VERSION(13, 0, 2)) - return; - if (!adev->gmc.xgmi.connected_to_cpu) { if (amdgpu_atomfirmware_mem_ecc_supported(adev)) { dev_info(adev->dev, "MEM ECC is active.\n"); -- cgit From c6863be231791fa80dca203b9295780488671195 Mon Sep 17 00:00:00 2001 From: Evan Quan Date: Thu, 29 Sep 2022 10:24:51 +0800 Subject: drm/amd/pm: fulfill SMU13.0.0 cstate control interface Fulfill the functionality for cstate control. Signed-off-by: Evan Quan Reviewed-by: Hawking Zhang Reviewed-by: Lijo Lazar Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org # 6.0.x --- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c index 1d454485e0d9..29529328152d 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c @@ -119,6 +119,7 @@ static struct cmn2asic_msg_mapping smu_v13_0_0_message_map[SMU_MSG_MAX_COUNT] = MSG_MAP(NotifyPowerSource, PPSMC_MSG_NotifyPowerSource, 0), MSG_MAP(Mode1Reset, PPSMC_MSG_Mode1Reset, 0), MSG_MAP(PrepareMp1ForUnload, PPSMC_MSG_PrepareMp1ForUnload, 0), + MSG_MAP(DFCstateControl, PPSMC_MSG_SetExternalClientDfCstateAllow, 0), }; static struct cmn2asic_mapping smu_v13_0_0_clk_map[SMU_CLK_COUNT] = { @@ -1753,6 +1754,15 @@ static int smu_v13_0_0_set_mp1_state(struct smu_context *smu, return ret; } +static int smu_v13_0_0_set_df_cstate(struct smu_context *smu, + enum pp_df_cstate state) +{ + return smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_DFCstateControl, + state, + NULL); +} + static const struct pptable_funcs smu_v13_0_0_ppt_funcs = { .get_allowed_feature_mask = smu_v13_0_0_get_allowed_feature_mask, .set_default_dpm_table = smu_v13_0_0_set_default_dpm_table, @@ -1822,6 +1832,7 @@ static const struct pptable_funcs smu_v13_0_0_ppt_funcs = { .mode1_reset_is_support = smu_v13_0_0_is_mode1_reset_supported, .mode1_reset = smu_v13_0_mode1_reset, .set_mp1_state = smu_v13_0_0_set_mp1_state, + .set_df_cstate = smu_v13_0_0_set_df_cstate, }; void smu_v13_0_0_set_ppt_funcs(struct smu_context *smu) -- cgit From 3cf377ee8df7dc4ae5e543c37833ae5a5b2a78d3 Mon Sep 17 00:00:00 2001 From: Evan Quan Date: Thu, 29 Sep 2022 10:30:01 +0800 Subject: drm/amd/pm: fulfill SMU13.0.7 cstate control interface Fulfill the functionality for cstate control. Signed-off-by: Evan Quan Reviewed-by: Hawking Zhang Reviewed-by: Lijo Lazar Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org # 6.0.x --- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c index c422bf8a09b1..c4102cfb734c 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c @@ -121,6 +121,7 @@ static struct cmn2asic_msg_mapping smu_v13_0_7_message_map[SMU_MSG_MAX_COUNT] = MSG_MAP(Mode1Reset, PPSMC_MSG_Mode1Reset, 0), MSG_MAP(PrepareMp1ForUnload, PPSMC_MSG_PrepareMp1ForUnload, 0), MSG_MAP(SetMGpuFanBoostLimitRpm, PPSMC_MSG_SetMGpuFanBoostLimitRpm, 0), + MSG_MAP(DFCstateControl, PPSMC_MSG_SetExternalClientDfCstateAllow, 0), }; static struct cmn2asic_mapping smu_v13_0_7_clk_map[SMU_CLK_COUNT] = { @@ -1587,6 +1588,16 @@ static bool smu_v13_0_7_is_mode1_reset_supported(struct smu_context *smu) return true; } + +static int smu_v13_0_7_set_df_cstate(struct smu_context *smu, + enum pp_df_cstate state) +{ + return smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_DFCstateControl, + state, + NULL); +} + static const struct pptable_funcs smu_v13_0_7_ppt_funcs = { .get_allowed_feature_mask = smu_v13_0_7_get_allowed_feature_mask, .set_default_dpm_table = smu_v13_0_7_set_default_dpm_table, @@ -1649,6 +1660,7 @@ static const struct pptable_funcs smu_v13_0_7_ppt_funcs = { .mode1_reset_is_support = smu_v13_0_7_is_mode1_reset_supported, .mode1_reset = smu_v13_0_mode1_reset, .set_mp1_state = smu_v13_0_7_set_mp1_state, + .set_df_cstate = smu_v13_0_7_set_df_cstate, }; void smu_v13_0_7_set_ppt_funcs(struct smu_context *smu) -- cgit From b31d6ada8346574ce04656e5ce9676ec763f5144 Mon Sep 17 00:00:00 2001 From: Evan Quan Date: Thu, 29 Sep 2022 10:50:44 +0800 Subject: drm/amd/pm: disable cstate feature for gpu reset scenario Suggested by PMFW team and same as what did for gfxoff feature. This can address some Mode1Reset failures observed on SMU13.0.0. Signed-off-by: Evan Quan Reviewed-by: Hawking Zhang Reviewed-by: Lijo Lazar Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org # 6.0.x --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 8 ++++++++ drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 8 ++++++++ drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 9 +++++++++ 3 files changed, 25 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index bb73fb420ffc..e0445e8cc342 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -2928,6 +2928,14 @@ static int amdgpu_device_ip_suspend_phase1(struct amdgpu_device *adev) amdgpu_device_set_pg_state(adev, AMD_PG_STATE_UNGATE); amdgpu_device_set_cg_state(adev, AMD_CG_STATE_UNGATE); + /* + * Per PMFW team's suggestion, driver needs to handle gfxoff + * and df cstate features disablement for gpu reset(e.g. Mode1Reset) + * scenario. Add the missing df cstate disablement here. + */ + if (amdgpu_dpm_set_df_cstate(adev, DF_CSTATE_DISALLOW)) + dev_warn(adev->dev, "Failed to disallow df cstate"); + for (i = adev->num_ip_blocks - 1; i >= 0; i--) { if (!adev->ip_blocks[i].status.valid) continue; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c index 445005571f76..9cd005131f56 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c @@ -2242,9 +2242,17 @@ static void arcturus_get_unique_id(struct smu_context *smu) static int arcturus_set_df_cstate(struct smu_context *smu, enum pp_df_cstate state) { + struct amdgpu_device *adev = smu->adev; uint32_t smu_version; int ret; + /* + * Arcturus does not need the cstate disablement + * prerequisite for gpu reset. + */ + if (amdgpu_in_reset(adev) || adev->in_suspend) + return 0; + ret = smu_cmn_get_smc_version(smu, NULL, &smu_version); if (ret) { dev_err(smu->adev->dev, "Failed to get smu version!\n"); diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c index 619aee51b123..d30ec3005ea1 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -1640,6 +1640,15 @@ static bool aldebaran_is_baco_supported(struct smu_context *smu) static int aldebaran_set_df_cstate(struct smu_context *smu, enum pp_df_cstate state) { + struct amdgpu_device *adev = smu->adev; + + /* + * Aldebaran does not need the cstate disablement + * prerequisite for gpu reset. + */ + if (amdgpu_in_reset(adev) || adev->in_suspend) + return 0; + return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_DFCstateControl, state, NULL); } -- cgit From 5af392a89bd009aced92e9079589bd82f249010a Mon Sep 17 00:00:00 2001 From: ZhenGuo Yin Date: Wed, 12 Oct 2022 16:54:38 +0800 Subject: drm/amd/pm: Init pm_attr_list when dpm is disabled [Why] In SRIOV multi-vf, dpm is always disabled, and pm_attr_list won't be initialized. There will be a NULL pointer call trace after removing the dpm check condition in amdgpu_pm_sysfs_fini. BUG: kernel NULL pointer dereference, address: 0000000000000000 RIP: 0010:amdgpu_device_attr_remove_groups+0x20/0x90 [amdgpu] Call Trace: amdgpu_pm_sysfs_fini+0x2f/0x40 [amdgpu] amdgpu_device_fini_hw+0xdf/0x290 [amdgpu] [How] List pm_attr_list should be initialized when dpm is disabled. Fixes: a6ad27cec585fe ("drm/amd/pm: Remove redundant check condition") Signed-off-by: ZhenGuo Yin Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/amdgpu_pm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c index 948cc75376f8..236657eece47 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c @@ -3362,11 +3362,11 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev) if (adev->pm.sysfs_initialized) return 0; + INIT_LIST_HEAD(&adev->pm.pm_attr_list); + if (adev->pm.dpm_enabled == 0) return 0; - INIT_LIST_HEAD(&adev->pm.pm_attr_list); - adev->pm.int_hwmon_dev = hwmon_device_register_with_groups(adev->dev, DRIVER_NAME, adev, hwmon_groups); -- cgit From d1bb3afc0527ab55d118852b398fd0f1d2fe802d Mon Sep 17 00:00:00 2001 From: Tim Huang Date: Thu, 29 Sep 2022 14:39:21 +0800 Subject: drm/amd/pm: update SMU IP v13.0.4 driver interface version Update the SMU driver interface version to V7. Signed-off-by: Tim Huang Reviewed-by: Mario Limonciello Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org # 6.0.x --- .../amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_4.h | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_4.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_4.h index ae2d337158f3..f77401709d83 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_4.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_4.h @@ -27,7 +27,7 @@ // *** IMPORTANT *** // SMU TEAM: Always increment the interface version if // any structure is changed in this file -#define PMFW_DRIVER_IF_VERSION 5 +#define PMFW_DRIVER_IF_VERSION 7 typedef struct { int32_t value; @@ -163,8 +163,8 @@ typedef struct { uint16_t DclkFrequency; //[MHz] uint16_t MemclkFrequency; //[MHz] uint16_t spare; //[centi] - uint16_t UvdActivity; //[centi] uint16_t GfxActivity; //[centi] + uint16_t UvdActivity; //[centi] uint16_t Voltage[2]; //[mV] indices: VDDCR_VDD, VDDCR_SOC uint16_t Current[2]; //[mA] indices: VDDCR_VDD, VDDCR_SOC @@ -199,6 +199,19 @@ typedef struct { uint16_t DeviceState; uint16_t CurTemp; //[centi-Celsius] uint16_t spare2; + + uint16_t AverageGfxclkFrequency; + uint16_t AverageFclkFrequency; + uint16_t AverageGfxActivity; + uint16_t AverageSocclkFrequency; + uint16_t AverageVclkFrequency; + uint16_t AverageVcnActivity; + uint16_t AverageDRAMReads; //Filtered DF Bandwidth::DRAM Reads + uint16_t AverageDRAMWrites; //Filtered DF Bandwidth::DRAM Writes + uint16_t AverageSocketPower; //Filtered value of CurrentSocketPower + uint16_t AverageCorePower; //Filtered of [sum of CorePower[8]]) + uint16_t AverageCoreC0Residency[8]; //Filtered of [average C0 residency % per core] + uint32_t MetricsCounter; //Counts the # of metrics table parameter reads per update to the metrics table, i.e. if the metrics table update happens every 1 second, this value could be up to 1000 if the smu collected metrics data every cycle, or as low as 0 if the smu was asleep the whole time. Reset to 0 after writing. } SmuMetrics_t; typedef struct { -- cgit From 027bf0cee89a27325a9a4f2240c21dd5fb81e4fa Mon Sep 17 00:00:00 2001 From: Tim Huang Date: Thu, 29 Sep 2022 15:06:47 +0800 Subject: drm/amd/pm: add SMU IP v13.0.4 IF version define to V7 The pmfw has changed the driver interface version, so keep same with the fw. Signed-off-by: Tim Huang Reviewed-by: Mario Limonciello Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org # 6.0.x --- drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h index 9d62ea2af132..8f72202aea8e 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h @@ -28,7 +28,7 @@ #define SMU13_DRIVER_IF_VERSION_INV 0xFFFFFFFF #define SMU13_DRIVER_IF_VERSION_YELLOW_CARP 0x04 #define SMU13_DRIVER_IF_VERSION_ALDE 0x08 -#define SMU13_DRIVER_IF_VERSION_SMU_V13_0_4 0x05 +#define SMU13_DRIVER_IF_VERSION_SMU_V13_0_4 0x07 #define SMU13_DRIVER_IF_VERSION_SMU_V13_0_5 0x04 #define SMU13_DRIVER_IF_VERSION_SMU_V13_0_0 0x30 #define SMU13_DRIVER_IF_VERSION_SMU_V13_0_7 0x2C -- cgit From 6c0ca748205dc815505c6de79ecf565953390b66 Mon Sep 17 00:00:00 2001 From: Hawking Zhang Date: Fri, 14 Oct 2022 15:17:43 +0800 Subject: drm/amdgpu: move convert_error_address out of umc_ras RAS error address translation algorithm is common across dGPU and A + A platform as along as the SOC integrates the same generation of UMC IP. UMC RAS is managed by x86 MCA on A + A platform, umc_ras in GPU driver is not initialized at all on A + A platform. In such case, any umc_ras callback implemented for dGPU config shouldn't be invoked from A + A specific callback. The change moves convert_error_address out of dGPU umc_ras structure and makes it share between A + A and dGPU config. Signed-off-by: Hawking Zhang Reviewed-by: Stanley Yang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c | 16 ++++++++++++---- drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h | 3 --- drivers/gpu/drm/amd/amdgpu/umc_v6_7.c | 7 +++---- drivers/gpu/drm/amd/amdgpu/umc_v6_7.h | 4 +++- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index a4b47e1bd111..21a47f2bb87b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -36,6 +36,7 @@ #include "ivsrcid/nbio/irqsrcs_nbif_7_4.h" #include "atom.h" #include "amdgpu_reset.h" +#include "umc_v6_7.h" #ifdef CONFIG_X86_MCE_AMD #include @@ -2899,10 +2900,17 @@ static int amdgpu_bad_page_notifier(struct notifier_block *nb, /* * Translate UMC channel address to Physical address */ - if (adev->umc.ras && - adev->umc.ras->convert_ras_error_address) - adev->umc.ras->convert_ras_error_address(adev, - &err_data, m->addr, ch_inst, umc_inst); + switch (adev->ip_versions[UMC_HWIP][0]) { + case IP_VERSION(6, 7, 0): + umc_v6_7_convert_error_address(adev, + &err_data, m->addr, ch_inst, umc_inst); + break; + default: + dev_warn(adev->dev, + "UMC address to Physical address translation is not supported\n"); + kfree(err_data.err_addr); + return NOTIFY_DONE; + } if (amdgpu_bad_page_threshold != 0) { amdgpu_ras_add_bad_pages(adev, err_data.err_addr, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h index e46439274f3a..3629d8f292ef 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h @@ -51,9 +51,6 @@ struct amdgpu_umc_ras { struct amdgpu_ras_block_object ras_block; void (*err_cnt_init)(struct amdgpu_device *adev); bool (*query_ras_poison_mode)(struct amdgpu_device *adev); - void (*convert_ras_error_address)(struct amdgpu_device *adev, - struct ras_err_data *err_data, uint64_t err_addr, - uint32_t ch_inst, uint32_t umc_inst); void (*ecc_info_query_ras_error_count)(struct amdgpu_device *adev, void *ras_error_status); void (*ecc_info_query_ras_error_address)(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/amdgpu/umc_v6_7.c b/drivers/gpu/drm/amd/amdgpu/umc_v6_7.c index 5d5d031c9e7d..72fd963f178b 100644 --- a/drivers/gpu/drm/amd/amdgpu/umc_v6_7.c +++ b/drivers/gpu/drm/amd/amdgpu/umc_v6_7.c @@ -187,9 +187,9 @@ static void umc_v6_7_ecc_info_query_ras_error_count(struct amdgpu_device *adev, } } -static void umc_v6_7_convert_error_address(struct amdgpu_device *adev, - struct ras_err_data *err_data, uint64_t err_addr, - uint32_t ch_inst, uint32_t umc_inst) +void umc_v6_7_convert_error_address(struct amdgpu_device *adev, + struct ras_err_data *err_data, uint64_t err_addr, + uint32_t ch_inst, uint32_t umc_inst) { uint32_t channel_index; uint64_t soc_pa, retired_page, column; @@ -553,5 +553,4 @@ struct amdgpu_umc_ras umc_v6_7_ras = { .query_ras_poison_mode = umc_v6_7_query_ras_poison_mode, .ecc_info_query_ras_error_count = umc_v6_7_ecc_info_query_ras_error_count, .ecc_info_query_ras_error_address = umc_v6_7_ecc_info_query_ras_error_address, - .convert_ras_error_address = umc_v6_7_convert_error_address, }; diff --git a/drivers/gpu/drm/amd/amdgpu/umc_v6_7.h b/drivers/gpu/drm/amd/amdgpu/umc_v6_7.h index fe41ed2f5945..105245d5b6e5 100644 --- a/drivers/gpu/drm/amd/amdgpu/umc_v6_7.h +++ b/drivers/gpu/drm/amd/amdgpu/umc_v6_7.h @@ -71,5 +71,7 @@ extern const uint32_t umc_v6_7_channel_idx_tbl_second[UMC_V6_7_UMC_INSTANCE_NUM][UMC_V6_7_CHANNEL_INSTANCE_NUM]; extern const uint32_t umc_v6_7_channel_idx_tbl_first[UMC_V6_7_UMC_INSTANCE_NUM][UMC_V6_7_CHANNEL_INSTANCE_NUM]; - +void umc_v6_7_convert_error_address(struct amdgpu_device *adev, + struct ras_err_data *err_data, uint64_t err_addr, + uint32_t ch_inst, uint32_t umc_inst); #endif -- cgit From 45950d88709ce1cd77756aec2e78b2b8dfc58894 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 13 Oct 2022 11:25:23 -0700 Subject: drm/amd/display: Increase frame size limit for display_mode_vba_util_32.o MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Building 32-bit images may fail with the following error. drivers/gpu/drm/amd/amdgpu/../display/dc/dml/dcn32/display_mode_vba_util_32.c: In function ‘dml32_UseMinimumDCFCLK’: drivers/gpu/drm/amd/amdgpu/../display/dc/dml/dcn32/display_mode_vba_util_32.c:3142:1: error: the frame size of 1096 bytes is larger than 1024 bytes This is seen when building i386:allmodconfig with any of the following compilers. gcc (Debian 12.2.0-3) 12.2.0 gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0 The problem is not seen if the compiler supports GCC_PLUGIN_LATENT_ENTROPY because in that case CONFIG_FRAME_WARN is already set to 2048 even for 32-bit builds. dml32_UseMinimumDCFCLK() was introduced with commit dda4fb85e433 ("drm/amd/display: DML changes for DCN32/321"). It declares a large number of local variables. Increase the frame size for the affected file to 2048, similar to other files in the same directory, to enable 32-bit build tests with affected compilers. Fixes: dda4fb85e433 ("drm/amd/display: DML changes for DCN32/321") Cc: Aurabindo Pillai Reported-by: Łukasz Bartosik Signed-off-by: Guenter Roeck Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dml/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dml/Makefile b/drivers/gpu/drm/amd/display/dc/dml/Makefile index d70838edba80..ca7d24000621 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dml/Makefile @@ -77,7 +77,7 @@ CFLAGS_$(AMDDALPATH)/dc/dml/dcn30/dcn30_fpu.o := $(dml_ccflags) CFLAGS_$(AMDDALPATH)/dc/dml/dcn32/dcn32_fpu.o := $(dml_ccflags) CFLAGS_$(AMDDALPATH)/dc/dml/dcn32/display_mode_vba_32.o := $(dml_ccflags) $(frame_warn_flag) CFLAGS_$(AMDDALPATH)/dc/dml/dcn32/display_rq_dlg_calc_32.o := $(dml_ccflags) -CFLAGS_$(AMDDALPATH)/dc/dml/dcn32/display_mode_vba_util_32.o := $(dml_ccflags) +CFLAGS_$(AMDDALPATH)/dc/dml/dcn32/display_mode_vba_util_32.o := $(dml_ccflags) $(frame_warn_flag) CFLAGS_$(AMDDALPATH)/dc/dml/dcn321/dcn321_fpu.o := $(dml_ccflags) CFLAGS_$(AMDDALPATH)/dc/dml/dcn31/dcn31_fpu.o := $(dml_ccflags) CFLAGS_$(AMDDALPATH)/dc/dml/dcn301/dcn301_fpu.o := $(dml_ccflags) -- cgit From cdabbde1ed262090bff45929e1f5c1153ba5003e Mon Sep 17 00:00:00 2001 From: "Fabio M. De Francesco" Date: Thu, 13 Oct 2022 23:07:14 +0200 Subject: drm/radeon: Replace kmap() with kmap_local_page() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The use of kmap() is being deprecated in favor of kmap_local_page(). There are two main problems with kmap(): (1) It comes with an overhead as the mapping space is restricted and protected by a global lock for synchronization and (2) it also requires global TLB invalidation when the kmap’s pool wraps and it might block when the mapping space is fully utilized until a slot becomes available. With kmap_local_page() the mappings are per thread, CPU local, can take page faults, and can be called from any context (including interrupts). It is faster than kmap() in kernels with HIGHMEM enabled. Furthermore, the tasks can be preempted and, when they are scheduled to run again, the kernel virtual addresses are restored and still valid. Therefore, replace kmap() with kmap_local_page() in radeon_ttm_gtt_read(). Cc: "Venkataramanan, Anirudh" Reviewed-by: Kees Cook Reviewed-by: Christian König Suggested-by: Ira Weiny Signed-off-by: Fabio M. De Francesco Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_ttm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index d33fec488713..bdb4c0e0736b 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -869,11 +869,11 @@ static ssize_t radeon_ttm_gtt_read(struct file *f, char __user *buf, page = rdev->gart.pages[p]; if (page) { - ptr = kmap(page); + ptr = kmap_local_page(page); ptr += off; r = copy_to_user(buf, ptr, cur_size); - kunmap(rdev->gart.pages[p]); + kunmap_local(ptr); } else r = clear_user(buf, cur_size); -- cgit From a2c554262d39f81be7422fd8bee2f2fe3779f7f5 Mon Sep 17 00:00:00 2001 From: "Fabio M. De Francesco" Date: Sun, 16 Oct 2022 19:41:58 +0200 Subject: drm/amd/amdgpu: Replace kmap() with kmap_local_page() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit kmap() is being deprecated in favor of kmap_local_page(). There are two main problems with kmap(): (1) It comes with an overhead as mapping space is restricted and protected by a global lock for synchronization and (2) it also requires global TLB invalidation when the kmap’s pool wraps and it might block when the mapping space is fully utilized until a slot becomes available. With kmap_local_page() the mappings are per thread, CPU local, can take page faults, and can be called from any context (including interrupts). It is faster than kmap() in kernels with HIGHMEM enabled. Furthermore, the tasks can be preempted and, when they are scheduled to run again, the kernel virtual addresses are restored and are still valid. Since its use in amdgpu/amdgpu_ttm.c is safe, it should be preferred. Therefore, replace kmap() with kmap_local_page() in amdgpu/amdgpu_ttm.c. Suggested-by: Ira Weiny Acked-by: Christian König Signed-off-by: Fabio M. De Francesco Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index dc262d2c2925..8782fc6bcd2c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -2292,9 +2292,9 @@ static ssize_t amdgpu_iomem_read(struct file *f, char __user *buf, if (p->mapping != adev->mman.bdev.dev_mapping) return -EPERM; - ptr = kmap(p); + ptr = kmap_local_page(p); r = copy_to_user(buf, ptr + off, bytes); - kunmap(p); + kunmap_local(ptr); if (r) return -EFAULT; @@ -2343,9 +2343,9 @@ static ssize_t amdgpu_iomem_write(struct file *f, const char __user *buf, if (p->mapping != adev->mman.bdev.dev_mapping) return -EPERM; - ptr = kmap(p); + ptr = kmap_local_page(p); r = copy_from_user(ptr + off, buf, bytes); - kunmap(p); + kunmap_local(ptr); if (r) return -EFAULT; -- cgit From e299b00adf3d4505132e624894f549422ad05eeb Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Mon, 17 Oct 2022 09:28:38 -0700 Subject: drm/amdkfd: Fix type of reset_type parameter in hqd_destroy() callback When booting a kernel compiled with CONFIG_CFI_CLANG on a machine with an RX 6700 XT, there is a CFI failure in kfd_destroy_mqd_cp(): [ 12.894543] CFI failure at kfd_destroy_mqd_cp+0x2a/0x40 [amdgpu] (target: hqd_destroy_v10_3+0x0/0x260 [amdgpu]; expected type: 0x8594d794) Clang's kernel Control Flow Integrity (kCFI) makes sure that all indirect call targets have a type that exactly matches the function pointer prototype. In this case, hqd_destroy()'s third parameter, reset_type, should have a type of 'uint32_t' but every implementation of this callback has a third parameter type of 'enum kfd_preempt_type'. Update the function pointer prototype to match reality so that there is no more CFI violation. Link: https://github.com/ClangBuiltLinux/linux/issues/1738 Signed-off-by: Nathan Chancellor Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/include/kgd_kfd_interface.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h index e85364dff4e0..5cb3e8634739 100644 --- a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h @@ -262,8 +262,9 @@ struct kfd2kgd_calls { uint32_t queue_id); int (*hqd_destroy)(struct amdgpu_device *adev, void *mqd, - uint32_t reset_type, unsigned int timeout, - uint32_t pipe_id, uint32_t queue_id); + enum kfd_preempt_type reset_type, + unsigned int timeout, uint32_t pipe_id, + uint32_t queue_id); bool (*hqd_sdma_is_occupied)(struct amdgpu_device *adev, void *mqd); -- cgit From b3372fa74d2a7f840bea706607ee2224dfd24039 Mon Sep 17 00:00:00 2001 From: Hamza Mahfooz Date: Fri, 14 Oct 2022 10:29:46 -0400 Subject: drm/amd/display: add an ASSERT() to irq service functions Currently, if we encounter unimplemented functions, it is difficult to tell what caused them just by looking at dmesg and that is compounded by the fact that it is often hard to reproduce said issues, for instance we have had reports of this condition being triggered when removing a secondary display that is setup in mirror mode and is connected using usb-c. So, to have access to more detailed debugging information, add an ASSERT() to dal_irq_service_ack() and dal_irq_service_set() that only triggers when we encounter an unimplemented function. Reviewed-by: Harry Wentland Signed-off-by: Hamza Mahfooz Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/irq/irq_service.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/irq/irq_service.c b/drivers/gpu/drm/amd/display/dc/irq/irq_service.c index 7bad39bba86b..d100edaedbbb 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/irq_service.c +++ b/drivers/gpu/drm/amd/display/dc/irq/irq_service.c @@ -112,8 +112,15 @@ bool dal_irq_service_set( dal_irq_service_ack(irq_service, source); - if (info->funcs && info->funcs->set) + if (info->funcs && info->funcs->set) { + if (info->funcs->set == dal_irq_service_dummy_set) { + DC_LOG_WARNING("%s: src: %d, st: %d\n", __func__, + source, enable); + ASSERT(0); + } + return info->funcs->set(irq_service, info, enable); + } dal_irq_service_set_generic(irq_service, info, enable); @@ -146,8 +153,14 @@ bool dal_irq_service_ack( return false; } - if (info->funcs && info->funcs->ack) + if (info->funcs && info->funcs->ack) { + if (info->funcs->ack == dal_irq_service_dummy_ack) { + DC_LOG_WARNING("%s: src: %d\n", __func__, source); + ASSERT(0); + } + return info->funcs->ack(irq_service, info); + } dal_irq_service_ack_generic(irq_service, info); -- cgit From 56e5abba8c3ec5c6098007693f9cefafaa2aa010 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 17 Oct 2022 20:22:09 +0300 Subject: dma-buf: Add unlocked variant of vmapping functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add unlocked variant of dma_buf_vmap/vunmap() that will be utilized by drivers that don't take the reservation lock explicitly. Acked-by: Sumit Semwal Acked-by: Christian König Signed-off-by: Dmitry Osipenko Link: https://patchwork.freedesktop.org/patch/msgid/20221017172229.42269-2-dmitry.osipenko@collabora.com --- drivers/dma-buf/dma-buf.c | 43 +++++++++++++++++++++++++++++++++++++++++++ include/linux/dma-buf.h | 2 ++ 2 files changed, 45 insertions(+) diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index efb4990b29e1..e95fc8dc3aed 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -1425,6 +1425,33 @@ out_unlock: } EXPORT_SYMBOL_NS_GPL(dma_buf_vmap, DMA_BUF); +/** + * dma_buf_vmap_unlocked - Create virtual mapping for the buffer object into kernel + * address space. Same restrictions as for vmap and friends apply. + * @dmabuf: [in] buffer to vmap + * @map: [out] returns the vmap pointer + * + * Unlocked version of dma_buf_vmap() + * + * Returns 0 on success, or a negative errno code otherwise. + */ +int dma_buf_vmap_unlocked(struct dma_buf *dmabuf, struct iosys_map *map) +{ + int ret; + + iosys_map_clear(map); + + if (WARN_ON(!dmabuf)) + return -EINVAL; + + dma_resv_lock(dmabuf->resv, NULL); + ret = dma_buf_vmap(dmabuf, map); + dma_resv_unlock(dmabuf->resv); + + return ret; +} +EXPORT_SYMBOL_NS_GPL(dma_buf_vmap_unlocked, DMA_BUF); + /** * dma_buf_vunmap - Unmap a vmap obtained by dma_buf_vmap. * @dmabuf: [in] buffer to vunmap @@ -1449,6 +1476,22 @@ void dma_buf_vunmap(struct dma_buf *dmabuf, struct iosys_map *map) } EXPORT_SYMBOL_NS_GPL(dma_buf_vunmap, DMA_BUF); +/** + * dma_buf_vunmap_unlocked - Unmap a vmap obtained by dma_buf_vmap. + * @dmabuf: [in] buffer to vunmap + * @map: [in] vmap pointer to vunmap + */ +void dma_buf_vunmap_unlocked(struct dma_buf *dmabuf, struct iosys_map *map) +{ + if (WARN_ON(!dmabuf)) + return; + + dma_resv_lock(dmabuf->resv, NULL); + dma_buf_vunmap(dmabuf, map); + dma_resv_unlock(dmabuf->resv); +} +EXPORT_SYMBOL_NS_GPL(dma_buf_vunmap_unlocked, DMA_BUF); + #ifdef CONFIG_DEBUG_FS static int dma_buf_debug_show(struct seq_file *s, void *unused) { diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h index 71731796c8c3..8daa054dd7fe 100644 --- a/include/linux/dma-buf.h +++ b/include/linux/dma-buf.h @@ -632,4 +632,6 @@ int dma_buf_mmap(struct dma_buf *, struct vm_area_struct *, unsigned long); int dma_buf_vmap(struct dma_buf *dmabuf, struct iosys_map *map); void dma_buf_vunmap(struct dma_buf *dmabuf, struct iosys_map *map); +int dma_buf_vmap_unlocked(struct dma_buf *dmabuf, struct iosys_map *map); +void dma_buf_vunmap_unlocked(struct dma_buf *dmabuf, struct iosys_map *map); #endif /* __DMA_BUF_H__ */ -- cgit From 19d6634d8789573a9212ce78dbb4348ffd4f7f78 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 17 Oct 2022 20:22:10 +0300 Subject: dma-buf: Add unlocked variant of attachment-mapping functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add unlocked variant of dma_buf_map/unmap_attachment() that will be used by drivers that don't take the reservation lock explicitly. Acked-by: Sumit Semwal Acked-by: Christian König Signed-off-by: Dmitry Osipenko Link: https://patchwork.freedesktop.org/patch/msgid/20221017172229.42269-3-dmitry.osipenko@collabora.com --- drivers/dma-buf/dma-buf.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++ include/linux/dma-buf.h | 6 ++++++ 2 files changed, 59 insertions(+) diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index e95fc8dc3aed..3e4060dadb74 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -1100,6 +1100,34 @@ struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach, } EXPORT_SYMBOL_NS_GPL(dma_buf_map_attachment, DMA_BUF); +/** + * dma_buf_map_attachment_unlocked - Returns the scatterlist table of the attachment; + * mapped into _device_ address space. Is a wrapper for map_dma_buf() of the + * dma_buf_ops. + * @attach: [in] attachment whose scatterlist is to be returned + * @direction: [in] direction of DMA transfer + * + * Unlocked variant of dma_buf_map_attachment(). + */ +struct sg_table * +dma_buf_map_attachment_unlocked(struct dma_buf_attachment *attach, + enum dma_data_direction direction) +{ + struct sg_table *sg_table; + + might_sleep(); + + if (WARN_ON(!attach || !attach->dmabuf)) + return ERR_PTR(-EINVAL); + + dma_resv_lock(attach->dmabuf->resv, NULL); + sg_table = dma_buf_map_attachment(attach, direction); + dma_resv_unlock(attach->dmabuf->resv); + + return sg_table; +} +EXPORT_SYMBOL_NS_GPL(dma_buf_map_attachment_unlocked, DMA_BUF); + /** * dma_buf_unmap_attachment - unmaps and decreases usecount of the buffer;might * deallocate the scatterlist associated. Is a wrapper for unmap_dma_buf() of @@ -1136,6 +1164,31 @@ void dma_buf_unmap_attachment(struct dma_buf_attachment *attach, } EXPORT_SYMBOL_NS_GPL(dma_buf_unmap_attachment, DMA_BUF); +/** + * dma_buf_unmap_attachment_unlocked - unmaps and decreases usecount of the buffer;might + * deallocate the scatterlist associated. Is a wrapper for unmap_dma_buf() of + * dma_buf_ops. + * @attach: [in] attachment to unmap buffer from + * @sg_table: [in] scatterlist info of the buffer to unmap + * @direction: [in] direction of DMA transfer + * + * Unlocked variant of dma_buf_unmap_attachment(). + */ +void dma_buf_unmap_attachment_unlocked(struct dma_buf_attachment *attach, + struct sg_table *sg_table, + enum dma_data_direction direction) +{ + might_sleep(); + + if (WARN_ON(!attach || !attach->dmabuf || !sg_table)) + return; + + dma_resv_lock(attach->dmabuf->resv, NULL); + dma_buf_unmap_attachment(attach, sg_table, direction); + dma_resv_unlock(attach->dmabuf->resv); +} +EXPORT_SYMBOL_NS_GPL(dma_buf_unmap_attachment_unlocked, DMA_BUF); + /** * dma_buf_move_notify - notify attachments that DMA-buf is moving * diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h index 8daa054dd7fe..f11b5bbc2f37 100644 --- a/include/linux/dma-buf.h +++ b/include/linux/dma-buf.h @@ -627,6 +627,12 @@ int dma_buf_begin_cpu_access(struct dma_buf *dma_buf, enum dma_data_direction dir); int dma_buf_end_cpu_access(struct dma_buf *dma_buf, enum dma_data_direction dir); +struct sg_table * +dma_buf_map_attachment_unlocked(struct dma_buf_attachment *attach, + enum dma_data_direction direction); +void dma_buf_unmap_attachment_unlocked(struct dma_buf_attachment *attach, + struct sg_table *sg_table, + enum dma_data_direction direction); int dma_buf_mmap(struct dma_buf *, struct vm_area_struct *, unsigned long); -- cgit From 79e2cf2e7a193473dfb0da3b9b869682b43dc60f Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 17 Oct 2022 20:22:11 +0300 Subject: drm/gem: Take reservation lock for vmap/vunmap operations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The new common dma-buf locking convention will require buffer importers to hold the reservation lock around mapping operations. Make DRM GEM core to take the lock around the vmapping operations and update DRM drivers to use the locked functions for the case where DRM core now holds the lock. This patch prepares DRM core and drivers to the common dynamic dma-buf locking convention. Acked-by: Christian König Signed-off-by: Dmitry Osipenko Link: https://patchwork.freedesktop.org/patch/msgid/20221017172229.42269-4-dmitry.osipenko@collabora.com --- drivers/gpu/drm/drm_client.c | 4 ++-- drivers/gpu/drm/drm_gem.c | 24 ++++++++++++++++++++++++ drivers/gpu/drm/drm_gem_dma_helper.c | 6 +++--- drivers/gpu/drm/drm_gem_framebuffer_helper.c | 6 +++--- drivers/gpu/drm/drm_gem_ttm_helper.c | 9 +-------- drivers/gpu/drm/lima/lima_sched.c | 4 ++-- drivers/gpu/drm/panfrost/panfrost_dump.c | 4 ++-- drivers/gpu/drm/panfrost/panfrost_perfcnt.c | 6 +++--- drivers/gpu/drm/qxl/qxl_object.c | 17 +++++++++-------- drivers/gpu/drm/qxl/qxl_prime.c | 4 ++-- include/drm/drm_gem.h | 3 +++ 11 files changed, 54 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c index 2b230b4d6942..fbcb1e995384 100644 --- a/drivers/gpu/drm/drm_client.c +++ b/drivers/gpu/drm/drm_client.c @@ -323,7 +323,7 @@ drm_client_buffer_vmap(struct drm_client_buffer *buffer, * fd_install step out of the driver backend hooks, to make that * final step optional for internal users. */ - ret = drm_gem_vmap(buffer->gem, map); + ret = drm_gem_vmap_unlocked(buffer->gem, map); if (ret) return ret; @@ -345,7 +345,7 @@ void drm_client_buffer_vunmap(struct drm_client_buffer *buffer) { struct iosys_map *map = &buffer->map; - drm_gem_vunmap(buffer->gem, map); + drm_gem_vunmap_unlocked(buffer->gem, map); } EXPORT_SYMBOL(drm_client_buffer_vunmap); diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 86d670c71286..dbee4863e4f7 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -1171,6 +1171,8 @@ int drm_gem_vmap(struct drm_gem_object *obj, struct iosys_map *map) { int ret; + dma_resv_assert_held(obj->resv); + if (!obj->funcs->vmap) return -EOPNOTSUPP; @@ -1186,6 +1188,8 @@ EXPORT_SYMBOL(drm_gem_vmap); void drm_gem_vunmap(struct drm_gem_object *obj, struct iosys_map *map) { + dma_resv_assert_held(obj->resv); + if (iosys_map_is_null(map)) return; @@ -1197,6 +1201,26 @@ void drm_gem_vunmap(struct drm_gem_object *obj, struct iosys_map *map) } EXPORT_SYMBOL(drm_gem_vunmap); +int drm_gem_vmap_unlocked(struct drm_gem_object *obj, struct iosys_map *map) +{ + int ret; + + dma_resv_lock(obj->resv, NULL); + ret = drm_gem_vmap(obj, map); + dma_resv_unlock(obj->resv); + + return ret; +} +EXPORT_SYMBOL(drm_gem_vmap_unlocked); + +void drm_gem_vunmap_unlocked(struct drm_gem_object *obj, struct iosys_map *map) +{ + dma_resv_lock(obj->resv, NULL); + drm_gem_vunmap(obj, map); + dma_resv_unlock(obj->resv); +} +EXPORT_SYMBOL(drm_gem_vunmap_unlocked); + /** * drm_gem_lock_reservations - Sets up the ww context and acquires * the lock on an array of GEM objects. diff --git a/drivers/gpu/drm/drm_gem_dma_helper.c b/drivers/gpu/drm/drm_gem_dma_helper.c index f6901ff97bbb..1e658c448366 100644 --- a/drivers/gpu/drm/drm_gem_dma_helper.c +++ b/drivers/gpu/drm/drm_gem_dma_helper.c @@ -230,7 +230,7 @@ void drm_gem_dma_free(struct drm_gem_dma_object *dma_obj) if (gem_obj->import_attach) { if (dma_obj->vaddr) - dma_buf_vunmap(gem_obj->import_attach->dmabuf, &map); + dma_buf_vunmap_unlocked(gem_obj->import_attach->dmabuf, &map); drm_prime_gem_destroy(gem_obj, dma_obj->sgt); } else if (dma_obj->vaddr) { if (dma_obj->map_noncoherent) @@ -581,7 +581,7 @@ drm_gem_dma_prime_import_sg_table_vmap(struct drm_device *dev, struct iosys_map map; int ret; - ret = dma_buf_vmap(attach->dmabuf, &map); + ret = dma_buf_vmap_unlocked(attach->dmabuf, &map); if (ret) { DRM_ERROR("Failed to vmap PRIME buffer\n"); return ERR_PTR(ret); @@ -589,7 +589,7 @@ drm_gem_dma_prime_import_sg_table_vmap(struct drm_device *dev, obj = drm_gem_dma_prime_import_sg_table(dev, attach, sgt); if (IS_ERR(obj)) { - dma_buf_vunmap(attach->dmabuf, &map); + dma_buf_vunmap_unlocked(attach->dmabuf, &map); return obj; } diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c index 880a4975507f..e35e224e6303 100644 --- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c +++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c @@ -354,7 +354,7 @@ int drm_gem_fb_vmap(struct drm_framebuffer *fb, struct iosys_map *map, ret = -EINVAL; goto err_drm_gem_vunmap; } - ret = drm_gem_vmap(obj, &map[i]); + ret = drm_gem_vmap_unlocked(obj, &map[i]); if (ret) goto err_drm_gem_vunmap; } @@ -376,7 +376,7 @@ err_drm_gem_vunmap: obj = drm_gem_fb_get_obj(fb, i); if (!obj) continue; - drm_gem_vunmap(obj, &map[i]); + drm_gem_vunmap_unlocked(obj, &map[i]); } return ret; } @@ -403,7 +403,7 @@ void drm_gem_fb_vunmap(struct drm_framebuffer *fb, struct iosys_map *map) continue; if (iosys_map_is_null(&map[i])) continue; - drm_gem_vunmap(obj, &map[i]); + drm_gem_vunmap_unlocked(obj, &map[i]); } } EXPORT_SYMBOL(drm_gem_fb_vunmap); diff --git a/drivers/gpu/drm/drm_gem_ttm_helper.c b/drivers/gpu/drm/drm_gem_ttm_helper.c index e5fc875990c4..d5962a34c01d 100644 --- a/drivers/gpu/drm/drm_gem_ttm_helper.c +++ b/drivers/gpu/drm/drm_gem_ttm_helper.c @@ -64,13 +64,8 @@ int drm_gem_ttm_vmap(struct drm_gem_object *gem, struct iosys_map *map) { struct ttm_buffer_object *bo = drm_gem_ttm_of_gem(gem); - int ret; - - dma_resv_lock(gem->resv, NULL); - ret = ttm_bo_vmap(bo, map); - dma_resv_unlock(gem->resv); - return ret; + return ttm_bo_vmap(bo, map); } EXPORT_SYMBOL(drm_gem_ttm_vmap); @@ -87,9 +82,7 @@ void drm_gem_ttm_vunmap(struct drm_gem_object *gem, { struct ttm_buffer_object *bo = drm_gem_ttm_of_gem(gem); - dma_resv_lock(gem->resv, NULL); ttm_bo_vunmap(bo, map); - dma_resv_unlock(gem->resv); } EXPORT_SYMBOL(drm_gem_ttm_vunmap); diff --git a/drivers/gpu/drm/lima/lima_sched.c b/drivers/gpu/drm/lima/lima_sched.c index e82931712d8a..ff003403fbbc 100644 --- a/drivers/gpu/drm/lima/lima_sched.c +++ b/drivers/gpu/drm/lima/lima_sched.c @@ -371,7 +371,7 @@ static void lima_sched_build_error_task_list(struct lima_sched_task *task) } else { buffer_chunk->size = lima_bo_size(bo); - ret = drm_gem_shmem_vmap(&bo->base, &map); + ret = drm_gem_vmap_unlocked(&bo->base.base, &map); if (ret) { kvfree(et); goto out; @@ -379,7 +379,7 @@ static void lima_sched_build_error_task_list(struct lima_sched_task *task) memcpy(buffer_chunk + 1, map.vaddr, buffer_chunk->size); - drm_gem_shmem_vunmap(&bo->base, &map); + drm_gem_vunmap_unlocked(&bo->base.base, &map); } buffer_chunk = (void *)(buffer_chunk + 1) + buffer_chunk->size; diff --git a/drivers/gpu/drm/panfrost/panfrost_dump.c b/drivers/gpu/drm/panfrost/panfrost_dump.c index 89056a1aac7d..f62a019cc523 100644 --- a/drivers/gpu/drm/panfrost/panfrost_dump.c +++ b/drivers/gpu/drm/panfrost/panfrost_dump.c @@ -209,7 +209,7 @@ void panfrost_core_dump(struct panfrost_job *job) goto dump_header; } - ret = drm_gem_shmem_vmap(&bo->base, &map); + ret = drm_gem_vmap_unlocked(&bo->base.base, &map); if (ret) { dev_err(pfdev->dev, "Panfrost Dump: couldn't map Buffer Object\n"); iter.hdr->bomap.valid = 0; @@ -236,7 +236,7 @@ void panfrost_core_dump(struct panfrost_job *job) vaddr = map.vaddr; memcpy(iter.data, vaddr, bo->base.base.size); - drm_gem_shmem_vunmap(&bo->base, &map); + drm_gem_vunmap_unlocked(&bo->base.base, &map); iter.hdr->bomap.valid = cpu_to_le32(1); diff --git a/drivers/gpu/drm/panfrost/panfrost_perfcnt.c b/drivers/gpu/drm/panfrost/panfrost_perfcnt.c index bc0df93f7f21..ba9b6e2b2636 100644 --- a/drivers/gpu/drm/panfrost/panfrost_perfcnt.c +++ b/drivers/gpu/drm/panfrost/panfrost_perfcnt.c @@ -106,7 +106,7 @@ static int panfrost_perfcnt_enable_locked(struct panfrost_device *pfdev, goto err_close_bo; } - ret = drm_gem_shmem_vmap(bo, &map); + ret = drm_gem_vmap_unlocked(&bo->base, &map); if (ret) goto err_put_mapping; perfcnt->buf = map.vaddr; @@ -165,7 +165,7 @@ static int panfrost_perfcnt_enable_locked(struct panfrost_device *pfdev, return 0; err_vunmap: - drm_gem_shmem_vunmap(bo, &map); + drm_gem_vunmap_unlocked(&bo->base, &map); err_put_mapping: panfrost_gem_mapping_put(perfcnt->mapping); err_close_bo: @@ -195,7 +195,7 @@ static int panfrost_perfcnt_disable_locked(struct panfrost_device *pfdev, GPU_PERFCNT_CFG_MODE(GPU_PERFCNT_CFG_MODE_OFF)); perfcnt->user = NULL; - drm_gem_shmem_vunmap(&perfcnt->mapping->obj->base, &map); + drm_gem_vunmap_unlocked(&perfcnt->mapping->obj->base.base, &map); perfcnt->buf = NULL; panfrost_gem_close(&perfcnt->mapping->obj->base.base, file_priv); panfrost_mmu_as_put(pfdev, perfcnt->mapping->mmu); diff --git a/drivers/gpu/drm/qxl/qxl_object.c b/drivers/gpu/drm/qxl/qxl_object.c index 695d9308d1f0..06a58dad5f5c 100644 --- a/drivers/gpu/drm/qxl/qxl_object.c +++ b/drivers/gpu/drm/qxl/qxl_object.c @@ -168,9 +168,16 @@ int qxl_bo_vmap_locked(struct qxl_bo *bo, struct iosys_map *map) bo->map_count++; goto out; } - r = ttm_bo_vmap(&bo->tbo, &bo->map); + + r = __qxl_bo_pin(bo); if (r) return r; + + r = ttm_bo_vmap(&bo->tbo, &bo->map); + if (r) { + __qxl_bo_unpin(bo); + return r; + } bo->map_count = 1; /* TODO: Remove kptr in favor of map everywhere. */ @@ -192,12 +199,6 @@ int qxl_bo_vmap(struct qxl_bo *bo, struct iosys_map *map) if (r) return r; - r = __qxl_bo_pin(bo); - if (r) { - qxl_bo_unreserve(bo); - return r; - } - r = qxl_bo_vmap_locked(bo, map); qxl_bo_unreserve(bo); return r; @@ -247,6 +248,7 @@ void qxl_bo_vunmap_locked(struct qxl_bo *bo) return; bo->kptr = NULL; ttm_bo_vunmap(&bo->tbo, &bo->map); + __qxl_bo_unpin(bo); } int qxl_bo_vunmap(struct qxl_bo *bo) @@ -258,7 +260,6 @@ int qxl_bo_vunmap(struct qxl_bo *bo) return r; qxl_bo_vunmap_locked(bo); - __qxl_bo_unpin(bo); qxl_bo_unreserve(bo); return 0; } diff --git a/drivers/gpu/drm/qxl/qxl_prime.c b/drivers/gpu/drm/qxl/qxl_prime.c index 142d01415acb..9169c26357d3 100644 --- a/drivers/gpu/drm/qxl/qxl_prime.c +++ b/drivers/gpu/drm/qxl/qxl_prime.c @@ -59,7 +59,7 @@ int qxl_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map) struct qxl_bo *bo = gem_to_qxl_bo(obj); int ret; - ret = qxl_bo_vmap(bo, map); + ret = qxl_bo_vmap_locked(bo, map); if (ret < 0) return ret; @@ -71,5 +71,5 @@ void qxl_gem_prime_vunmap(struct drm_gem_object *obj, { struct qxl_bo *bo = gem_to_qxl_bo(obj); - qxl_bo_vunmap(bo); + qxl_bo_vunmap_locked(bo); } diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h index 58a18a17c67e..ed82039bfd5b 100644 --- a/include/drm/drm_gem.h +++ b/include/drm/drm_gem.h @@ -408,6 +408,9 @@ struct page **drm_gem_get_pages(struct drm_gem_object *obj); void drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages, bool dirty, bool accessed); +int drm_gem_vmap_unlocked(struct drm_gem_object *obj, struct iosys_map *map); +void drm_gem_vunmap_unlocked(struct drm_gem_object *obj, struct iosys_map *map); + int drm_gem_objects_lookup(struct drm_file *filp, void __user *bo_handles, int count, struct drm_gem_object ***objs_out); struct drm_gem_object *drm_gem_object_lookup(struct drm_file *filp, u32 handle); -- cgit From ac530e0b1fc0fc69c634f9204b03f5aaccd55355 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 17 Oct 2022 20:22:12 +0300 Subject: drm/prime: Prepare to dynamic dma-buf locking specification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prepare DRM prime core to the common dynamic dma-buf locking convention by starting to use the unlocked versions of dma-buf API functions. Reviewed-by: Christian König Signed-off-by: Dmitry Osipenko Link: https://patchwork.freedesktop.org/patch/msgid/20221017172229.42269-5-dmitry.osipenko@collabora.com --- drivers/gpu/drm/drm_prime.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index a3f180653b8b..ef50c4e2e509 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c @@ -936,7 +936,7 @@ struct drm_gem_object *drm_gem_prime_import_dev(struct drm_device *dev, get_dma_buf(dma_buf); - sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); + sgt = dma_buf_map_attachment_unlocked(attach, DMA_BIDIRECTIONAL); if (IS_ERR(sgt)) { ret = PTR_ERR(sgt); goto fail_detach; @@ -954,7 +954,7 @@ struct drm_gem_object *drm_gem_prime_import_dev(struct drm_device *dev, return obj; fail_unmap: - dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL); + dma_buf_unmap_attachment_unlocked(attach, sgt, DMA_BIDIRECTIONAL); fail_detach: dma_buf_detach(dma_buf, attach); dma_buf_put(dma_buf); @@ -1052,7 +1052,7 @@ void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg) attach = obj->import_attach; if (sg) - dma_buf_unmap_attachment(attach, sg, DMA_BIDIRECTIONAL); + dma_buf_unmap_attachment_unlocked(attach, sg, DMA_BIDIRECTIONAL); dma_buf = attach->dmabuf; dma_buf_detach(attach->dmabuf, attach); /* remove the reference */ -- cgit From e4ea542846d0ef2127d4feb75b7de78ab1266ead Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 17 Oct 2022 20:22:13 +0300 Subject: drm/armada: Prepare to dynamic dma-buf locking specification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prepare Armada driver to the common dynamic dma-buf locking convention by starting to use the unlocked versions of dma-buf API functions. Acked-by: Christian König Signed-off-by: Dmitry Osipenko Link: https://patchwork.freedesktop.org/patch/msgid/20221017172229.42269-6-dmitry.osipenko@collabora.com --- drivers/gpu/drm/armada/armada_gem.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_gem.c b/drivers/gpu/drm/armada/armada_gem.c index 5430265ad458..26d10065d534 100644 --- a/drivers/gpu/drm/armada/armada_gem.c +++ b/drivers/gpu/drm/armada/armada_gem.c @@ -66,8 +66,8 @@ void armada_gem_free_object(struct drm_gem_object *obj) if (dobj->obj.import_attach) { /* We only ever display imported data */ if (dobj->sgt) - dma_buf_unmap_attachment(dobj->obj.import_attach, - dobj->sgt, DMA_TO_DEVICE); + dma_buf_unmap_attachment_unlocked(dobj->obj.import_attach, + dobj->sgt, DMA_TO_DEVICE); drm_prime_gem_destroy(&dobj->obj, NULL); } @@ -539,8 +539,8 @@ int armada_gem_map_import(struct armada_gem_object *dobj) { int ret; - dobj->sgt = dma_buf_map_attachment(dobj->obj.import_attach, - DMA_TO_DEVICE); + dobj->sgt = dma_buf_map_attachment_unlocked(dobj->obj.import_attach, + DMA_TO_DEVICE); if (IS_ERR(dobj->sgt)) { ret = PTR_ERR(dobj->sgt); dobj->sgt = NULL; -- cgit From f2d8e15ba18b708ab937b31f4af39ebd804eef1b Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 17 Oct 2022 20:22:14 +0300 Subject: drm/i915: Prepare to dynamic dma-buf locking specification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prepare i915 driver to the common dynamic dma-buf locking convention by starting to use the unlocked versions of dma-buf API functions and handling cases where importer now holds the reservation lock. Acked-by: Christian König Reviewed-by: Michael J. Ruhl Signed-off-by: Dmitry Osipenko Link: https://patchwork.freedesktop.org/patch/msgid/20221017172229.42269-7-dmitry.osipenko@collabora.com --- drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c | 2 +- drivers/gpu/drm/i915/gem/i915_gem_object.c | 14 ++++++++++++++ drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c | 16 ++++++++-------- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c index f5062d0c6333..07eee1c09aaf 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c @@ -72,7 +72,7 @@ static int i915_gem_dmabuf_vmap(struct dma_buf *dma_buf, struct drm_i915_gem_object *obj = dma_buf_to_obj(dma_buf); void *vaddr; - vaddr = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WB); + vaddr = i915_gem_object_pin_map(obj, I915_MAP_WB); if (IS_ERR(vaddr)) return PTR_ERR(vaddr); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c index 85482a04d158..7cab89618bad 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c @@ -290,7 +290,21 @@ void __i915_gem_object_pages_fini(struct drm_i915_gem_object *obj) __i915_gem_object_free_mmaps(obj); atomic_set(&obj->mm.pages_pin_count, 0); + + /* + * dma_buf_unmap_attachment() requires reservation to be + * locked. The imported GEM shouldn't share reservation lock + * and ttm_bo_cleanup_memtype_use() shouldn't be invoked for + * dma-buf, so it's safe to take the lock. + */ + if (obj->base.import_attach) + i915_gem_object_lock(obj, NULL); + __i915_gem_object_put_pages(obj); + + if (obj->base.import_attach) + i915_gem_object_unlock(obj); + GEM_BUG_ON(i915_gem_object_has_pages(obj)); } diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c index 51ed824b020c..f2f3cfad807b 100644 --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c @@ -213,7 +213,7 @@ static int igt_dmabuf_import_same_driver(struct drm_i915_private *i915, goto out_import; } - st = dma_buf_map_attachment(import_attach, DMA_BIDIRECTIONAL); + st = dma_buf_map_attachment_unlocked(import_attach, DMA_BIDIRECTIONAL); if (IS_ERR(st)) { err = PTR_ERR(st); goto out_detach; @@ -226,7 +226,7 @@ static int igt_dmabuf_import_same_driver(struct drm_i915_private *i915, timeout = -ETIME; } err = timeout > 0 ? 0 : timeout; - dma_buf_unmap_attachment(import_attach, st, DMA_BIDIRECTIONAL); + dma_buf_unmap_attachment_unlocked(import_attach, st, DMA_BIDIRECTIONAL); out_detach: dma_buf_detach(dmabuf, import_attach); out_import: @@ -296,7 +296,7 @@ static int igt_dmabuf_import(void *arg) goto out_obj; } - err = dma_buf_vmap(dmabuf, &map); + err = dma_buf_vmap_unlocked(dmabuf, &map); dma_map = err ? NULL : map.vaddr; if (!dma_map) { pr_err("dma_buf_vmap failed\n"); @@ -337,7 +337,7 @@ static int igt_dmabuf_import(void *arg) err = 0; out_dma_map: - dma_buf_vunmap(dmabuf, &map); + dma_buf_vunmap_unlocked(dmabuf, &map); out_obj: i915_gem_object_put(obj); out_dmabuf: @@ -358,7 +358,7 @@ static int igt_dmabuf_import_ownership(void *arg) if (IS_ERR(dmabuf)) return PTR_ERR(dmabuf); - err = dma_buf_vmap(dmabuf, &map); + err = dma_buf_vmap_unlocked(dmabuf, &map); ptr = err ? NULL : map.vaddr; if (!ptr) { pr_err("dma_buf_vmap failed\n"); @@ -367,7 +367,7 @@ static int igt_dmabuf_import_ownership(void *arg) } memset(ptr, 0xc5, PAGE_SIZE); - dma_buf_vunmap(dmabuf, &map); + dma_buf_vunmap_unlocked(dmabuf, &map); obj = to_intel_bo(i915_gem_prime_import(&i915->drm, dmabuf)); if (IS_ERR(obj)) { @@ -418,7 +418,7 @@ static int igt_dmabuf_export_vmap(void *arg) } i915_gem_object_put(obj); - err = dma_buf_vmap(dmabuf, &map); + err = dma_buf_vmap_unlocked(dmabuf, &map); ptr = err ? NULL : map.vaddr; if (!ptr) { pr_err("dma_buf_vmap failed\n"); @@ -435,7 +435,7 @@ static int igt_dmabuf_export_vmap(void *arg) memset(ptr, 0xc5, dmabuf->size); err = 0; - dma_buf_vunmap(dmabuf, &map); + dma_buf_vunmap_unlocked(dmabuf, &map); out: dma_buf_put(dmabuf); return err; -- cgit From 8b0baa8136641c41d02cd6e1b4e701d10f45c88d Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 17 Oct 2022 20:22:15 +0300 Subject: drm/omapdrm: Prepare to dynamic dma-buf locking specification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prepare OMAP DRM driver to the common dynamic dma-buf locking convention by starting to use the unlocked versions of dma-buf API functions. Acked-by: Christian König Signed-off-by: Dmitry Osipenko Link: https://patchwork.freedesktop.org/patch/msgid/20221017172229.42269-8-dmitry.osipenko@collabora.com --- drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c index 393f82e26927..8e194dbc9506 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c +++ b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c @@ -125,7 +125,7 @@ struct drm_gem_object *omap_gem_prime_import(struct drm_device *dev, get_dma_buf(dma_buf); - sgt = dma_buf_map_attachment(attach, DMA_TO_DEVICE); + sgt = dma_buf_map_attachment_unlocked(attach, DMA_TO_DEVICE); if (IS_ERR(sgt)) { ret = PTR_ERR(sgt); goto fail_detach; @@ -142,7 +142,7 @@ struct drm_gem_object *omap_gem_prime_import(struct drm_device *dev, return obj; fail_unmap: - dma_buf_unmap_attachment(attach, sgt, DMA_TO_DEVICE); + dma_buf_unmap_attachment_unlocked(attach, sgt, DMA_TO_DEVICE); fail_detach: dma_buf_detach(dma_buf, attach); dma_buf_put(dma_buf); -- cgit From f66d48c8cc8d996cf10ca9d2ec0d27bb1754dc13 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 17 Oct 2022 20:22:16 +0300 Subject: drm/tegra: Prepare to dynamic dma-buf locking specification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prepare Tegra DRM driver to the common dynamic dma-buf locking convention by starting to use the unlocked versions of dma-buf API functions. Acked-by: Christian König Signed-off-by: Dmitry Osipenko Link: https://patchwork.freedesktop.org/patch/msgid/20221017172229.42269-9-dmitry.osipenko@collabora.com --- drivers/gpu/drm/tegra/gem.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c index 81991090adcc..b09b8ab40ae4 100644 --- a/drivers/gpu/drm/tegra/gem.c +++ b/drivers/gpu/drm/tegra/gem.c @@ -84,7 +84,7 @@ static struct host1x_bo_mapping *tegra_bo_pin(struct device *dev, struct host1x_ goto free; } - map->sgt = dma_buf_map_attachment(map->attach, direction); + map->sgt = dma_buf_map_attachment_unlocked(map->attach, direction); if (IS_ERR(map->sgt)) { dma_buf_detach(buf, map->attach); err = PTR_ERR(map->sgt); @@ -160,7 +160,8 @@ free: static void tegra_bo_unpin(struct host1x_bo_mapping *map) { if (map->attach) { - dma_buf_unmap_attachment(map->attach, map->sgt, map->direction); + dma_buf_unmap_attachment_unlocked(map->attach, map->sgt, + map->direction); dma_buf_detach(map->attach->dmabuf, map->attach); } else { dma_unmap_sgtable(map->dev, map->sgt, map->direction, 0); @@ -181,7 +182,7 @@ static void *tegra_bo_mmap(struct host1x_bo *bo) if (obj->vaddr) { return obj->vaddr; } else if (obj->gem.import_attach) { - ret = dma_buf_vmap(obj->gem.import_attach->dmabuf, &map); + ret = dma_buf_vmap_unlocked(obj->gem.import_attach->dmabuf, &map); return ret ? NULL : map.vaddr; } else { return vmap(obj->pages, obj->num_pages, VM_MAP, @@ -197,7 +198,7 @@ static void tegra_bo_munmap(struct host1x_bo *bo, void *addr) if (obj->vaddr) return; else if (obj->gem.import_attach) - dma_buf_vunmap(obj->gem.import_attach->dmabuf, &map); + dma_buf_vunmap_unlocked(obj->gem.import_attach->dmabuf, &map); else vunmap(addr); } @@ -461,7 +462,7 @@ static struct tegra_bo *tegra_bo_import(struct drm_device *drm, get_dma_buf(buf); - bo->sgt = dma_buf_map_attachment(attach, DMA_TO_DEVICE); + bo->sgt = dma_buf_map_attachment_unlocked(attach, DMA_TO_DEVICE); if (IS_ERR(bo->sgt)) { err = PTR_ERR(bo->sgt); goto detach; @@ -479,7 +480,7 @@ static struct tegra_bo *tegra_bo_import(struct drm_device *drm, detach: if (!IS_ERR_OR_NULL(bo->sgt)) - dma_buf_unmap_attachment(attach, bo->sgt, DMA_TO_DEVICE); + dma_buf_unmap_attachment_unlocked(attach, bo->sgt, DMA_TO_DEVICE); dma_buf_detach(buf, attach); dma_buf_put(buf); @@ -508,8 +509,8 @@ void tegra_bo_free_object(struct drm_gem_object *gem) tegra_bo_iommu_unmap(tegra, bo); if (gem->import_attach) { - dma_buf_unmap_attachment(gem->import_attach, bo->sgt, - DMA_TO_DEVICE); + dma_buf_unmap_attachment_unlocked(gem->import_attach, bo->sgt, + DMA_TO_DEVICE); drm_prime_gem_destroy(gem, NULL); } else { tegra_bo_free(gem->dev, bo); -- cgit From 03a75fd6c6282b4e5aafa87e5ae52dd02868829a Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 17 Oct 2022 20:22:17 +0300 Subject: drm/etnaviv: Prepare to dynamic dma-buf locking specification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prepare Etnaviv driver to the common dynamic dma-buf locking convention by starting to use the unlocked versions of dma-buf API functions. Acked-by: Christian König Signed-off-by: Dmitry Osipenko Link: https://patchwork.freedesktop.org/patch/msgid/20221017172229.42269-10-dmitry.osipenko@collabora.com --- drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c index 3fa2da149639..7031db145a77 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c @@ -65,7 +65,7 @@ static void etnaviv_gem_prime_release(struct etnaviv_gem_object *etnaviv_obj) struct iosys_map map = IOSYS_MAP_INIT_VADDR(etnaviv_obj->vaddr); if (etnaviv_obj->vaddr) - dma_buf_vunmap(etnaviv_obj->base.import_attach->dmabuf, &map); + dma_buf_vunmap_unlocked(etnaviv_obj->base.import_attach->dmabuf, &map); /* Don't drop the pages for imported dmabuf, as they are not * ours, just free the array we allocated: -- cgit From 21c9c5c0784f1b5e9c9e61dece97f3f97956e5f6 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 17 Oct 2022 20:22:18 +0300 Subject: RDMA/umem: Prepare to dynamic dma-buf locking specification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prepare InfiniBand drivers to the common dynamic dma-buf locking convention by starting to use the unlocked versions of dma-buf API functions. Acked-by: Jason Gunthorpe Acked-by: Christian König Signed-off-by: Dmitry Osipenko Link: https://patchwork.freedesktop.org/patch/msgid/20221017172229.42269-11-dmitry.osipenko@collabora.com --- drivers/infiniband/core/umem_dmabuf.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/core/umem_dmabuf.c b/drivers/infiniband/core/umem_dmabuf.c index 04c04e6d24c3..43b26bc12288 100644 --- a/drivers/infiniband/core/umem_dmabuf.c +++ b/drivers/infiniband/core/umem_dmabuf.c @@ -26,7 +26,8 @@ int ib_umem_dmabuf_map_pages(struct ib_umem_dmabuf *umem_dmabuf) if (umem_dmabuf->sgt) goto wait_fence; - sgt = dma_buf_map_attachment(umem_dmabuf->attach, DMA_BIDIRECTIONAL); + sgt = dma_buf_map_attachment_unlocked(umem_dmabuf->attach, + DMA_BIDIRECTIONAL); if (IS_ERR(sgt)) return PTR_ERR(sgt); @@ -102,8 +103,8 @@ void ib_umem_dmabuf_unmap_pages(struct ib_umem_dmabuf *umem_dmabuf) umem_dmabuf->last_sg_trim = 0; } - dma_buf_unmap_attachment(umem_dmabuf->attach, umem_dmabuf->sgt, - DMA_BIDIRECTIONAL); + dma_buf_unmap_attachment_unlocked(umem_dmabuf->attach, umem_dmabuf->sgt, + DMA_BIDIRECTIONAL); umem_dmabuf->sgt = NULL; } -- cgit From 791da5c7fedbc1d662445ec030d8f86872f6184c Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 17 Oct 2022 20:22:19 +0300 Subject: misc: fastrpc: Prepare to dynamic dma-buf locking specification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prepare fastrpc to the common dynamic dma-buf locking convention by starting to use the unlocked versions of dma-buf API functions. Acked-by: Christian König Acked-by: Srinivas Kandagatla Signed-off-by: Dmitry Osipenko Link: https://patchwork.freedesktop.org/patch/msgid/20221017172229.42269-12-dmitry.osipenko@collabora.com --- drivers/misc/fastrpc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index 93ebd174d848..6fcfb2e9f7a7 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -310,8 +310,8 @@ static void fastrpc_free_map(struct kref *ref) return; } } - dma_buf_unmap_attachment(map->attach, map->table, - DMA_BIDIRECTIONAL); + dma_buf_unmap_attachment_unlocked(map->attach, map->table, + DMA_BIDIRECTIONAL); dma_buf_detach(map->buf, map->attach); dma_buf_put(map->buf); } @@ -726,7 +726,7 @@ static int fastrpc_map_create(struct fastrpc_user *fl, int fd, goto attach_err; } - map->table = dma_buf_map_attachment(map->attach, DMA_BIDIRECTIONAL); + map->table = dma_buf_map_attachment_unlocked(map->attach, DMA_BIDIRECTIONAL); if (IS_ERR(map->table)) { err = PTR_ERR(map->table); goto map_err; -- cgit From e841ad86e7bffc865f5e7a96c36006c49489c675 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 17 Oct 2022 20:22:20 +0300 Subject: xen/gntdev: Prepare to dynamic dma-buf locking specification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prepare gntdev driver to the common dynamic dma-buf locking convention by starting to use the unlocked versions of dma-buf API functions. Acked-by: Juergen Gross Acked-by: Christian König Signed-off-by: Dmitry Osipenko Link: https://patchwork.freedesktop.org/patch/msgid/20221017172229.42269-13-dmitry.osipenko@collabora.com --- drivers/xen/gntdev-dmabuf.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/xen/gntdev-dmabuf.c b/drivers/xen/gntdev-dmabuf.c index 940e5e9e8a54..4440e626b797 100644 --- a/drivers/xen/gntdev-dmabuf.c +++ b/drivers/xen/gntdev-dmabuf.c @@ -600,7 +600,7 @@ dmabuf_imp_to_refs(struct gntdev_dmabuf_priv *priv, struct device *dev, gntdev_dmabuf->u.imp.attach = attach; - sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); + sgt = dma_buf_map_attachment_unlocked(attach, DMA_BIDIRECTIONAL); if (IS_ERR(sgt)) { ret = ERR_CAST(sgt); goto fail_detach; @@ -658,7 +658,7 @@ dmabuf_imp_to_refs(struct gntdev_dmabuf_priv *priv, struct device *dev, fail_end_access: dmabuf_imp_end_foreign_access(gntdev_dmabuf->u.imp.refs, count); fail_unmap: - dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL); + dma_buf_unmap_attachment_unlocked(attach, sgt, DMA_BIDIRECTIONAL); fail_detach: dma_buf_detach(dma_buf, attach); fail_free_obj: @@ -708,8 +708,8 @@ static int dmabuf_imp_release(struct gntdev_dmabuf_priv *priv, u32 fd) attach = gntdev_dmabuf->u.imp.attach; if (gntdev_dmabuf->u.imp.sgt) - dma_buf_unmap_attachment(attach, gntdev_dmabuf->u.imp.sgt, - DMA_BIDIRECTIONAL); + dma_buf_unmap_attachment_unlocked(attach, gntdev_dmabuf->u.imp.sgt, + DMA_BIDIRECTIONAL); dma_buf = attach->dmabuf; dma_buf_detach(attach->dmabuf, attach); dma_buf_put(dma_buf); -- cgit From a26ee3b71896d4e0d52d866fd16cc42da7106e6f Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 17 Oct 2022 20:22:21 +0300 Subject: media: videobuf2: Prepare to dynamic dma-buf locking specification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prepare V4L2 memory allocators to the common dynamic dma-buf locking convention by starting to use the unlocked versions of dma-buf API functions. Acked-by: Tomasz Figa Acked-by: Christian König Signed-off-by: Dmitry Osipenko Link: https://patchwork.freedesktop.org/patch/msgid/20221017172229.42269-14-dmitry.osipenko@collabora.com --- drivers/media/common/videobuf2/videobuf2-dma-contig.c | 11 ++++++----- drivers/media/common/videobuf2/videobuf2-dma-sg.c | 8 ++++---- drivers/media/common/videobuf2/videobuf2-vmalloc.c | 6 +++--- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/media/common/videobuf2/videobuf2-dma-contig.c b/drivers/media/common/videobuf2/videobuf2-dma-contig.c index 678b359717c4..79f4d8301fbb 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-contig.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-contig.c @@ -101,7 +101,7 @@ static void *vb2_dc_vaddr(struct vb2_buffer *vb, void *buf_priv) if (buf->db_attach) { struct iosys_map map; - if (!dma_buf_vmap(buf->db_attach->dmabuf, &map)) + if (!dma_buf_vmap_unlocked(buf->db_attach->dmabuf, &map)) buf->vaddr = map.vaddr; return buf->vaddr; @@ -711,7 +711,7 @@ static int vb2_dc_map_dmabuf(void *mem_priv) } /* get the associated scatterlist for this buffer */ - sgt = dma_buf_map_attachment(buf->db_attach, buf->dma_dir); + sgt = dma_buf_map_attachment_unlocked(buf->db_attach, buf->dma_dir); if (IS_ERR(sgt)) { pr_err("Error getting dmabuf scatterlist\n"); return -EINVAL; @@ -722,7 +722,8 @@ static int vb2_dc_map_dmabuf(void *mem_priv) if (contig_size < buf->size) { pr_err("contiguous chunk is too small %lu/%lu\n", contig_size, buf->size); - dma_buf_unmap_attachment(buf->db_attach, sgt, buf->dma_dir); + dma_buf_unmap_attachment_unlocked(buf->db_attach, sgt, + buf->dma_dir); return -EFAULT; } @@ -750,10 +751,10 @@ static void vb2_dc_unmap_dmabuf(void *mem_priv) } if (buf->vaddr) { - dma_buf_vunmap(buf->db_attach->dmabuf, &map); + dma_buf_vunmap_unlocked(buf->db_attach->dmabuf, &map); buf->vaddr = NULL; } - dma_buf_unmap_attachment(buf->db_attach, sgt, buf->dma_dir); + dma_buf_unmap_attachment_unlocked(buf->db_attach, sgt, buf->dma_dir); buf->dma_addr = 0; buf->dma_sgt = NULL; diff --git a/drivers/media/common/videobuf2/videobuf2-dma-sg.c b/drivers/media/common/videobuf2/videobuf2-dma-sg.c index fa69158a65b1..36ecdea8d707 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-sg.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-sg.c @@ -309,7 +309,7 @@ static void *vb2_dma_sg_vaddr(struct vb2_buffer *vb, void *buf_priv) if (!buf->vaddr) { if (buf->db_attach) { - ret = dma_buf_vmap(buf->db_attach->dmabuf, &map); + ret = dma_buf_vmap_unlocked(buf->db_attach->dmabuf, &map); buf->vaddr = ret ? NULL : map.vaddr; } else { buf->vaddr = vm_map_ram(buf->pages, buf->num_pages, -1); @@ -565,7 +565,7 @@ static int vb2_dma_sg_map_dmabuf(void *mem_priv) } /* get the associated scatterlist for this buffer */ - sgt = dma_buf_map_attachment(buf->db_attach, buf->dma_dir); + sgt = dma_buf_map_attachment_unlocked(buf->db_attach, buf->dma_dir); if (IS_ERR(sgt)) { pr_err("Error getting dmabuf scatterlist\n"); return -EINVAL; @@ -594,10 +594,10 @@ static void vb2_dma_sg_unmap_dmabuf(void *mem_priv) } if (buf->vaddr) { - dma_buf_vunmap(buf->db_attach->dmabuf, &map); + dma_buf_vunmap_unlocked(buf->db_attach->dmabuf, &map); buf->vaddr = NULL; } - dma_buf_unmap_attachment(buf->db_attach, sgt, buf->dma_dir); + dma_buf_unmap_attachment_unlocked(buf->db_attach, sgt, buf->dma_dir); buf->dma_sgt = NULL; } diff --git a/drivers/media/common/videobuf2/videobuf2-vmalloc.c b/drivers/media/common/videobuf2/videobuf2-vmalloc.c index 948152f1596b..7831bf545874 100644 --- a/drivers/media/common/videobuf2/videobuf2-vmalloc.c +++ b/drivers/media/common/videobuf2/videobuf2-vmalloc.c @@ -376,7 +376,7 @@ static int vb2_vmalloc_map_dmabuf(void *mem_priv) struct iosys_map map; int ret; - ret = dma_buf_vmap(buf->dbuf, &map); + ret = dma_buf_vmap_unlocked(buf->dbuf, &map); if (ret) return -EFAULT; buf->vaddr = map.vaddr; @@ -389,7 +389,7 @@ static void vb2_vmalloc_unmap_dmabuf(void *mem_priv) struct vb2_vmalloc_buf *buf = mem_priv; struct iosys_map map = IOSYS_MAP_INIT_VADDR(buf->vaddr); - dma_buf_vunmap(buf->dbuf, &map); + dma_buf_vunmap_unlocked(buf->dbuf, &map); buf->vaddr = NULL; } @@ -399,7 +399,7 @@ static void vb2_vmalloc_detach_dmabuf(void *mem_priv) struct iosys_map map = IOSYS_MAP_INIT_VADDR(buf->vaddr); if (buf->vaddr) - dma_buf_vunmap(buf->dbuf, &map); + dma_buf_vunmap_unlocked(buf->dbuf, &map); kfree(buf); } -- cgit From 50f0ddcdee2db940d5c4ebc2fdc3c06d703e14fc Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 17 Oct 2022 20:22:22 +0300 Subject: media: tegra-vde: Prepare to dynamic dma-buf locking specification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prepare Tegra video decoder driver to the common dynamic dma-buf locking convention by starting to use the unlocked versions of dma-buf API functions. Acked-by: Christian König Signed-off-by: Dmitry Osipenko Link: https://patchwork.freedesktop.org/patch/msgid/20221017172229.42269-15-dmitry.osipenko@collabora.com --- drivers/media/platform/nvidia/tegra-vde/dmabuf-cache.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/nvidia/tegra-vde/dmabuf-cache.c b/drivers/media/platform/nvidia/tegra-vde/dmabuf-cache.c index 69c346148070..1c5b94989aec 100644 --- a/drivers/media/platform/nvidia/tegra-vde/dmabuf-cache.c +++ b/drivers/media/platform/nvidia/tegra-vde/dmabuf-cache.c @@ -38,7 +38,7 @@ static void tegra_vde_release_entry(struct tegra_vde_cache_entry *entry) if (entry->vde->domain) tegra_vde_iommu_unmap(entry->vde, entry->iova); - dma_buf_unmap_attachment(entry->a, entry->sgt, entry->dma_dir); + dma_buf_unmap_attachment_unlocked(entry->a, entry->sgt, entry->dma_dir); dma_buf_detach(dmabuf, entry->a); dma_buf_put(dmabuf); @@ -102,7 +102,7 @@ int tegra_vde_dmabuf_cache_map(struct tegra_vde *vde, goto err_unlock; } - sgt = dma_buf_map_attachment(attachment, dma_dir); + sgt = dma_buf_map_attachment_unlocked(attachment, dma_dir); if (IS_ERR(sgt)) { dev_err(dev, "Failed to get dmabufs sg_table\n"); err = PTR_ERR(sgt); @@ -152,7 +152,7 @@ ref: err_free: kfree(entry); err_unmap: - dma_buf_unmap_attachment(attachment, sgt, dma_dir); + dma_buf_unmap_attachment_unlocked(attachment, sgt, dma_dir); err_detach: dma_buf_detach(dmabuf, attachment); err_unlock: -- cgit From 34c7797f9ef498e722dfaebf2a35b75d70d8cf64 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 17 Oct 2022 20:22:23 +0300 Subject: dma-buf: Move dma_buf_vmap() to dynamic locking specification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move dma_buf_vmap/vunmap() functions to the dynamic locking specification by asserting that the reservation lock is held. Acked-by: Sumit Semwal Acked-by: Christian König Signed-off-by: Dmitry Osipenko Link: https://patchwork.freedesktop.org/patch/msgid/20221017172229.42269-16-dmitry.osipenko@collabora.com --- drivers/dma-buf/dma-buf.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 3e4060dadb74..2c4381bb9478 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -1450,6 +1450,8 @@ int dma_buf_vmap(struct dma_buf *dmabuf, struct iosys_map *map) if (WARN_ON(!dmabuf)) return -EINVAL; + dma_resv_assert_held(dmabuf->resv); + if (!dmabuf->ops->vmap) return -EINVAL; @@ -1515,6 +1517,8 @@ void dma_buf_vunmap(struct dma_buf *dmabuf, struct iosys_map *map) if (WARN_ON(!dmabuf)) return; + dma_resv_assert_held(dmabuf->resv); + BUG_ON(iosys_map_is_null(&dmabuf->vmap_ptr)); BUG_ON(dmabuf->vmapping_counter == 0); BUG_ON(!iosys_map_is_equal(&dmabuf->vmap_ptr, map)); -- cgit From 809d9c72c2f83ef7225379908e125eb4b662232c Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 17 Oct 2022 20:22:24 +0300 Subject: dma-buf: Move dma_buf_attach() to dynamic locking specification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move dma-buf attachment API functions to the dynamic locking specification by taking the reservation lock around the mapping operations. The strict locking convention prevents deadlock situations for dma-buf importers and exporters. Acked-by: Sumit Semwal Reviewed-by: Christian König Signed-off-by: Dmitry Osipenko Link: https://patchwork.freedesktop.org/patch/msgid/20221017172229.42269-17-dmitry.osipenko@collabora.com --- drivers/dma-buf/dma-buf.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 2c4381bb9478..d685a5adb122 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -859,8 +859,8 @@ dma_buf_dynamic_attach(struct dma_buf *dmabuf, struct device *dev, dma_buf_is_dynamic(dmabuf)) { struct sg_table *sgt; + dma_resv_lock(attach->dmabuf->resv, NULL); if (dma_buf_is_dynamic(attach->dmabuf)) { - dma_resv_lock(attach->dmabuf->resv, NULL); ret = dmabuf->ops->pin(attach); if (ret) goto err_unlock; @@ -873,8 +873,7 @@ dma_buf_dynamic_attach(struct dma_buf *dmabuf, struct device *dev, ret = PTR_ERR(sgt); goto err_unpin; } - if (dma_buf_is_dynamic(attach->dmabuf)) - dma_resv_unlock(attach->dmabuf->resv); + dma_resv_unlock(attach->dmabuf->resv); attach->sgt = sgt; attach->dir = DMA_BIDIRECTIONAL; } @@ -890,8 +889,7 @@ err_unpin: dmabuf->ops->unpin(attach); err_unlock: - if (dma_buf_is_dynamic(attach->dmabuf)) - dma_resv_unlock(attach->dmabuf->resv); + dma_resv_unlock(attach->dmabuf->resv); dma_buf_detach(dmabuf, attach); return ERR_PTR(ret); @@ -937,21 +935,19 @@ void dma_buf_detach(struct dma_buf *dmabuf, struct dma_buf_attachment *attach) if (WARN_ON(!dmabuf || !attach)) return; + dma_resv_lock(attach->dmabuf->resv, NULL); + if (attach->sgt) { - if (dma_buf_is_dynamic(attach->dmabuf)) - dma_resv_lock(attach->dmabuf->resv, NULL); __unmap_dma_buf(attach, attach->sgt, attach->dir); - if (dma_buf_is_dynamic(attach->dmabuf)) { + if (dma_buf_is_dynamic(attach->dmabuf)) dmabuf->ops->unpin(attach); - dma_resv_unlock(attach->dmabuf->resv); - } } - - dma_resv_lock(dmabuf->resv, NULL); list_del(&attach->node); + dma_resv_unlock(dmabuf->resv); + if (dmabuf->ops->detach) dmabuf->ops->detach(dmabuf, attach); -- cgit From 47e982d5195d76c621d21d2f1911159175d0839e Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 17 Oct 2022 20:22:25 +0300 Subject: dma-buf: Move dma_buf_map_attachment() to dynamic locking specification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move dma-buf attachment mapping functions to the dynamic locking specification by asserting that the reservation lock is held. Acked-by: Sumit Semwal Reviewed-by: Christian König Signed-off-by: Dmitry Osipenko Link: https://patchwork.freedesktop.org/patch/msgid/20221017172229.42269-18-dmitry.osipenko@collabora.com --- drivers/dma-buf/dma-buf.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index d685a5adb122..f54c649f922a 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -1038,8 +1038,7 @@ struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach, if (WARN_ON(!attach || !attach->dmabuf)) return ERR_PTR(-EINVAL); - if (dma_buf_attachment_is_dynamic(attach)) - dma_resv_assert_held(attach->dmabuf->resv); + dma_resv_assert_held(attach->dmabuf->resv); if (attach->sgt) { /* @@ -1054,7 +1053,6 @@ struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach, } if (dma_buf_is_dynamic(attach->dmabuf)) { - dma_resv_assert_held(attach->dmabuf->resv); if (!IS_ENABLED(CONFIG_DMABUF_MOVE_NOTIFY)) { r = attach->dmabuf->ops->pin(attach); if (r) @@ -1143,15 +1141,11 @@ void dma_buf_unmap_attachment(struct dma_buf_attachment *attach, if (WARN_ON(!attach || !attach->dmabuf || !sg_table)) return; - if (dma_buf_attachment_is_dynamic(attach)) - dma_resv_assert_held(attach->dmabuf->resv); + dma_resv_assert_held(attach->dmabuf->resv); if (attach->sgt == sg_table) return; - if (dma_buf_is_dynamic(attach->dmabuf)) - dma_resv_assert_held(attach->dmabuf->resv); - __unmap_dma_buf(attach, sg_table, direction); if (dma_buf_is_dynamic(attach->dmabuf) && -- cgit From d078fd9b8daa282a0c713daa433315940bbf8188 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 17 Oct 2022 20:22:26 +0300 Subject: dma-buf: Move dma_buf_mmap() to dynamic locking specification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move dma_buf_mmap() function to the dynamic locking specification by taking the reservation lock. Neither of the today's drivers take the reservation lock within the mmap() callback, hence it's safe to enforce the locking. Acked-by: Sumit Semwal Acked-by: Christian König Signed-off-by: Dmitry Osipenko Link: https://patchwork.freedesktop.org/patch/msgid/20221017172229.42269-19-dmitry.osipenko@collabora.com --- drivers/dma-buf/dma-buf.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index f54c649f922a..f149b384f4dd 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -1390,6 +1390,8 @@ EXPORT_SYMBOL_NS_GPL(dma_buf_end_cpu_access, DMA_BUF); int dma_buf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma, unsigned long pgoff) { + int ret; + if (WARN_ON(!dmabuf || !vma)) return -EINVAL; @@ -1410,7 +1412,11 @@ int dma_buf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma, vma_set_file(vma, dmabuf->file); vma->vm_pgoff = pgoff; - return dmabuf->ops->mmap(dmabuf, vma); + dma_resv_lock(dmabuf->resv, NULL); + ret = dmabuf->ops->mmap(dmabuf, vma); + dma_resv_unlock(dmabuf->resv); + + return ret; } EXPORT_SYMBOL_NS_GPL(dma_buf_mmap, DMA_BUF); -- cgit From ae2e7f28a170c01fdea420f1284e2f163198c9aa Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 17 Oct 2022 20:22:27 +0300 Subject: dma-buf: Document dynamic locking convention MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add documentation for the dynamic locking convention. The documentation tells dma-buf API users when they should take the reservation lock and when not. Acked-by: Sumit Semwal Reviewed-by: Christian König Signed-off-by: Dmitry Osipenko Link: https://patchwork.freedesktop.org/patch/msgid/20221017172229.42269-20-dmitry.osipenko@collabora.com --- Documentation/driver-api/dma-buf.rst | 6 ++++ drivers/dma-buf/dma-buf.c | 64 ++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/Documentation/driver-api/dma-buf.rst b/Documentation/driver-api/dma-buf.rst index 36a76cbe9095..622b8156d212 100644 --- a/Documentation/driver-api/dma-buf.rst +++ b/Documentation/driver-api/dma-buf.rst @@ -119,6 +119,12 @@ DMA Buffer ioctls .. kernel-doc:: include/uapi/linux/dma-buf.h +DMA-BUF locking convention +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. kernel-doc:: drivers/dma-buf/dma-buf.c + :doc: locking convention + Kernel Functions and Structures Reference ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index f149b384f4dd..f1d968e5bac4 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -795,6 +795,70 @@ static struct sg_table * __map_dma_buf(struct dma_buf_attachment *attach, return sg_table; } +/** + * DOC: locking convention + * + * In order to avoid deadlock situations between dma-buf exports and importers, + * all dma-buf API users must follow the common dma-buf locking convention. + * + * Convention for importers + * + * 1. Importers must hold the dma-buf reservation lock when calling these + * functions: + * + * - dma_buf_pin() + * - dma_buf_unpin() + * - dma_buf_map_attachment() + * - dma_buf_unmap_attachment() + * - dma_buf_vmap() + * - dma_buf_vunmap() + * + * 2. Importers must not hold the dma-buf reservation lock when calling these + * functions: + * + * - dma_buf_attach() + * - dma_buf_dynamic_attach() + * - dma_buf_detach() + * - dma_buf_export( + * - dma_buf_fd() + * - dma_buf_get() + * - dma_buf_put() + * - dma_buf_mmap() + * - dma_buf_begin_cpu_access() + * - dma_buf_end_cpu_access() + * - dma_buf_map_attachment_unlocked() + * - dma_buf_unmap_attachment_unlocked() + * - dma_buf_vmap_unlocked() + * - dma_buf_vunmap_unlocked() + * + * Convention for exporters + * + * 1. These &dma_buf_ops callbacks are invoked with unlocked dma-buf + * reservation and exporter can take the lock: + * + * - &dma_buf_ops.attach() + * - &dma_buf_ops.detach() + * - &dma_buf_ops.release() + * - &dma_buf_ops.begin_cpu_access() + * - &dma_buf_ops.end_cpu_access() + * + * 2. These &dma_buf_ops callbacks are invoked with locked dma-buf + * reservation and exporter can't take the lock: + * + * - &dma_buf_ops.pin() + * - &dma_buf_ops.unpin() + * - &dma_buf_ops.map_dma_buf() + * - &dma_buf_ops.unmap_dma_buf() + * - &dma_buf_ops.mmap() + * - &dma_buf_ops.vmap() + * - &dma_buf_ops.vunmap() + * + * 3. Exporters must hold the dma-buf reservation lock when calling these + * functions: + * + * - dma_buf_move_notify() + */ + /** * dma_buf_dynamic_attach - Add the device to dma_buf's attachments list * @dmabuf: [in] buffer to attach device to. -- cgit From 23543b3c4f7fe4ee03d624d0584ec8429d4e7a15 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 17 Oct 2022 20:22:28 +0300 Subject: media: videobuf2: Stop using internal dma-buf lock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All drivers that use dma-bufs have been moved to the updated locking specification and now dma-buf reservation is guaranteed to be locked by importers during the mapping operations. There is no need to take the internal dma-buf lock anymore. Remove locking from the videobuf2 memory allocators. Acked-by: Tomasz Figa Acked-by: Hans Verkuil Acked-by: Christian König Signed-off-by: Dmitry Osipenko Link: https://patchwork.freedesktop.org/patch/msgid/20221017172229.42269-21-dmitry.osipenko@collabora.com --- drivers/media/common/videobuf2/videobuf2-dma-contig.c | 11 +---------- drivers/media/common/videobuf2/videobuf2-dma-sg.c | 11 +---------- drivers/media/common/videobuf2/videobuf2-vmalloc.c | 11 +---------- 3 files changed, 3 insertions(+), 30 deletions(-) diff --git a/drivers/media/common/videobuf2/videobuf2-dma-contig.c b/drivers/media/common/videobuf2/videobuf2-dma-contig.c index 79f4d8301fbb..555bd40fa472 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-contig.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-contig.c @@ -382,18 +382,12 @@ static struct sg_table *vb2_dc_dmabuf_ops_map( struct dma_buf_attachment *db_attach, enum dma_data_direction dma_dir) { struct vb2_dc_attachment *attach = db_attach->priv; - /* stealing dmabuf mutex to serialize map/unmap operations */ - struct mutex *lock = &db_attach->dmabuf->lock; struct sg_table *sgt; - mutex_lock(lock); - sgt = &attach->sgt; /* return previously mapped sg table */ - if (attach->dma_dir == dma_dir) { - mutex_unlock(lock); + if (attach->dma_dir == dma_dir) return sgt; - } /* release any previous cache */ if (attach->dma_dir != DMA_NONE) { @@ -409,14 +403,11 @@ static struct sg_table *vb2_dc_dmabuf_ops_map( if (dma_map_sgtable(db_attach->dev, sgt, dma_dir, DMA_ATTR_SKIP_CPU_SYNC)) { pr_err("failed to map scatterlist\n"); - mutex_unlock(lock); return ERR_PTR(-EIO); } attach->dma_dir = dma_dir; - mutex_unlock(lock); - return sgt; } diff --git a/drivers/media/common/videobuf2/videobuf2-dma-sg.c b/drivers/media/common/videobuf2/videobuf2-dma-sg.c index 36ecdea8d707..36981a5b5c53 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-sg.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-sg.c @@ -424,18 +424,12 @@ static struct sg_table *vb2_dma_sg_dmabuf_ops_map( struct dma_buf_attachment *db_attach, enum dma_data_direction dma_dir) { struct vb2_dma_sg_attachment *attach = db_attach->priv; - /* stealing dmabuf mutex to serialize map/unmap operations */ - struct mutex *lock = &db_attach->dmabuf->lock; struct sg_table *sgt; - mutex_lock(lock); - sgt = &attach->sgt; /* return previously mapped sg table */ - if (attach->dma_dir == dma_dir) { - mutex_unlock(lock); + if (attach->dma_dir == dma_dir) return sgt; - } /* release any previous cache */ if (attach->dma_dir != DMA_NONE) { @@ -446,14 +440,11 @@ static struct sg_table *vb2_dma_sg_dmabuf_ops_map( /* mapping to the client with new direction */ if (dma_map_sgtable(db_attach->dev, sgt, dma_dir, 0)) { pr_err("failed to map scatterlist\n"); - mutex_unlock(lock); return ERR_PTR(-EIO); } attach->dma_dir = dma_dir; - mutex_unlock(lock); - return sgt; } diff --git a/drivers/media/common/videobuf2/videobuf2-vmalloc.c b/drivers/media/common/videobuf2/videobuf2-vmalloc.c index 7831bf545874..41db707e43a4 100644 --- a/drivers/media/common/videobuf2/videobuf2-vmalloc.c +++ b/drivers/media/common/videobuf2/videobuf2-vmalloc.c @@ -267,18 +267,12 @@ static struct sg_table *vb2_vmalloc_dmabuf_ops_map( struct dma_buf_attachment *db_attach, enum dma_data_direction dma_dir) { struct vb2_vmalloc_attachment *attach = db_attach->priv; - /* stealing dmabuf mutex to serialize map/unmap operations */ - struct mutex *lock = &db_attach->dmabuf->lock; struct sg_table *sgt; - mutex_lock(lock); - sgt = &attach->sgt; /* return previously mapped sg table */ - if (attach->dma_dir == dma_dir) { - mutex_unlock(lock); + if (attach->dma_dir == dma_dir) return sgt; - } /* release any previous cache */ if (attach->dma_dir != DMA_NONE) { @@ -289,14 +283,11 @@ static struct sg_table *vb2_vmalloc_dmabuf_ops_map( /* mapping to the client with new direction */ if (dma_map_sgtable(db_attach->dev, sgt, dma_dir, 0)) { pr_err("failed to map scatterlist\n"); - mutex_unlock(lock); return ERR_PTR(-EIO); } attach->dma_dir = dma_dir; - mutex_unlock(lock); - return sgt; } -- cgit From 28743e25fa1c867675bd8ff976eb92d4251f13a1 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 17 Oct 2022 20:22:29 +0300 Subject: dma-buf: Remove obsoleted internal lock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The internal dma-buf lock isn't needed anymore because the updated locking specification claims that dma-buf reservation must be locked by importers, and thus, the internal data is already protected by the reservation lock. Remove the obsoleted internal lock. Acked-by: Sumit Semwal Acked-by: Christian König Reviewed-by: Christian König Signed-off-by: Dmitry Osipenko Link: https://patchwork.freedesktop.org/patch/msgid/20221017172229.42269-22-dmitry.osipenko@collabora.com --- drivers/dma-buf/dma-buf.c | 14 ++++---------- include/linux/dma-buf.h | 9 --------- 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index f1d968e5bac4..7663c4e784b6 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -657,7 +657,6 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info) dmabuf->file = file; - mutex_init(&dmabuf->lock); INIT_LIST_HEAD(&dmabuf->attachments); mutex_lock(&db_list.lock); @@ -1503,7 +1502,7 @@ EXPORT_SYMBOL_NS_GPL(dma_buf_mmap, DMA_BUF); int dma_buf_vmap(struct dma_buf *dmabuf, struct iosys_map *map) { struct iosys_map ptr; - int ret = 0; + int ret; iosys_map_clear(map); @@ -1515,28 +1514,25 @@ int dma_buf_vmap(struct dma_buf *dmabuf, struct iosys_map *map) if (!dmabuf->ops->vmap) return -EINVAL; - mutex_lock(&dmabuf->lock); if (dmabuf->vmapping_counter) { dmabuf->vmapping_counter++; BUG_ON(iosys_map_is_null(&dmabuf->vmap_ptr)); *map = dmabuf->vmap_ptr; - goto out_unlock; + return 0; } BUG_ON(iosys_map_is_set(&dmabuf->vmap_ptr)); ret = dmabuf->ops->vmap(dmabuf, &ptr); if (WARN_ON_ONCE(ret)) - goto out_unlock; + return ret; dmabuf->vmap_ptr = ptr; dmabuf->vmapping_counter = 1; *map = dmabuf->vmap_ptr; -out_unlock: - mutex_unlock(&dmabuf->lock); - return ret; + return 0; } EXPORT_SYMBOL_NS_GPL(dma_buf_vmap, DMA_BUF); @@ -1583,13 +1579,11 @@ void dma_buf_vunmap(struct dma_buf *dmabuf, struct iosys_map *map) BUG_ON(dmabuf->vmapping_counter == 0); BUG_ON(!iosys_map_is_equal(&dmabuf->vmap_ptr, map)); - mutex_lock(&dmabuf->lock); if (--dmabuf->vmapping_counter == 0) { if (dmabuf->ops->vunmap) dmabuf->ops->vunmap(dmabuf, map); iosys_map_clear(&dmabuf->vmap_ptr); } - mutex_unlock(&dmabuf->lock); } EXPORT_SYMBOL_NS_GPL(dma_buf_vunmap, DMA_BUF); diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h index f11b5bbc2f37..6fa8d4e29719 100644 --- a/include/linux/dma-buf.h +++ b/include/linux/dma-buf.h @@ -326,15 +326,6 @@ struct dma_buf { /** @ops: dma_buf_ops associated with this buffer object. */ const struct dma_buf_ops *ops; - /** - * @lock: - * - * Used internally to serialize list manipulation, attach/detach and - * vmap/unmap. Note that in many cases this is superseeded by - * dma_resv_lock() on @resv. - */ - struct mutex lock; - /** * @vmapping_counter: * -- cgit From ef7e222cd68f7b7c654f23fce51e8be888a3d7ee Mon Sep 17 00:00:00 2001 From: Radhakrishna Sripada Date: Tue, 11 Oct 2022 08:38:50 -0700 Subject: drm/i915: Add intel_ prefix to struct ip_version Rename struct ip_version to intel_ip_version to comply with the naming conventions for structures. Suggested-by: Jani Nikula Signed-off-by: Radhakrishna Sripada Reviewed-by: Lucas De Marchi Signed-off-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20221011153851.3781507-1-radhakrishna.sripada@intel.com --- drivers/gpu/drm/i915/intel_device_info.c | 2 +- drivers/gpu/drm/i915/intel_device_info.h | 8 ++++---- drivers/gpu/drm/i915/intel_step.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_device_info.c b/drivers/gpu/drm/i915/intel_device_info.c index 090097bb3c0a..37267c662dc6 100644 --- a/drivers/gpu/drm/i915/intel_device_info.c +++ b/drivers/gpu/drm/i915/intel_device_info.c @@ -289,7 +289,7 @@ static void intel_device_info_subplatform_init(struct drm_i915_private *i915) RUNTIME_INFO(i915)->platform_mask[pi] |= mask; } -static void ip_ver_read(struct drm_i915_private *i915, u32 offset, struct ip_version *ip) +static void ip_ver_read(struct drm_i915_private *i915, u32 offset, struct intel_ip_version *ip) { struct pci_dev *pdev = to_pci_dev(i915->drm.dev); void __iomem *addr; diff --git a/drivers/gpu/drm/i915/intel_device_info.h b/drivers/gpu/drm/i915/intel_device_info.h index 8e494c59f9a1..4da73f4e4751 100644 --- a/drivers/gpu/drm/i915/intel_device_info.h +++ b/drivers/gpu/drm/i915/intel_device_info.h @@ -194,7 +194,7 @@ enum intel_ppgtt_type { func(overlay_needs_physical); \ func(supports_tv); -struct ip_version { +struct intel_ip_version { u8 ver; u8 rel; u8 step; @@ -206,13 +206,13 @@ struct intel_runtime_info { * render, compute and copy behavior. */ struct { - struct ip_version ip; + struct intel_ip_version ip; } graphics; struct { - struct ip_version ip; + struct intel_ip_version ip; } media; struct { - struct ip_version ip; + struct intel_ip_version ip; } display; /* diff --git a/drivers/gpu/drm/i915/intel_step.c b/drivers/gpu/drm/i915/intel_step.c index 91e7c51991b0..75d7a86c60c0 100644 --- a/drivers/gpu/drm/i915/intel_step.c +++ b/drivers/gpu/drm/i915/intel_step.c @@ -136,7 +136,7 @@ static const struct intel_step_info adlp_n_revids[] = { }; static u8 gmd_to_intel_step(struct drm_i915_private *i915, - struct ip_version *gmd) + struct intel_ip_version *gmd) { u8 step = gmd->step + STEP_A0; -- cgit From 80c1fb2ee7b88e1e03bbbd5b3e19cbae28b95dcf Mon Sep 17 00:00:00 2001 From: Radhakrishna Sripada Date: Tue, 11 Oct 2022 08:38:51 -0700 Subject: drm/i915: Use graphics ver, rel info for media on old platforms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Platforms prior to MTL do not have a separate media and graphics version. On platforms where GMD id is not supported, reuse the graphics ip version, release info for media. The rest of the IP graphics, display versions would be copied during driver creation. While at it warn if GMD is not used for platforms greater than gen12. v2: - Use simple assignment to copy contents of the structure(JaniN) Fixes: c2c7075225ef ("drm/i915: Read graphics/media/display arch version from hw") Cc: Jani Nikula Cc: Lucas De Marchi Cc: Matt Roper Cc: Ville Syrjälä Signed-off-by: Radhakrishna Sripada Reviewed-by: Lucas De Marchi Signed-off-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20221011153851.3781507-2-radhakrishna.sripada@intel.com --- drivers/gpu/drm/i915/intel_device_info.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_device_info.c b/drivers/gpu/drm/i915/intel_device_info.c index 37267c662dc6..1dc1fb29a776 100644 --- a/drivers/gpu/drm/i915/intel_device_info.c +++ b/drivers/gpu/drm/i915/intel_device_info.c @@ -329,8 +329,16 @@ static void intel_ipver_early_init(struct drm_i915_private *i915) { struct intel_runtime_info *runtime = RUNTIME_INFO(i915); - if (!HAS_GMD_ID(i915)) + if (!HAS_GMD_ID(i915)) { + drm_WARN_ON(&i915->drm, RUNTIME_INFO(i915)->graphics.ip.ver > 12); + /* + * On older platforms, graphics and media share the same ip + * version and release. + */ + RUNTIME_INFO(i915)->media.ip = + RUNTIME_INFO(i915)->graphics.ip; return; + } ip_ver_read(i915, i915_mmio_reg_offset(GMD_ID_GRAPHICS), &runtime->graphics.ip); -- cgit From f74354670fc6dfc2ac3fcf2ec2c4e5ae9155433c Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Mon, 17 Oct 2022 10:55:25 +0200 Subject: drm/i915: fix clear mask in GEN7_MISCCPCTL update GEN7_DOP_CLOCK_GATE_ENABLE bit should be cleared, not inverse. The bug was introduced during conversion to intel_uncore_rmw helper. Suggested-by: Matt Roper Fixes: 8cee664d3eb6f8 ("drm/i915: use proper helper for register updates") Signed-off-by: Andrzej Hajda Reviewed-by: Lucas De Marchi Signed-off-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20221017085525.3898649-1-andrzej.hajda@intel.com --- drivers/gpu/drm/i915/i915_irq.c | 4 ++-- drivers/gpu/drm/i915/intel_pm.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 2048ee10af33..b141001a090a 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1052,8 +1052,8 @@ static void ivb_parity_work(struct work_struct *work) if (drm_WARN_ON(&dev_priv->drm, !dev_priv->l3_parity.which_slice)) goto out; - misccpctl = intel_uncore_rmw(&dev_priv->uncore, GEN7_MISCCPCTL, ~GEN7_DOP_CLOCK_GATE_ENABLE, - 0); + misccpctl = intel_uncore_rmw(&dev_priv->uncore, GEN7_MISCCPCTL, + GEN7_DOP_CLOCK_GATE_ENABLE, 0); intel_uncore_posting_read(&dev_priv->uncore, GEN7_MISCCPCTL); while ((slice = ffs(dev_priv->l3_parity.which_slice)) != 0) { diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index efe334dad372..a204a32bce44 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4321,8 +4321,8 @@ static void gen8_set_l3sqc_credits(struct drm_i915_private *dev_priv, u32 val; /* WaTempDisableDOPClkGating:bdw */ - misccpctl = intel_uncore_rmw(&dev_priv->uncore, GEN7_MISCCPCTL, ~GEN7_DOP_CLOCK_GATE_ENABLE, - 0); + misccpctl = intel_uncore_rmw(&dev_priv->uncore, GEN7_MISCCPCTL, + GEN7_DOP_CLOCK_GATE_ENABLE, 0); val = intel_uncore_read(&dev_priv->uncore, GEN8_L3SQCREG1); val &= ~L3_PRIO_CREDITS_MASK; -- cgit From 66eb93e71a7a6695b7c5eb682e3ca1c980cf9d58 Mon Sep 17 00:00:00 2001 From: Anshuman Gupta Date: Fri, 14 Oct 2022 17:02:58 +0530 Subject: drm/i915/dgfx: Keep PCI autosuspend control 'on' by default on all dGPU DGFX platforms has lmem and cpu can access the lmem objects via mmap and i915 internal i915_gem_object_pin_map() for i915 own usages. Both of these methods has pre-requisite requirement to keep GFX PCI endpoint in D0 for a supported iomem transaction over PCI link. (Refer PCIe specs 5.3.1.4.1) Both DG1/DG2 have a known hardware bug that violates the PCIe specs and support the iomem read write transaction over PCIe bus despite endpoint is D3 state. Due to above H/W bug, we had never observed any issue with i915 runtime PM versus lmem access. But this issue becomes visible when PCIe gfx endpoint's upstream bridge enters to D3, at this point any lmem read/write access will be returned as unsupported request. But again this issue is not observed on every platform because it has been observed on few host machines DG1/DG2 endpoint's upstream bridge does not bind with pcieport driver. which really disables the PCIe power savings and leaves the bridge at D0 state. We need a unique interface to read/write from lmem with runtime PM wakeref protection something similar to intel_uncore_{read, write}, keep autosuspend control to 'on' on all discrete platforms, until we have a unique interface to read/write from lmem. This just change the default autosuspend setting of i915 on dGPU, user can still change it to 'auto'. v2: - Modified the commit message and subject with more information. - Changed the Fixes tag to LMEM support commit. [Joonas] - Changed !HAS_LMEM() Cond to !IS_DGFX(). [Rodrigo] Fixes: b908be543e44 ("drm/i915: support creating LMEM objects") Suggested-by: Rodrigo Vivi Reviewed-by: Rodrigo Vivi Signed-off-by: Anshuman Gupta Link: https://patchwork.freedesktop.org/patch/msgid/20221014113258.1284226-1-anshuman.gupta@intel.com --- drivers/gpu/drm/i915/intel_runtime_pm.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 6ed5786bcd29..744cca507946 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -591,8 +591,15 @@ void intel_runtime_pm_enable(struct intel_runtime_pm *rpm) pm_runtime_use_autosuspend(kdev); } - /* Enable by default */ - pm_runtime_allow(kdev); + /* + * FIXME: Temp hammer to keep autosupend disable on lmem supported platforms. + * As per PCIe specs 5.3.1.4.1, all iomem read write request over a PCIe + * function will be unsupported in case PCIe endpoint function is in D3. + * Let's keep i915 autosuspend control 'on' till we fix all known issue + * with lmem access in D3. + */ + if (!IS_DGFX(i915)) + pm_runtime_allow(kdev); /* * The core calls the driver load handler with an RPM reference held. -- cgit From b389286d0234e1edbaf62ed8bc0892a568c33662 Mon Sep 17 00:00:00 2001 From: Jocelyn Falempe Date: Thu, 13 Oct 2022 15:28:10 +0200 Subject: drm/mgag200: Fix PLL setup for G200_SE_A rev >=4 For G200_SE_A, PLL M setting is wrong, which leads to blank screen, or "signal out of range" on VGA display. previous code had "m |= 0x80" which was changed to m |= ((pixpllcn & BIT(8)) >> 1); Tested on G200_SE_A rev 42 This line of code was moved to another file with commit 877507bb954e ("drm/mgag200: Provide per-device callbacks for PIXPLLC") but can be easily backported before this commit. v2: * put BIT(7) First to respect MSB-to-LSB (Thomas) * Add a comment to explain that this bit must be set (Thomas) Fixes: 2dd040946ecf ("drm/mgag200: Store values (not bits) in struct mgag200_pll_values") Cc: stable@vger.kernel.org Signed-off-by: Jocelyn Falempe Reviewed-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20221013132810.521945-1-jfalempe@redhat.com --- drivers/gpu/drm/mgag200/mgag200_g200se.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/mgag200/mgag200_g200se.c b/drivers/gpu/drm/mgag200/mgag200_g200se.c index be389ed91cbd..bd6e573c9a1a 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200se.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200se.c @@ -284,7 +284,8 @@ static void mgag200_g200se_04_pixpllc_atomic_update(struct drm_crtc *crtc, pixpllcp = pixpllc->p - 1; pixpllcs = pixpllc->s; - xpixpllcm = pixpllcm | ((pixpllcn & BIT(8)) >> 1); + // For G200SE A, BIT(7) should be set unconditionally. + xpixpllcm = BIT(7) | pixpllcm; xpixpllcn = pixpllcn; xpixpllcp = (pixpllcs << 3) | pixpllcp; -- cgit From 7e2c58320ed59c9326e82cf9c00090f6a912fb64 Mon Sep 17 00:00:00 2001 From: Yifan Zha Date: Wed, 7 Sep 2022 14:13:02 +0800 Subject: drm/amdgpu: Program GC registers through RLCG interface in gfx_v11/gmc_v11 [Why] L1 blocks most of GC registers accessing by MMIO. [How] Use RLCG interface to program GC registers under SRIOV VF in full access time. Signed-off-by: Yifan Zha Reviewed-by: Hawking Zhang Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v11.c | 2 +- drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 2 +- drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c | 18 +++++++++++------- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v11.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v11.c index 0b0a72ca5695..7e80caa05060 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v11.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v11.c @@ -111,7 +111,7 @@ static int init_interrupts_v11(struct amdgpu_device *adev, uint32_t pipe_id) lock_srbm(adev, mec, pipe, 0, 0); - WREG32(SOC15_REG_OFFSET(GC, 0, regCPC_INT_CNTL), + WREG32_SOC15(GC, 0, regCPC_INT_CNTL, CP_INT_CNTL_RING0__TIME_STAMP_INT_ENABLE_MASK | CP_INT_CNTL_RING0__OPCODE_ERROR_INT_ENABLE_MASK); diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c index 73106f53246d..e3842dc100d6 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c @@ -1571,7 +1571,7 @@ static void gfx_v11_0_init_compute_vmid(struct amdgpu_device *adev) WREG32_SOC15(GC, 0, regSH_MEM_BASES, sh_mem_bases); /* Enable trap for each kfd vmid. */ - data = RREG32(SOC15_REG_OFFSET(GC, 0, regSPI_GDBG_PER_VMID_CNTL)); + data = RREG32_SOC15(GC, 0, regSPI_GDBG_PER_VMID_CNTL); data = REG_SET_FIELD(data, SPI_GDBG_PER_VMID_CNTL, TRAP_EN, 1); } soc21_grbm_select(adev, 0, 0, 0, 0); diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c index 846ccb6cf07d..66dfb574cc7d 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c @@ -186,6 +186,10 @@ static void gmc_v11_0_flush_vm_hub(struct amdgpu_device *adev, uint32_t vmid, /* Use register 17 for GART */ const unsigned eng = 17; unsigned int i; + unsigned char hub_ip = 0; + + hub_ip = (vmhub == AMDGPU_GFXHUB_0) ? + GC_HWIP : MMHUB_HWIP; spin_lock(&adev->gmc.invalidate_lock); /* @@ -199,8 +203,8 @@ static void gmc_v11_0_flush_vm_hub(struct amdgpu_device *adev, uint32_t vmid, if (use_semaphore) { for (i = 0; i < adev->usec_timeout; i++) { /* a read return value of 1 means semaphore acuqire */ - tmp = RREG32_NO_KIQ(hub->vm_inv_eng0_sem + - hub->eng_distance * eng); + tmp = RREG32_RLC_NO_KIQ(hub->vm_inv_eng0_sem + + hub->eng_distance * eng, hub_ip); if (tmp & 0x1) break; udelay(1); @@ -210,12 +214,12 @@ static void gmc_v11_0_flush_vm_hub(struct amdgpu_device *adev, uint32_t vmid, DRM_ERROR("Timeout waiting for sem acquire in VM flush!\n"); } - WREG32_NO_KIQ(hub->vm_inv_eng0_req + hub->eng_distance * eng, inv_req); + WREG32_RLC_NO_KIQ(hub->vm_inv_eng0_req + hub->eng_distance * eng, inv_req, hub_ip); /* Wait for ACK with a delay.*/ for (i = 0; i < adev->usec_timeout; i++) { - tmp = RREG32_NO_KIQ(hub->vm_inv_eng0_ack + - hub->eng_distance * eng); + tmp = RREG32_RLC_NO_KIQ(hub->vm_inv_eng0_ack + + hub->eng_distance * eng, hub_ip); tmp &= 1 << vmid; if (tmp) break; @@ -229,8 +233,8 @@ static void gmc_v11_0_flush_vm_hub(struct amdgpu_device *adev, uint32_t vmid, * add semaphore release after invalidation, * write with 0 means semaphore release */ - WREG32_NO_KIQ(hub->vm_inv_eng0_sem + - hub->eng_distance * eng, 0); + WREG32_RLC_NO_KIQ(hub->vm_inv_eng0_sem + + hub->eng_distance * eng, 0, hub_ip); /* Issue additional private vm invalidation to MMHUB */ if ((vmhub != AMDGPU_GFXHUB_0) && -- cgit From c520ba3fad335c76f4fad2ab49485eb9edf3de54 Mon Sep 17 00:00:00 2001 From: Kenneth Feng Date: Fri, 14 Oct 2022 15:19:51 +0800 Subject: drm/amd/pm: enable thermal alert on smu_v13_0_10 enable thermal alert on smu_v13_0_10 Signed-off-by: Kenneth Feng Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 3d436e7f6e95..4fe75dd2b329 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -1312,12 +1312,10 @@ static int smu_smc_hw_setup(struct smu_context *smu) return ret; } - if (adev->ip_versions[MP1_HWIP][0] != IP_VERSION(13, 0, 10)) { - ret = smu_enable_thermal_alert(smu); - if (ret) { - dev_err(adev->dev, "Failed to enable thermal alert!\n"); - return ret; - } + ret = smu_enable_thermal_alert(smu); + if (ret) { + dev_err(adev->dev, "Failed to enable thermal alert!\n"); + return ret; } ret = smu_notify_display_change(smu); -- cgit From c4dfad81e444ba27ea9944c9af061a789ab91201 Mon Sep 17 00:00:00 2001 From: YuBiao Wang Date: Thu, 13 Oct 2022 11:31:55 +0800 Subject: drm/amdgpu: dequeue mes scheduler during fini [Why] If mes is not dequeued during fini, mes will be in an uncleaned state during reload, then mes couldn't receive some commands which leads to reload failure. [How] Perform MES dequeue via MMIO after all the unmap jobs are done by mes and before kiq fini. v2: Move the dequeue operation inside kiq_hw_fini. Signed-off-by: YuBiao Wang Reviewed-by: Jack Xiao Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/mes_v11_0.c | 42 +++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c index 133804e6018a..fef7d020bc5f 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c @@ -1156,6 +1156,42 @@ static int mes_v11_0_sw_fini(void *handle) return 0; } +static void mes_v11_0_kiq_dequeue_sched(struct amdgpu_device *adev) +{ + uint32_t data; + int i; + + mutex_lock(&adev->srbm_mutex); + soc21_grbm_select(adev, 3, AMDGPU_MES_SCHED_PIPE, 0, 0); + + /* disable the queue if it's active */ + if (RREG32_SOC15(GC, 0, regCP_HQD_ACTIVE) & 1) { + WREG32_SOC15(GC, 0, regCP_HQD_DEQUEUE_REQUEST, 1); + for (i = 0; i < adev->usec_timeout; i++) { + if (!(RREG32_SOC15(GC, 0, regCP_HQD_ACTIVE) & 1)) + break; + udelay(1); + } + } + data = RREG32_SOC15(GC, 0, regCP_HQD_PQ_DOORBELL_CONTROL); + data = REG_SET_FIELD(data, CP_HQD_PQ_DOORBELL_CONTROL, + DOORBELL_EN, 0); + data = REG_SET_FIELD(data, CP_HQD_PQ_DOORBELL_CONTROL, + DOORBELL_HIT, 1); + WREG32_SOC15(GC, 0, regCP_HQD_PQ_DOORBELL_CONTROL, data); + + WREG32_SOC15(GC, 0, regCP_HQD_PQ_DOORBELL_CONTROL, 0); + + WREG32_SOC15(GC, 0, regCP_HQD_PQ_WPTR_LO, 0); + WREG32_SOC15(GC, 0, regCP_HQD_PQ_WPTR_HI, 0); + WREG32_SOC15(GC, 0, regCP_HQD_PQ_RPTR, 0); + + soc21_grbm_select(adev, 0, 0, 0, 0); + mutex_unlock(&adev->srbm_mutex); + + adev->mes.ring.sched.ready = false; +} + static void mes_v11_0_kiq_setting(struct amdgpu_ring *ring) { uint32_t tmp; @@ -1207,6 +1243,9 @@ failure: static int mes_v11_0_kiq_hw_fini(struct amdgpu_device *adev) { + if (adev->mes.ring.sched.ready) + mes_v11_0_kiq_dequeue_sched(adev); + mes_v11_0_enable(adev, false); return 0; } @@ -1262,9 +1301,6 @@ failure: static int mes_v11_0_hw_fini(void *handle) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - adev->mes.ring.sched.ready = false; return 0; } -- cgit From df768a9770271b0d9faab25f42dfc7bdec87b21c Mon Sep 17 00:00:00 2001 From: Arunpravin Paneer Selvam Date: Tue, 18 Oct 2022 07:08:38 -0700 Subject: drm/amdgpu: Fix for BO move issue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A user reported a bug on CAPE VERDE system where uvd_v3_1 IP component failed to initialize as there is an issue with BO move code from one memory to other. In function amdgpu_mem_visible() called by amdgpu_bo_move(), when there are no blocks to compare or if we have a single block then break the loop. Fixes: 312b4dc11d4f ("drm/amdgpu: Fix VRAM BO swap issue") Signed-off-by: Arunpravin Paneer Selvam Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 8782fc6bcd2c..0de9bc12793d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -439,6 +439,9 @@ static bool amdgpu_mem_visible(struct amdgpu_device *adev, while (cursor.remaining) { amdgpu_res_next(&cursor, cursor.size); + if (!cursor.remaining) + break; + /* ttm_resource_ioremap only supports contiguous memory */ if (end != cursor.start) return false; -- cgit From 8f8033d5663b18e6efb33feb61f2287a04605ab5 Mon Sep 17 00:00:00 2001 From: Rafael Mendonca Date: Mon, 17 Oct 2022 21:53:57 -0300 Subject: drm/amdgpu/powerplay/psm: Fix memory leak in power state init Commit 902bc65de0b3 ("drm/amdgpu/powerplay/psm: return an error in power state init") made the power state init function return early in case of failure to get an entry from the powerplay table, but it missed to clean up the allocated memory for the current power state before returning. Fixes: 902bc65de0b3 ("drm/amdgpu/powerplay/psm: return an error in power state init") Reviewed-by: Evan Quan Signed-off-by: Rafael Mendonca Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/powerplay/hwmgr/pp_psm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/pp_psm.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/pp_psm.c index 67d7da0b6fed..1d829402cd2e 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/pp_psm.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/pp_psm.c @@ -75,8 +75,10 @@ int psm_init_power_state_table(struct pp_hwmgr *hwmgr) for (i = 0; i < table_entries; i++) { result = hwmgr->hwmgr_func->get_pp_table_entry(hwmgr, i, state); if (result) { + kfree(hwmgr->current_ps); kfree(hwmgr->request_ps); kfree(hwmgr->ps); + hwmgr->current_ps = NULL; hwmgr->request_ps = NULL; hwmgr->ps = NULL; return -EINVAL; -- cgit From 2d3093fd5ea0e79cc6ca0e80ca56280ea7b4d0bf Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Fri, 14 Oct 2022 16:30:04 -0700 Subject: drm/i915/pvc: Update forcewake domain for CCS register ranges The bspec was just updated with a correction to the forcewake domain required when accessing registers in the CCS engine ranges (0x1a000 - 0x1ffff and 0x26000 - 0x27fff) on PVC; these ranges require a wake on the RENDER domain, not the GT domain. Bspec: 67609 Signed-off-by: Matt Roper Reviewed-by: Harish Chegondi Link: https://patchwork.freedesktop.org/patch/msgid/20221014233004.1053678-1-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/intel_uncore.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index c058cdc6d8a0..2a3e2869fe71 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -1682,25 +1682,27 @@ static const struct intel_forcewake_range __pvc_fw_ranges[] = { GEN_FW_RANGE(0x12000, 0x12fff, 0), /* 0x12000 - 0x127ff: always on 0x12800 - 0x12fff: reserved */ - GEN_FW_RANGE(0x13000, 0x23fff, FORCEWAKE_GT), /* + GEN_FW_RANGE(0x13000, 0x19fff, FORCEWAKE_GT), /* 0x13000 - 0x135ff: gt 0x13600 - 0x147ff: reserved 0x14800 - 0x153ff: gt - 0x15400 - 0x19fff: reserved - 0x1a000 - 0x1ffff: gt - 0x20000 - 0x21fff: reserved - 0x22000 - 0x23fff: gt */ + 0x15400 - 0x19fff: reserved */ + GEN_FW_RANGE(0x1a000, 0x21fff, FORCEWAKE_RENDER), /* + 0x1a000 - 0x1ffff: render + 0x20000 - 0x21fff: reserved */ + GEN_FW_RANGE(0x22000, 0x23fff, FORCEWAKE_GT), GEN_FW_RANGE(0x24000, 0x2417f, 0), /* 24000 - 0x2407f: always on 24080 - 0x2417f: reserved */ - GEN_FW_RANGE(0x24180, 0x3ffff, FORCEWAKE_GT), /* + GEN_FW_RANGE(0x24180, 0x25fff, FORCEWAKE_GT), /* 0x24180 - 0x241ff: gt 0x24200 - 0x251ff: reserved 0x25200 - 0x252ff: gt - 0x25300 - 0x25fff: reserved - 0x26000 - 0x27fff: gt - 0x28000 - 0x2ffff: reserved - 0x30000 - 0x3ffff: gt */ + 0x25300 - 0x25fff: reserved */ + GEN_FW_RANGE(0x26000, 0x2ffff, FORCEWAKE_RENDER), /* + 0x26000 - 0x27fff: render + 0x28000 - 0x2ffff: reserved */ + GEN_FW_RANGE(0x30000, 0x3ffff, FORCEWAKE_GT), GEN_FW_RANGE(0x40000, 0x1bffff, 0), GEN_FW_RANGE(0x1c0000, 0x1c3fff, FORCEWAKE_MEDIA_VDBOX0), /* 0x1c0000 - 0x1c2bff: VD0 -- cgit From 6667d78a1123d237d66e34923754ebca97d06d39 Mon Sep 17 00:00:00 2001 From: Nirmoy Das Date: Fri, 14 Oct 2022 15:14:27 +0200 Subject: drm/i915: Refactor ttm ghost obj detection Currently i915_ttm_to_gem() returns NULL for ttm ghost object which makes it unclear when we should add a NULL check for a caller of i915_ttm_to_gem() as ttm ghost objects are expected behaviour for certain cases. Create a separate function to detect ttm ghost object and use that in places where we expect a ghost obj from ttm. Signed-off-by: Nirmoy Das Reviewed-by: Matthew Auld Signed-off-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20221014131427.21102-1-nirmoy.das@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 21 ++++++++++----------- drivers/gpu/drm/i915/gem/i915_gem_ttm.h | 18 +++++++++++++----- drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c | 2 +- 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c index d63f30efd631..84c91a4228a1 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c @@ -279,7 +279,7 @@ static struct ttm_tt *i915_ttm_tt_create(struct ttm_buffer_object *bo, struct i915_ttm_tt *i915_tt; int ret; - if (!obj) + if (i915_ttm_is_ghost_object(bo)) return NULL; i915_tt = kzalloc(sizeof(*i915_tt), GFP_KERNEL); @@ -362,7 +362,7 @@ static bool i915_ttm_eviction_valuable(struct ttm_buffer_object *bo, { struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo); - if (!obj) + if (i915_ttm_is_ghost_object(bo)) return false; /* @@ -511,7 +511,7 @@ static void i915_ttm_delete_mem_notify(struct ttm_buffer_object *bo) struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo); intel_wakeref_t wakeref = 0; - if (bo->resource && likely(obj)) { + if (bo->resource && !i915_ttm_is_ghost_object(bo)) { /* ttm_bo_release() already has dma_resv_lock */ if (i915_ttm_cpu_maps_iomem(bo->resource)) wakeref = intel_runtime_pm_get(&to_i915(obj->base.dev)->runtime_pm); @@ -624,7 +624,7 @@ static void i915_ttm_swap_notify(struct ttm_buffer_object *bo) struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo); int ret; - if (!obj) + if (i915_ttm_is_ghost_object(bo)) return; ret = i915_ttm_move_notify(bo); @@ -657,7 +657,7 @@ static int i915_ttm_io_mem_reserve(struct ttm_device *bdev, struct ttm_resource struct drm_i915_gem_object *obj = i915_ttm_to_gem(mem->bo); bool unknown_state; - if (!obj) + if (i915_ttm_is_ghost_object(mem->bo)) return -EINVAL; if (!kref_get_unless_zero(&obj->base.refcount)) @@ -690,7 +690,7 @@ static unsigned long i915_ttm_io_mem_pfn(struct ttm_buffer_object *bo, unsigned long base; unsigned int ofs; - GEM_BUG_ON(!obj); + GEM_BUG_ON(i915_ttm_is_ghost_object(bo)); GEM_WARN_ON(bo->ttm); base = obj->mm.region->iomap.base - obj->mm.region->region.start; @@ -1035,13 +1035,12 @@ static vm_fault_t vm_fault_ttm(struct vm_fault *vmf) struct vm_area_struct *area = vmf->vma; struct ttm_buffer_object *bo = area->vm_private_data; struct drm_device *dev = bo->base.dev; - struct drm_i915_gem_object *obj; + struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo); intel_wakeref_t wakeref = 0; vm_fault_t ret; int idx; - obj = i915_ttm_to_gem(bo); - if (!obj) + if (i915_ttm_is_ghost_object(bo)) return VM_FAULT_SIGBUS; /* Sanity check that we allow writing into this object */ @@ -1140,7 +1139,7 @@ static void ttm_vm_open(struct vm_area_struct *vma) struct drm_i915_gem_object *obj = i915_ttm_to_gem(vma->vm_private_data); - GEM_BUG_ON(!obj); + GEM_BUG_ON(i915_ttm_is_ghost_object(vma->vm_private_data)); i915_gem_object_get(obj); } @@ -1149,7 +1148,7 @@ static void ttm_vm_close(struct vm_area_struct *vma) struct drm_i915_gem_object *obj = i915_ttm_to_gem(vma->vm_private_data); - GEM_BUG_ON(!obj); + GEM_BUG_ON(i915_ttm_is_ghost_object(vma->vm_private_data)); i915_gem_object_put(obj); } diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.h b/drivers/gpu/drm/i915/gem/i915_gem_ttm.h index e4842b4296fc..2a94a99ef76b 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.h @@ -27,19 +27,27 @@ i915_gem_to_ttm(struct drm_i915_gem_object *obj) */ void i915_ttm_bo_destroy(struct ttm_buffer_object *bo); +/** + * i915_ttm_is_ghost_object - Check if the ttm bo is a ghost object. + * @bo: Pointer to the ttm buffer object + * + * Return: True if the ttm bo is not a i915 object but a ghost ttm object, + * False otherwise. + */ +static inline bool i915_ttm_is_ghost_object(struct ttm_buffer_object *bo) +{ + return bo->destroy != i915_ttm_bo_destroy; +} + /** * i915_ttm_to_gem - Convert a struct ttm_buffer_object to an embedding * struct drm_i915_gem_object. * - * Return: Pointer to the embedding struct ttm_buffer_object, or NULL - * if the object was not an i915 ttm object. + * Return: Pointer to the embedding struct ttm_buffer_object. */ static inline struct drm_i915_gem_object * i915_ttm_to_gem(struct ttm_buffer_object *bo) { - if (bo->destroy != i915_ttm_bo_destroy) - return NULL; - return container_of(bo, struct drm_i915_gem_object, __do_not_access); } diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c index 9a7e50534b84..f59f812dc6d2 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c @@ -560,7 +560,7 @@ int i915_ttm_move(struct ttm_buffer_object *bo, bool evict, bool clear; int ret; - if (GEM_WARN_ON(!obj)) { + if (GEM_WARN_ON(i915_ttm_is_ghost_object(bo))) { ttm_bo_move_null(bo, dst_mem); return 0; } -- cgit From 20c68127e8e9d7899001c47465d0b79581f5fdc1 Mon Sep 17 00:00:00 2001 From: Nirmoy Das Date: Fri, 14 Oct 2022 17:46:55 +0200 Subject: drm/i915: Print return value on error Print returned error code for better debuggability. References: https://gitlab.freedesktop.org/drm/intel/-/issues/7211 Signed-off-by: Nirmoy Das Reviewed-by: Andrzej Hajda Signed-off-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20221014154655.14075-1-nirmoy.das@intel.com --- drivers/gpu/drm/i915/display/intel_fbdev.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c index b3a254c34fc6..efbdf1c144b3 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev.c @@ -175,7 +175,7 @@ static int intelfb_alloc(struct drm_fb_helper *helper, } if (IS_ERR(obj)) { - drm_err(&dev_priv->drm, "failed to allocate framebuffer\n"); + drm_err(&dev_priv->drm, "failed to allocate framebuffer (%pe)\n", obj); return PTR_ERR(obj); } @@ -256,7 +256,7 @@ static int intelfb_create(struct drm_fb_helper *helper, info = drm_fb_helper_alloc_fbi(helper); if (IS_ERR(info)) { - drm_err(&dev_priv->drm, "Failed to allocate fb_info\n"); + drm_err(&dev_priv->drm, "Failed to allocate fb_info (%pe)\n", info); ret = PTR_ERR(info); goto out_unpin; } @@ -291,7 +291,7 @@ static int intelfb_create(struct drm_fb_helper *helper, vaddr = i915_vma_pin_iomap(vma); if (IS_ERR(vaddr)) { drm_err(&dev_priv->drm, - "Failed to remap framebuffer into virtual memory\n"); + "Failed to remap framebuffer into virtual memory (%pe)\n", vaddr); ret = PTR_ERR(vaddr); goto out_unpin; } -- cgit From 833cad8c373f31805d5bf44929f1822ddf7a6b48 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Aug 2021 13:59:45 +0300 Subject: dt-bindings: display: xlnx: zynqmp-dpsub: Add OF graph ports The DPSUB doesn't live in isolation, but is connected to the programmable logic for live inputs and outputs, and also has a DisplayPort output. Model all those using OF graph. Signed-off-by: Laurent Pinchart Reviewed-by: Rob Herring --- .../bindings/display/xlnx/xlnx,zynqmp-dpsub.yaml | 67 ++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/Documentation/devicetree/bindings/display/xlnx/xlnx,zynqmp-dpsub.yaml b/Documentation/devicetree/bindings/display/xlnx/xlnx,zynqmp-dpsub.yaml index 10ec78ca1c65..554f9d5809d4 100644 --- a/Documentation/devicetree/bindings/display/xlnx/xlnx,zynqmp-dpsub.yaml +++ b/Documentation/devicetree/bindings/display/xlnx/xlnx,zynqmp-dpsub.yaml @@ -117,6 +117,45 @@ properties: - const: dp-phy0 - const: dp-phy1 + ports: + $ref: /schemas/graph.yaml#/properties/ports + description: | + Connections to the programmable logic and the DisplayPort PHYs. Each port + shall have a single endpoint. + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: The live video input from the programmable logic + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: The live graphics input from the programmable logic + + port@2: + $ref: /schemas/graph.yaml#/properties/port + description: The live audio input from the programmable logic + + port@3: + $ref: /schemas/graph.yaml#/properties/port + description: The blended video output to the programmable logic + + port@4: + $ref: /schemas/graph.yaml#/properties/port + description: The mixed audio output to the programmable logic + + port@5: + $ref: /schemas/graph.yaml#/properties/port + description: The DisplayPort output + + required: + - port@0 + - port@1 + - port@2 + - port@3 + - port@4 + - port@5 + required: - compatible - reg @@ -130,6 +169,7 @@ required: - dma-names - phys - phy-names + - ports additionalProperties: false @@ -164,6 +204,33 @@ examples: <&psgtr 0 PHY_TYPE_DP 1 3>; phy-names = "dp-phy0", "dp-phy1"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + }; + port@1 { + reg = <1>; + }; + port@2 { + reg = <2>; + }; + port@3 { + reg = <3>; + }; + port@4 { + reg = <4>; + }; + port@5 { + reg = <5>; + dpsub_dp_out: endpoint { + remote-endpoint = <&dp_connector>; + }; + }; + }; }; ... -- cgit From ccce29ea4bb73fec9effcca5bafa1c9fe48e2870 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 4 Aug 2021 19:21:41 +0300 Subject: drm: xlnx: zynqmp_dpsub: Switch to atomic encoder enable/disable To prepare for the transition to the DRM bridge API, switch the encoder operations to the atomic versions of .enable() and .disable(). This doesn't cause any functional change by itself. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/xlnx/zynqmp_dp.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c index d14612b34796..10e469c92e73 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c @@ -1400,7 +1400,8 @@ zynqmp_dp_connector_helper_funcs = { * DRM Encoder */ -static void zynqmp_dp_encoder_enable(struct drm_encoder *encoder) +static void zynqmp_dp_encoder_atomic_enable(struct drm_encoder *encoder, + struct drm_atomic_state *state) { struct zynqmp_dp *dp = encoder_to_dp(encoder); unsigned int i; @@ -1432,7 +1433,8 @@ static void zynqmp_dp_encoder_enable(struct drm_encoder *encoder) zynqmp_dp_write(dp, ZYNQMP_DP_MAIN_STREAM_ENABLE, 1); } -static void zynqmp_dp_encoder_disable(struct drm_encoder *encoder) +static void zynqmp_dp_encoder_atomic_disable(struct drm_encoder *encoder, + struct drm_atomic_state *state) { struct zynqmp_dp *dp = encoder_to_dp(encoder); @@ -1509,8 +1511,8 @@ zynqmp_dp_encoder_atomic_check(struct drm_encoder *encoder, } static const struct drm_encoder_helper_funcs zynqmp_dp_encoder_helper_funcs = { - .enable = zynqmp_dp_encoder_enable, - .disable = zynqmp_dp_encoder_disable, + .atomic_enable = zynqmp_dp_encoder_atomic_enable, + .atomic_disable = zynqmp_dp_encoder_atomic_disable, .atomic_mode_set = zynqmp_dp_encoder_atomic_mode_set, .atomic_check = zynqmp_dp_encoder_atomic_check, }; -- cgit From d693bd3b5b640fadc1d2d310b9bc7256cfdc557c Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 4 Aug 2021 19:21:41 +0300 Subject: drm: xlnx: zynqmp_dpsub: Constify mode argument to function The zynqmp_dp_encoder_mode_set_transfer_unit() function takes a mode pointer argument that it doesn't need to modify. Make it const. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/xlnx/zynqmp_dp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c index 10e469c92e73..a2d87543d637 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c @@ -1195,7 +1195,7 @@ static int zynqmp_dp_set_format(struct zynqmp_dp *dp, */ static void zynqmp_dp_encoder_mode_set_transfer_unit(struct zynqmp_dp *dp, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { u32 tu = ZYNQMP_DP_MSA_TRANSFER_UNIT_SIZE_TU_SIZE_DEF; u32 bw, vid_kbytes, avg_bytes_per_tu, init_wait; -- cgit From 47e801bd0749f0691a137255e2db35f5348f4f4f Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 4 Aug 2021 19:21:41 +0300 Subject: drm: xlnx: zynqmp_dpsub: Create DRM bridge to model DP encoder The DP encoder is currently modelled as a DRM encoder and DRM connector. This doesn't support system configurations where the DP encoder is driven by the FPGA programmable logic, using the live video input to the DP subsystem. To enable such use cases, we need to model the encoder as a DRM bridge. As a first step, create a DRM bridge in the DP encoder driver. Move and delegate the implementation of the DRM encoder and connector operations to the bridge to prepare for the transition. The bridge will be registered with the DRM core as a separate change. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/xlnx/zynqmp_dp.c | 333 ++++++++++++++++++++++++++------------- 1 file changed, 225 insertions(+), 108 deletions(-) diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c index a2d87543d637..8acd5cfbbd1d 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c @@ -285,6 +285,7 @@ struct zynqmp_dp_config { * @iomem: device I/O memory for register access * @reset: reset controller * @irq: irq + * @bridge: DRM bridge for the DP encoder * @config: IP core configuration from DTS * @aux: aux channel * @phy: PHY handles for DP lanes @@ -307,6 +308,8 @@ struct zynqmp_dp { struct reset_control *reset; int irq; + struct drm_bridge bridge; + struct zynqmp_dp_config config; struct drm_dp_aux aux; struct phy *phy[ZYNQMP_DP_MAX_LANES]; @@ -331,6 +334,11 @@ static inline struct zynqmp_dp *connector_to_dp(struct drm_connector *connector) return container_of(connector, struct zynqmp_dp, connector); } +static inline struct zynqmp_dp *bridge_to_dp(struct drm_bridge *bridge) +{ + return container_of(bridge, struct zynqmp_dp, bridge); +} + static void zynqmp_dp_write(struct zynqmp_dp *dp, int offset, u32 val) { writel(val, dp->iomem + offset); @@ -1255,7 +1263,7 @@ static void zynqmp_dp_encoder_mode_set_stream(struct zynqmp_dp *dp, zynqmp_dp_write(dp, ZYNQMP_DP_MAIN_STREAM_VSTART, mode->vtotal - mode->vsync_start); - /* In synchronous mode, set the diviers */ + /* In synchronous mode, set the dividers */ if (dp->config.misc0 & ZYNQMP_DP_MAIN_STREAM_MISC0_SYNC_LOCK) { reg = drm_dp_bw_code_to_link_rate(dp->mode.bw_code); zynqmp_dp_write(dp, ZYNQMP_DP_MAIN_STREAM_N_VID, reg); @@ -1281,13 +1289,167 @@ static void zynqmp_dp_encoder_mode_set_stream(struct zynqmp_dp *dp, } /* ----------------------------------------------------------------------------- - * DRM Connector + * DRM Bridge */ -static enum drm_connector_status -zynqmp_dp_connector_detect(struct drm_connector *connector, bool force) +static int zynqmp_dp_bridge_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) { - struct zynqmp_dp *dp = connector_to_dp(connector); + return 0; +} + +static int zynqmp_dp_bridge_mode_valid(struct drm_bridge *bridge, + const struct drm_display_info *info, + const struct drm_display_mode *mode) +{ + struct zynqmp_dp *dp = bridge_to_dp(bridge); + int rate; + + if (mode->clock > ZYNQMP_MAX_FREQ) { + dev_dbg(dp->dev, "filtered mode %s for high pixel rate\n", + mode->name); + drm_mode_debug_printmodeline(mode); + return MODE_CLOCK_HIGH; + } + + /* Check with link rate and lane count */ + rate = zynqmp_dp_max_rate(dp->link_config.max_rate, + dp->link_config.max_lanes, dp->config.bpp); + if (mode->clock > rate) { + dev_dbg(dp->dev, "filtered mode %s for high pixel rate\n", + mode->name); + drm_mode_debug_printmodeline(mode); + return MODE_CLOCK_HIGH; + } + + return MODE_OK; +} + +static void zynqmp_dp_bridge_atomic_enable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) +{ + struct zynqmp_dp *dp = bridge_to_dp(bridge); + struct drm_atomic_state *state = old_bridge_state->base.state; + const struct drm_crtc_state *crtc_state; + const struct drm_display_mode *adjusted_mode; + const struct drm_display_mode *mode; + struct drm_connector *connector; + struct drm_crtc *crtc; + unsigned int i; + int rate; + int ret; + + pm_runtime_get_sync(dp->dev); + + /* + * Retrieve the CRTC mode and adjusted mode. This requires a little + * dance to go from the bridge to the encoder, to the connector and to + * the CRTC. + */ + connector = drm_atomic_get_new_connector_for_encoder(state, + bridge->encoder); + crtc = drm_atomic_get_new_connector_state(state, connector)->crtc; + crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + adjusted_mode = &crtc_state->adjusted_mode; + mode = &crtc_state->mode; + + zynqmp_dp_set_format(dp, ZYNQMP_DPSUB_FORMAT_RGB, 8); + + /* Check again as bpp or format might have been changed */ + rate = zynqmp_dp_max_rate(dp->link_config.max_rate, + dp->link_config.max_lanes, dp->config.bpp); + if (mode->clock > rate) { + dev_err(dp->dev, "mode %s has too high pixel rate\n", + mode->name); + drm_mode_debug_printmodeline(mode); + } + + /* Configure the mode */ + ret = zynqmp_dp_mode_configure(dp, adjusted_mode->clock, 0); + if (ret < 0) { + pm_runtime_put_sync(dp->dev); + return; + } + + zynqmp_dp_encoder_mode_set_transfer_unit(dp, adjusted_mode); + zynqmp_dp_encoder_mode_set_stream(dp, adjusted_mode); + + /* Enable the encoder */ + dp->enabled = true; + zynqmp_dp_update_misc(dp); + if (zynqmp_disp_audio_enabled(dp->dpsub->disp)) + zynqmp_dp_write(dp, ZYNQMP_DP_TX_AUDIO_CONTROL, 1); + zynqmp_dp_write(dp, ZYNQMP_DP_TX_PHY_POWER_DOWN, 0); + if (dp->status == connector_status_connected) { + for (i = 0; i < 3; i++) { + ret = drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, + DP_SET_POWER_D0); + if (ret == 1) + break; + usleep_range(300, 500); + } + /* Some monitors take time to wake up properly */ + msleep(zynqmp_dp_power_on_delay_ms); + } + if (ret != 1) + dev_dbg(dp->dev, "DP aux failed\n"); + else + zynqmp_dp_train_loop(dp); + zynqmp_dp_write(dp, ZYNQMP_DP_SOFTWARE_RESET, + ZYNQMP_DP_SOFTWARE_RESET_ALL); + zynqmp_dp_write(dp, ZYNQMP_DP_MAIN_STREAM_ENABLE, 1); +} + +static void zynqmp_dp_bridge_atomic_disable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) +{ + struct zynqmp_dp *dp = bridge_to_dp(bridge); + + dp->enabled = false; + cancel_delayed_work(&dp->hpd_work); + zynqmp_dp_write(dp, ZYNQMP_DP_MAIN_STREAM_ENABLE, 0); + drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, DP_SET_POWER_D3); + zynqmp_dp_write(dp, ZYNQMP_DP_TX_PHY_POWER_DOWN, + ZYNQMP_DP_TX_PHY_POWER_DOWN_ALL); + if (zynqmp_disp_audio_enabled(dp->dpsub->disp)) + zynqmp_dp_write(dp, ZYNQMP_DP_TX_AUDIO_CONTROL, 0); + pm_runtime_put_sync(dp->dev); +} + +#define ZYNQMP_DP_MIN_H_BACKPORCH 20 + +static int zynqmp_dp_bridge_atomic_check(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct zynqmp_dp *dp = bridge_to_dp(bridge); + struct drm_display_mode *mode = &crtc_state->mode; + struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode; + int diff = mode->htotal - mode->hsync_end; + + /* + * ZynqMP DP requires horizontal backporch to be greater than 12. + * This limitation may not be compatible with the sink device. + */ + if (diff < ZYNQMP_DP_MIN_H_BACKPORCH) { + int vrefresh = (adjusted_mode->clock * 1000) / + (adjusted_mode->vtotal * adjusted_mode->htotal); + + dev_dbg(dp->dev, "hbackporch adjusted: %d to %d", + diff, ZYNQMP_DP_MIN_H_BACKPORCH - diff); + diff = ZYNQMP_DP_MIN_H_BACKPORCH - diff; + adjusted_mode->htotal += diff; + adjusted_mode->clock = adjusted_mode->vtotal * + adjusted_mode->htotal * vrefresh / 1000; + } + + return 0; +} + +static enum drm_connector_status zynqmp_dp_bridge_detect(struct drm_bridge *bridge) +{ + struct zynqmp_dp *dp = bridge_to_dp(bridge); struct zynqmp_dp_link_config *link_config = &dp->link_config; u32 state, i; int ret; @@ -1327,13 +1489,46 @@ disconnected: return connector_status_disconnected; } +static struct edid *zynqmp_dp_bridge_get_edid(struct drm_bridge *bridge, + struct drm_connector *connector) +{ + struct zynqmp_dp *dp = bridge_to_dp(bridge); + + return drm_get_edid(connector, &dp->aux.ddc); +} + +static const struct drm_bridge_funcs zynqmp_dp_bridge_funcs = { + .attach = zynqmp_dp_bridge_attach, + .mode_valid = zynqmp_dp_bridge_mode_valid, + .atomic_enable = zynqmp_dp_bridge_atomic_enable, + .atomic_disable = zynqmp_dp_bridge_atomic_disable, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_reset = drm_atomic_helper_bridge_reset, + .atomic_check = zynqmp_dp_bridge_atomic_check, + .detect = zynqmp_dp_bridge_detect, + .get_edid = zynqmp_dp_bridge_get_edid, +}; + +/* ----------------------------------------------------------------------------- + * DRM Connector + */ + +static enum drm_connector_status +zynqmp_dp_connector_detect(struct drm_connector *connector, bool force) +{ + struct zynqmp_dp *dp = connector_to_dp(connector); + + return zynqmp_dp_bridge_detect(&dp->bridge); +} + static int zynqmp_dp_connector_get_modes(struct drm_connector *connector) { struct zynqmp_dp *dp = connector_to_dp(connector); struct edid *edid; int ret; - edid = drm_get_edid(connector, &dp->aux.ddc); + edid = zynqmp_dp_bridge_get_edid(&dp->bridge, connector); if (!edid) return 0; @@ -1356,28 +1551,9 @@ static int zynqmp_dp_connector_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct zynqmp_dp *dp = connector_to_dp(connector); - u8 max_lanes = dp->link_config.max_lanes; - u8 bpp = dp->config.bpp; - int max_rate = dp->link_config.max_rate; - int rate; - - if (mode->clock > ZYNQMP_MAX_FREQ) { - dev_dbg(dp->dev, "filtered the mode, %s,for high pixel rate\n", - mode->name); - drm_mode_debug_printmodeline(mode); - return MODE_CLOCK_HIGH; - } - /* Check with link rate and lane count */ - rate = zynqmp_dp_max_rate(max_rate, max_lanes, bpp); - if (mode->clock > rate) { - dev_dbg(dp->dev, "filtered the mode, %s,for high pixel rate\n", - mode->name); - drm_mode_debug_printmodeline(mode); - return MODE_CLOCK_HIGH; - } - - return MODE_OK; + return zynqmp_dp_bridge_mode_valid(&dp->bridge, &connector->display_info, + mode); } static const struct drm_connector_funcs zynqmp_dp_connector_funcs = { @@ -1404,49 +1580,20 @@ static void zynqmp_dp_encoder_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *state) { struct zynqmp_dp *dp = encoder_to_dp(encoder); - unsigned int i; - int ret = 0; + struct drm_bridge_state bridge_state; - pm_runtime_get_sync(dp->dev); - dp->enabled = true; - zynqmp_dp_update_misc(dp); - if (zynqmp_disp_audio_enabled(dp->dpsub->disp)) - zynqmp_dp_write(dp, ZYNQMP_DP_TX_AUDIO_CONTROL, 1); - zynqmp_dp_write(dp, ZYNQMP_DP_TX_PHY_POWER_DOWN, 0); - if (dp->status == connector_status_connected) { - for (i = 0; i < 3; i++) { - ret = drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, - DP_SET_POWER_D0); - if (ret == 1) - break; - usleep_range(300, 500); - } - /* Some monitors take time to wake up properly */ - msleep(zynqmp_dp_power_on_delay_ms); - } - if (ret != 1) - dev_dbg(dp->dev, "DP aux failed\n"); - else - zynqmp_dp_train_loop(dp); - zynqmp_dp_write(dp, ZYNQMP_DP_SOFTWARE_RESET, - ZYNQMP_DP_SOFTWARE_RESET_ALL); - zynqmp_dp_write(dp, ZYNQMP_DP_MAIN_STREAM_ENABLE, 1); + bridge_state.base.state = state; + zynqmp_dp_bridge_atomic_enable(&dp->bridge, &bridge_state); } static void zynqmp_dp_encoder_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *state) { struct zynqmp_dp *dp = encoder_to_dp(encoder); + struct drm_bridge_state bridge_state; - dp->enabled = false; - cancel_delayed_work(&dp->hpd_work); - zynqmp_dp_write(dp, ZYNQMP_DP_MAIN_STREAM_ENABLE, 0); - drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, DP_SET_POWER_D3); - zynqmp_dp_write(dp, ZYNQMP_DP_TX_PHY_POWER_DOWN, - ZYNQMP_DP_TX_PHY_POWER_DOWN_ALL); - if (zynqmp_disp_audio_enabled(dp->dpsub->disp)) - zynqmp_dp_write(dp, ZYNQMP_DP_TX_AUDIO_CONTROL, 0); - pm_runtime_put_sync(dp->dev); + bridge_state.base.state = state; + zynqmp_dp_bridge_atomic_disable(&dp->bridge, &bridge_state); } static void @@ -1454,60 +1601,17 @@ zynqmp_dp_encoder_atomic_mode_set(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state, struct drm_connector_state *connector_state) { - struct zynqmp_dp *dp = encoder_to_dp(encoder); - struct drm_display_mode *mode = &crtc_state->mode; - struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode; - u8 max_lanes = dp->link_config.max_lanes; - u8 bpp = dp->config.bpp; - int rate, max_rate = dp->link_config.max_rate; - int ret; - - zynqmp_dp_set_format(dp, ZYNQMP_DPSUB_FORMAT_RGB, 8); - - /* Check again as bpp or format might have been chagned */ - rate = zynqmp_dp_max_rate(max_rate, max_lanes, bpp); - if (mode->clock > rate) { - dev_err(dp->dev, "the mode, %s,has too high pixel rate\n", - mode->name); - drm_mode_debug_printmodeline(mode); - } - - ret = zynqmp_dp_mode_configure(dp, adjusted_mode->clock, 0); - if (ret < 0) - return; - - zynqmp_dp_encoder_mode_set_transfer_unit(dp, adjusted_mode); - zynqmp_dp_encoder_mode_set_stream(dp, adjusted_mode); } -#define ZYNQMP_DP_MIN_H_BACKPORCH 20 - static int zynqmp_dp_encoder_atomic_check(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state, struct drm_connector_state *conn_state) { - struct drm_display_mode *mode = &crtc_state->mode; - struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode; - int diff = mode->htotal - mode->hsync_end; - - /* - * ZynqMP DP requires horizontal backporch to be greater than 12. - * This limitation may not be compatible with the sink device. - */ - if (diff < ZYNQMP_DP_MIN_H_BACKPORCH) { - int vrefresh = (adjusted_mode->clock * 1000) / - (adjusted_mode->vtotal * adjusted_mode->htotal); - - dev_dbg(encoder->dev->dev, "hbackporch adjusted: %d to %d", - diff, ZYNQMP_DP_MIN_H_BACKPORCH - diff); - diff = ZYNQMP_DP_MIN_H_BACKPORCH - diff; - adjusted_mode->htotal += diff; - adjusted_mode->clock = adjusted_mode->vtotal * - adjusted_mode->htotal * vrefresh / 1000; - } + struct zynqmp_dp *dp = encoder_to_dp(encoder); - return 0; + return zynqmp_dp_bridge_atomic_check(&dp->bridge, NULL, crtc_state, + conn_state); } static const struct drm_encoder_helper_funcs zynqmp_dp_encoder_helper_funcs = { @@ -1604,6 +1708,7 @@ handled: int zynqmp_dp_drm_init(struct zynqmp_dpsub *dpsub) { struct zynqmp_dp *dp = dpsub->dp; + struct drm_bridge *bridge = &dp->bridge; struct drm_encoder *encoder = &dp->encoder; struct drm_connector *connector = &dp->connector; int ret; @@ -1611,6 +1716,18 @@ int zynqmp_dp_drm_init(struct zynqmp_dpsub *dpsub) dp->config.misc0 &= ~ZYNQMP_DP_MAIN_STREAM_MISC0_SYNC_LOCK; zynqmp_dp_set_format(dp, ZYNQMP_DPSUB_FORMAT_RGB, 8); + /* + * Initialize the bridge. Setting the device and encoder manually is a + * hack, to be removed once the bridge will get attached to the encoder + * using the bridge API. + */ + bridge->dev = dp->drm; + bridge->encoder = &dp->encoder; + bridge->funcs = &zynqmp_dp_bridge_funcs; + bridge->ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID + | DRM_BRIDGE_OP_HPD; + bridge->type = DRM_MODE_CONNECTOR_DisplayPort; + /* Create the DRM encoder and connector. */ encoder->possible_crtcs |= zynqmp_disp_get_crtc_mask(dpsub->disp); drm_simple_encoder_init(dp->drm, encoder, DRM_MODE_ENCODER_TMDS); -- cgit From 5827398b0e765324bdd89df96b3e948847dc7663 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 4 Aug 2021 19:21:41 +0300 Subject: drm: xlnx: zynqmp_dpsub: Don't access connector in zynqmp_dp_set_format() To prepare for the removal of the connector from the DP encoder, pass the display info pointer to the zynqmp_dp_set_format() function instead of accessing the connector internally. The display info is NULL when the function is called at initialization time, as we have no display info at that point. This doesn't change the existing behaviour, given that the zynqmp_dp_set_format() was already handling this as a special case (the display info isn't initialized at init time and is all zeroes). Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/xlnx/zynqmp_dp.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c index 8acd5cfbbd1d..ca566553e547 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c @@ -1109,6 +1109,7 @@ static void zynqmp_dp_update_misc(struct zynqmp_dp *dp) /** * zynqmp_dp_set_format - Set the input format * @dp: DisplayPort IP core structure + * @info: Display info * @format: input format * @bpc: bits per component * @@ -1117,10 +1118,10 @@ static void zynqmp_dp_update_misc(struct zynqmp_dp *dp) * Return: 0 on success, or -EINVAL. */ static int zynqmp_dp_set_format(struct zynqmp_dp *dp, + const struct drm_display_info *info, enum zynqmp_dpsub_format format, unsigned int bpc) { - static const struct drm_display_info *display; struct zynqmp_dp_config *config = &dp->config; unsigned int num_colors; @@ -1153,12 +1154,11 @@ static int zynqmp_dp_set_format(struct zynqmp_dp *dp, return -EINVAL; } - display = &dp->connector.display_info; - if (display->bpc && bpc > display->bpc) { + if (info && info->bpc && bpc > info->bpc) { dev_warn(dp->dev, "downgrading requested %ubpc to display limit %ubpc\n", - bpc, display->bpc); - bpc = display->bpc; + bpc, info->bpc); + bpc = info->bpc; } config->misc0 &= ~ZYNQMP_DP_MAIN_STREAM_MISC0_BPC_MASK; @@ -1353,7 +1353,8 @@ static void zynqmp_dp_bridge_atomic_enable(struct drm_bridge *bridge, adjusted_mode = &crtc_state->adjusted_mode; mode = &crtc_state->mode; - zynqmp_dp_set_format(dp, ZYNQMP_DPSUB_FORMAT_RGB, 8); + zynqmp_dp_set_format(dp, &connector->display_info, + ZYNQMP_DPSUB_FORMAT_RGB, 8); /* Check again as bpp or format might have been changed */ rate = zynqmp_dp_max_rate(dp->link_config.max_rate, @@ -1714,7 +1715,7 @@ int zynqmp_dp_drm_init(struct zynqmp_dpsub *dpsub) int ret; dp->config.misc0 &= ~ZYNQMP_DP_MAIN_STREAM_MISC0_SYNC_LOCK; - zynqmp_dp_set_format(dp, ZYNQMP_DPSUB_FORMAT_RGB, 8); + zynqmp_dp_set_format(dp, NULL, ZYNQMP_DPSUB_FORMAT_RGB, 8); /* * Initialize the bridge. Setting the device and encoder manually is a -- cgit From 2374b6ea30384f23a78555c3b962bce358a8869e Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 4 Aug 2021 19:21:41 +0300 Subject: drm: xlnx: zynqmp_dpsub: Move connector registration to bridge attach Connector creation requires the DRM encoder, and it thus typically performed in the bridge attach operation. Move it there, to prepare for registration of the DRM bridge. For now the zynqmp_dp_bridge_attach() is called manually at initialization time. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/xlnx/zynqmp_dp.c | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c index ca566553e547..65b1ab4e4d2d 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c @@ -1292,9 +1292,30 @@ static void zynqmp_dp_encoder_mode_set_stream(struct zynqmp_dp *dp, * DRM Bridge */ +static const struct drm_connector_funcs zynqmp_dp_connector_funcs; +static const struct drm_connector_helper_funcs zynqmp_dp_connector_helper_funcs; + static int zynqmp_dp_bridge_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags) { + struct zynqmp_dp *dp = bridge_to_dp(bridge); + struct drm_connector *connector = &dp->connector; + int ret; + + /* Create the DRM connector. */ + connector->polled = DRM_CONNECTOR_POLL_HPD; + ret = drm_connector_init(dp->drm, connector, + &zynqmp_dp_connector_funcs, + DRM_MODE_CONNECTOR_DisplayPort); + if (ret) { + dev_err(dp->dev, "failed to create the DRM connector\n"); + return ret; + } + + drm_connector_helper_add(connector, &zynqmp_dp_connector_helper_funcs); + drm_connector_register(connector); + drm_connector_attach_encoder(connector, bridge->encoder); + return 0; } @@ -1711,7 +1732,6 @@ int zynqmp_dp_drm_init(struct zynqmp_dpsub *dpsub) struct zynqmp_dp *dp = dpsub->dp; struct drm_bridge *bridge = &dp->bridge; struct drm_encoder *encoder = &dp->encoder; - struct drm_connector *connector = &dp->connector; int ret; dp->config.misc0 &= ~ZYNQMP_DP_MAIN_STREAM_MISC0_SYNC_LOCK; @@ -1729,23 +1749,14 @@ int zynqmp_dp_drm_init(struct zynqmp_dpsub *dpsub) | DRM_BRIDGE_OP_HPD; bridge->type = DRM_MODE_CONNECTOR_DisplayPort; - /* Create the DRM encoder and connector. */ + /* Create the DRM encoder and attach the bridge. */ encoder->possible_crtcs |= zynqmp_disp_get_crtc_mask(dpsub->disp); drm_simple_encoder_init(dp->drm, encoder, DRM_MODE_ENCODER_TMDS); drm_encoder_helper_add(encoder, &zynqmp_dp_encoder_helper_funcs); - connector->polled = DRM_CONNECTOR_POLL_HPD; - ret = drm_connector_init(encoder->dev, connector, - &zynqmp_dp_connector_funcs, - DRM_MODE_CONNECTOR_DisplayPort); - if (ret) { - dev_err(dp->dev, "failed to create the DRM connector\n"); + ret = zynqmp_dp_bridge_attach(bridge, 0); + if (ret < 0) return ret; - } - - drm_connector_helper_add(connector, &zynqmp_dp_connector_helper_funcs); - drm_connector_register(connector); - drm_connector_attach_encoder(connector, encoder); /* Initialize and register the AUX adapter. */ ret = zynqmp_dp_aux_init(dp); -- cgit From e8e357337dc91f6c2c28a06f783f0219b77ba07a Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 4 Aug 2021 19:21:41 +0300 Subject: drm: xlnx: zynqmp_dpsub: Move encoder to DPSUB core As part of the transitition of the DP encoder to a DRM bridge, turn the DRM encoder into a dummy encoder and move it out of the DP code, to the DPSUB core. DP encoder operations are handled by the DP bridge, which is now attached to the encoder. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/xlnx/zynqmp_dp.c | 79 ++----------------------------------- drivers/gpu/drm/xlnx/zynqmp_dpsub.c | 16 +++++++- drivers/gpu/drm/xlnx/zynqmp_dpsub.h | 8 ++++ 3 files changed, 25 insertions(+), 78 deletions(-) diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c index 65b1ab4e4d2d..28f92b5d8385 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c @@ -15,12 +15,10 @@ #include #include #include -#include #include #include #include #include -#include #include #include @@ -277,7 +275,6 @@ struct zynqmp_dp_config { /** * struct zynqmp_dp - Xilinx DisplayPort core - * @encoder: the drm encoder structure * @connector: the drm connector structure * @dev: device structure * @dpsub: Display subsystem @@ -299,7 +296,6 @@ struct zynqmp_dp_config { * @train_set: set of training data */ struct zynqmp_dp { - struct drm_encoder encoder; struct drm_connector connector; struct device *dev; struct zynqmp_dpsub *dpsub; @@ -324,11 +320,6 @@ struct zynqmp_dp { u8 train_set[ZYNQMP_DP_MAX_LANES]; }; -static inline struct zynqmp_dp *encoder_to_dp(struct drm_encoder *encoder) -{ - return container_of(encoder, struct zynqmp_dp, encoder); -} - static inline struct zynqmp_dp *connector_to_dp(struct drm_connector *connector) { return container_of(connector, struct zynqmp_dp, connector); @@ -1566,7 +1557,7 @@ zynqmp_dp_connector_best_encoder(struct drm_connector *connector) { struct zynqmp_dp *dp = connector_to_dp(connector); - return &dp->encoder; + return &dp->dpsub->encoder; } static int zynqmp_dp_connector_mode_valid(struct drm_connector *connector, @@ -1594,55 +1585,6 @@ zynqmp_dp_connector_helper_funcs = { .mode_valid = zynqmp_dp_connector_mode_valid, }; -/* ----------------------------------------------------------------------------- - * DRM Encoder - */ - -static void zynqmp_dp_encoder_atomic_enable(struct drm_encoder *encoder, - struct drm_atomic_state *state) -{ - struct zynqmp_dp *dp = encoder_to_dp(encoder); - struct drm_bridge_state bridge_state; - - bridge_state.base.state = state; - zynqmp_dp_bridge_atomic_enable(&dp->bridge, &bridge_state); -} - -static void zynqmp_dp_encoder_atomic_disable(struct drm_encoder *encoder, - struct drm_atomic_state *state) -{ - struct zynqmp_dp *dp = encoder_to_dp(encoder); - struct drm_bridge_state bridge_state; - - bridge_state.base.state = state; - zynqmp_dp_bridge_atomic_disable(&dp->bridge, &bridge_state); -} - -static void -zynqmp_dp_encoder_atomic_mode_set(struct drm_encoder *encoder, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *connector_state) -{ -} - -static int -zynqmp_dp_encoder_atomic_check(struct drm_encoder *encoder, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state) -{ - struct zynqmp_dp *dp = encoder_to_dp(encoder); - - return zynqmp_dp_bridge_atomic_check(&dp->bridge, NULL, crtc_state, - conn_state); -} - -static const struct drm_encoder_helper_funcs zynqmp_dp_encoder_helper_funcs = { - .atomic_enable = zynqmp_dp_encoder_atomic_enable, - .atomic_disable = zynqmp_dp_encoder_atomic_disable, - .atomic_mode_set = zynqmp_dp_encoder_atomic_mode_set, - .atomic_check = zynqmp_dp_encoder_atomic_check, -}; - /* ----------------------------------------------------------------------------- * Interrupt Handling */ @@ -1731,32 +1673,17 @@ int zynqmp_dp_drm_init(struct zynqmp_dpsub *dpsub) { struct zynqmp_dp *dp = dpsub->dp; struct drm_bridge *bridge = &dp->bridge; - struct drm_encoder *encoder = &dp->encoder; int ret; dp->config.misc0 &= ~ZYNQMP_DP_MAIN_STREAM_MISC0_SYNC_LOCK; zynqmp_dp_set_format(dp, NULL, ZYNQMP_DPSUB_FORMAT_RGB, 8); - /* - * Initialize the bridge. Setting the device and encoder manually is a - * hack, to be removed once the bridge will get attached to the encoder - * using the bridge API. - */ - bridge->dev = dp->drm; - bridge->encoder = &dp->encoder; + /* Initialize the bridge. */ bridge->funcs = &zynqmp_dp_bridge_funcs; bridge->ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_HPD; bridge->type = DRM_MODE_CONNECTOR_DisplayPort; - - /* Create the DRM encoder and attach the bridge. */ - encoder->possible_crtcs |= zynqmp_disp_get_crtc_mask(dpsub->disp); - drm_simple_encoder_init(dp->drm, encoder, DRM_MODE_ENCODER_TMDS); - drm_encoder_helper_add(encoder, &zynqmp_dp_encoder_helper_funcs); - - ret = zynqmp_dp_bridge_attach(bridge, 0); - if (ret < 0) - return ret; + dpsub->bridge = bridge; /* Initialize and register the AUX adapter. */ ret = zynqmp_dp_aux_init(dp); diff --git a/drivers/gpu/drm/xlnx/zynqmp_dpsub.c b/drivers/gpu/drm/xlnx/zynqmp_dpsub.c index 1de2d927c32b..bb7c74a73dc2 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dpsub.c +++ b/drivers/gpu/drm/xlnx/zynqmp_dpsub.c @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -27,6 +28,7 @@ #include #include #include +#include #include #include "zynqmp_disp.h" @@ -94,6 +96,7 @@ static const struct drm_driver zynqmp_dpsub_drm_driver = { static int zynqmp_dpsub_drm_init(struct zynqmp_dpsub *dpsub) { + struct drm_encoder *encoder = &dpsub->encoder; struct drm_device *drm = &dpsub->drm; int ret; @@ -116,8 +119,7 @@ static int zynqmp_dpsub_drm_init(struct zynqmp_dpsub *dpsub) /* * Initialize the DISP and DP components. This will creates planes, - * CRTC, encoder and connector. The DISP should be initialized first as - * the DP encoder needs the CRTC. + * CRTC, and a bridge for the DP encoder. */ ret = zynqmp_disp_drm_init(dpsub); if (ret) @@ -127,6 +129,16 @@ static int zynqmp_dpsub_drm_init(struct zynqmp_dpsub *dpsub) if (ret) goto err_poll_fini; + /* Create the encoder and attach the bridge. */ + encoder->possible_crtcs |= zynqmp_disp_get_crtc_mask(dpsub->disp); + drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_NONE); + + ret = drm_bridge_attach(encoder, dpsub->bridge, NULL, 0); + if (ret) { + dev_err(dpsub->dev, "failed to attach bridge to encoder\n"); + goto err_poll_fini; + } + /* Reset all components and register the DRM device. */ drm_mode_config_reset(drm); diff --git a/drivers/gpu/drm/xlnx/zynqmp_dpsub.h b/drivers/gpu/drm/xlnx/zynqmp_dpsub.h index c04026d82639..66820bbc4507 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dpsub.h +++ b/drivers/gpu/drm/xlnx/zynqmp_dpsub.h @@ -12,8 +12,11 @@ #ifndef _ZYNQMP_DPSUB_H_ #define _ZYNQMP_DPSUB_H_ +#include + struct clk; struct device; +struct drm_bridge; struct drm_device; struct zynqmp_disp; struct zynqmp_dp; @@ -30,6 +33,8 @@ enum zynqmp_dpsub_format { * @drm: The DRM/KMS device * @dev: The physical device * @apb_clk: The APB clock + * @encoder: The dummy DRM encoder + * @bridge: The DP encoder bridge * @disp: The display controller * @dp: The DisplayPort controller * @dma_align: DMA alignment constraint (must be a power of 2) @@ -40,6 +45,9 @@ struct zynqmp_dpsub { struct clk *apb_clk; + struct drm_encoder encoder; + struct drm_bridge *bridge; + struct zynqmp_disp *disp; struct zynqmp_dp *dp; -- cgit From bd68b9b3cb2e0d48a6adb773fa11393f869a7f9a Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 4 Aug 2021 19:21:41 +0300 Subject: drm: xlnx: zynqmp_dpsub: Attach to the next bridge The next component in the display chain, after the DP encoder, is most likely a DP connector. The display connector driver registers a bridge for it. That bridge doesn't need to be controlled, but is needed in order to use the DRM connector bridge helper. Retrieve it at init time, and attach to it in the DP bridge attach handler. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/xlnx/zynqmp_dp.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c index 28f92b5d8385..0aa810ebdeca 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c @@ -283,6 +283,7 @@ struct zynqmp_dp_config { * @reset: reset controller * @irq: irq * @bridge: DRM bridge for the DP encoder + * @next_bridge: The downstream bridge * @config: IP core configuration from DTS * @aux: aux channel * @phy: PHY handles for DP lanes @@ -305,6 +306,7 @@ struct zynqmp_dp { int irq; struct drm_bridge bridge; + struct drm_bridge *next_bridge; struct zynqmp_dp_config config; struct drm_dp_aux aux; @@ -1307,6 +1309,13 @@ static int zynqmp_dp_bridge_attach(struct drm_bridge *bridge, drm_connector_register(connector); drm_connector_attach_encoder(connector, bridge->encoder); + if (dp->next_bridge) { + ret = drm_bridge_attach(bridge->encoder, dp->next_bridge, + bridge, DRM_BRIDGE_ATTACH_NO_CONNECTOR); + if (ret < 0) + return ret; + } + return 0; } @@ -1744,6 +1753,15 @@ int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm) if (ret) goto err_reset; + /* + * Acquire the next bridge in the chain. Ignore errors caused by port@5 + * not being connected for backward-compatibility with older DTs. + */ + ret = drm_of_find_panel_or_bridge(dp->dev->of_node, 5, 0, NULL, + &dp->next_bridge); + if (ret < 0 && ret != -ENODEV) + goto err_reset; + /* Initialize the hardware. */ zynqmp_dp_write(dp, ZYNQMP_DP_TX_PHY_POWER_DOWN, ZYNQMP_DP_TX_PHY_POWER_DOWN_ALL); -- cgit From cbb11ef9871956244c38ab8520dc9abe87ccdb3b Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Aug 2021 14:29:52 +0300 Subject: drm: xlnx: zynqmp_dpsub: Use DRM connector bridge helper Replace the manual connector implementation and registration in the DP encoder with the DRM connector bridge helper. This removes boilerplate code and simplifies the driver. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/xlnx/zynqmp_dp.c | 90 +------------------------------------ drivers/gpu/drm/xlnx/zynqmp_dpsub.c | 20 ++++++++- 2 files changed, 20 insertions(+), 90 deletions(-) diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c index 0aa810ebdeca..a18cb979be52 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c @@ -11,7 +11,6 @@ #include #include -#include #include #include #include @@ -275,7 +274,6 @@ struct zynqmp_dp_config { /** * struct zynqmp_dp - Xilinx DisplayPort core - * @connector: the drm connector structure * @dev: device structure * @dpsub: Display subsystem * @drm: DRM core @@ -297,7 +295,6 @@ struct zynqmp_dp_config { * @train_set: set of training data */ struct zynqmp_dp { - struct drm_connector connector; struct device *dev; struct zynqmp_dpsub *dpsub; struct drm_device *drm; @@ -322,11 +319,6 @@ struct zynqmp_dp { u8 train_set[ZYNQMP_DP_MAX_LANES]; }; -static inline struct zynqmp_dp *connector_to_dp(struct drm_connector *connector) -{ - return container_of(connector, struct zynqmp_dp, connector); -} - static inline struct zynqmp_dp *bridge_to_dp(struct drm_bridge *bridge) { return container_of(bridge, struct zynqmp_dp, bridge); @@ -1285,33 +1277,15 @@ static void zynqmp_dp_encoder_mode_set_stream(struct zynqmp_dp *dp, * DRM Bridge */ -static const struct drm_connector_funcs zynqmp_dp_connector_funcs; -static const struct drm_connector_helper_funcs zynqmp_dp_connector_helper_funcs; - static int zynqmp_dp_bridge_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags) { struct zynqmp_dp *dp = bridge_to_dp(bridge); - struct drm_connector *connector = &dp->connector; int ret; - /* Create the DRM connector. */ - connector->polled = DRM_CONNECTOR_POLL_HPD; - ret = drm_connector_init(dp->drm, connector, - &zynqmp_dp_connector_funcs, - DRM_MODE_CONNECTOR_DisplayPort); - if (ret) { - dev_err(dp->dev, "failed to create the DRM connector\n"); - return ret; - } - - drm_connector_helper_add(connector, &zynqmp_dp_connector_helper_funcs); - drm_connector_register(connector); - drm_connector_attach_encoder(connector, bridge->encoder); - if (dp->next_bridge) { ret = drm_bridge_attach(bridge->encoder, dp->next_bridge, - bridge, DRM_BRIDGE_ATTACH_NO_CONNECTOR); + bridge, flags); if (ret < 0) return ret; } @@ -1532,68 +1506,6 @@ static const struct drm_bridge_funcs zynqmp_dp_bridge_funcs = { .get_edid = zynqmp_dp_bridge_get_edid, }; -/* ----------------------------------------------------------------------------- - * DRM Connector - */ - -static enum drm_connector_status -zynqmp_dp_connector_detect(struct drm_connector *connector, bool force) -{ - struct zynqmp_dp *dp = connector_to_dp(connector); - - return zynqmp_dp_bridge_detect(&dp->bridge); -} - -static int zynqmp_dp_connector_get_modes(struct drm_connector *connector) -{ - struct zynqmp_dp *dp = connector_to_dp(connector); - struct edid *edid; - int ret; - - edid = zynqmp_dp_bridge_get_edid(&dp->bridge, connector); - if (!edid) - return 0; - - drm_connector_update_edid_property(connector, edid); - ret = drm_add_edid_modes(connector, edid); - kfree(edid); - - return ret; -} - -static struct drm_encoder * -zynqmp_dp_connector_best_encoder(struct drm_connector *connector) -{ - struct zynqmp_dp *dp = connector_to_dp(connector); - - return &dp->dpsub->encoder; -} - -static int zynqmp_dp_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) -{ - struct zynqmp_dp *dp = connector_to_dp(connector); - - return zynqmp_dp_bridge_mode_valid(&dp->bridge, &connector->display_info, - mode); -} - -static const struct drm_connector_funcs zynqmp_dp_connector_funcs = { - .detect = zynqmp_dp_connector_detect, - .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = drm_connector_cleanup, - .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, - .reset = drm_atomic_helper_connector_reset, -}; - -static const struct drm_connector_helper_funcs -zynqmp_dp_connector_helper_funcs = { - .get_modes = zynqmp_dp_connector_get_modes, - .best_encoder = zynqmp_dp_connector_best_encoder, - .mode_valid = zynqmp_dp_connector_mode_valid, -}; - /* ----------------------------------------------------------------------------- * Interrupt Handling */ diff --git a/drivers/gpu/drm/xlnx/zynqmp_dpsub.c b/drivers/gpu/drm/xlnx/zynqmp_dpsub.c index bb7c74a73dc2..6f6e7c67d370 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dpsub.c +++ b/drivers/gpu/drm/xlnx/zynqmp_dpsub.c @@ -18,6 +18,8 @@ #include #include +#include +#include #include #include #include @@ -97,6 +99,7 @@ static const struct drm_driver zynqmp_dpsub_drm_driver = { static int zynqmp_dpsub_drm_init(struct zynqmp_dpsub *dpsub) { struct drm_encoder *encoder = &dpsub->encoder; + struct drm_connector *connector; struct drm_device *drm = &dpsub->drm; int ret; @@ -133,12 +136,27 @@ static int zynqmp_dpsub_drm_init(struct zynqmp_dpsub *dpsub) encoder->possible_crtcs |= zynqmp_disp_get_crtc_mask(dpsub->disp); drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_NONE); - ret = drm_bridge_attach(encoder, dpsub->bridge, NULL, 0); + ret = drm_bridge_attach(encoder, dpsub->bridge, NULL, + DRM_BRIDGE_ATTACH_NO_CONNECTOR); if (ret) { dev_err(dpsub->dev, "failed to attach bridge to encoder\n"); goto err_poll_fini; } + /* Create the connector for the chain of bridges. */ + connector = drm_bridge_connector_init(drm, encoder); + if (IS_ERR(connector)) { + dev_err(dpsub->dev, "failed to created connector\n"); + ret = PTR_ERR(connector); + goto err_poll_fini; + } + + ret = drm_connector_attach_encoder(connector, encoder); + if (ret < 0) { + dev_err(dpsub->dev, "failed to attach connector to encoder\n"); + goto err_poll_fini; + } + /* Reset all components and register the DRM device. */ drm_mode_config_reset(drm); -- cgit From eb2d64bfcc174919a921295a5327b99a3b8f4166 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Aug 2021 14:29:52 +0300 Subject: drm: xlnx: zynqmp_dpsub: Report HPD through the bridge Now that the driver uses the connector bridge helper, HPD can be reported directly for the connector through the drm_bridge_hpd_notify() function. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/xlnx/zynqmp_dp.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c index a18cb979be52..33fd69ed7550 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include @@ -1534,12 +1533,12 @@ void zynqmp_dp_disable_vblank(struct zynqmp_dp *dp) static void zynqmp_dp_hpd_work_func(struct work_struct *work) { - struct zynqmp_dp *dp; - - dp = container_of(work, struct zynqmp_dp, hpd_work.work); + struct zynqmp_dp *dp = container_of(work, struct zynqmp_dp, + hpd_work.work); + enum drm_connector_status status; - if (dp->drm) - drm_helper_hpd_irq_event(dp->drm); + status = zynqmp_dp_bridge_detect(&dp->bridge); + drm_bridge_hpd_notify(&dp->bridge, status); } static irqreturn_t zynqmp_dp_irq_handler(int irq, void *data) -- cgit From c7bfa73cdfeb66f3c9170e05cab3aa160c93a95b Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Aug 2021 14:29:52 +0300 Subject: drm: xlnx: zynqmp_dpsub: Drop unused zynqmp_disp.event field The event field of the zynqmp_disp structure is unused. Drop it. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/xlnx/zynqmp_disp.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c b/drivers/gpu/drm/xlnx/zynqmp_disp.c index bbb365f2d087..a168433456f7 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_disp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c @@ -171,7 +171,6 @@ struct zynqmp_disp_layer { * @audio.clk: Audio clock * @audio.clk_from_ps: True of the audio clock comes from PS, false from PL * @layers: Layers (planes) - * @event: Pending vblank event request * @pclk: Pixel clock * @pclk_from_ps: True of the video clock comes from PS, false from PL */ @@ -196,8 +195,6 @@ struct zynqmp_disp { struct zynqmp_disp_layer layers[ZYNQMP_DISP_NUM_LAYERS]; - struct drm_pending_vblank_event *event; - struct clk *pclk; bool pclk_from_ps; }; -- cgit From c91d2d383537302105c139dfb9f34d12855bb369 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Aug 2021 14:29:52 +0300 Subject: drm: xlnx: zynqmp_dpsub: Drop unused zynqmp_disp_format.bus_fmt field The bus_fmt field of the zynqmp_disp_format structure is unused. Drop it. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/xlnx/zynqmp_disp.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c b/drivers/gpu/drm/xlnx/zynqmp_disp.c index a168433456f7..e6fe6203fce7 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_disp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c @@ -79,14 +79,12 @@ * struct zynqmp_disp_format - Display subsystem format information * @drm_fmt: DRM format (4CC) * @buf_fmt: AV buffer format - * @bus_fmt: Media bus formats (live formats) * @swap: Flag to swap R & B for RGB formats, and U & V for YUV formats * @sf: Scaling factors for color components */ struct zynqmp_disp_format { u32 drm_fmt; u32 buf_fmt; - u32 bus_fmt; bool swap; const u32 *sf; }; -- cgit From a7727b3771084eadc0e5b832756e1a493949a5fd Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Aug 2021 14:29:52 +0300 Subject: drm: xlnx: zynqmp_dpsub: Don't pass CRTC to zynqmp_disp_setup_clock() To prepare for usage of the clock setup function outside of the CRTC code, replace the DRM-specific structures passed as parameters with a pointer to the zynqmp_disp and the requested clock rate. This doesn't introduce any functional change. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/xlnx/zynqmp_disp.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c b/drivers/gpu/drm/xlnx/zynqmp_disp.c index e6fe6203fce7..380540fd08ff 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_disp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c @@ -1409,16 +1409,9 @@ static void zynqmp_disp_disable(struct zynqmp_disp *disp) zynqmp_disp_avbuf_disable(disp); } -static inline struct zynqmp_disp *crtc_to_disp(struct drm_crtc *crtc) -{ - return container_of(crtc, struct zynqmp_disp, crtc); -} - -static int zynqmp_disp_crtc_setup_clock(struct drm_crtc *crtc, - struct drm_display_mode *adjusted_mode) +static int zynqmp_disp_setup_clock(struct zynqmp_disp *disp, + unsigned long mode_clock) { - struct zynqmp_disp *disp = crtc_to_disp(crtc); - unsigned long mode_clock = adjusted_mode->clock * 1000; unsigned long rate; long diff; int ret; @@ -1443,6 +1436,11 @@ static int zynqmp_disp_crtc_setup_clock(struct drm_crtc *crtc, return 0; } +static inline struct zynqmp_disp *crtc_to_disp(struct drm_crtc *crtc) +{ + return container_of(crtc, struct zynqmp_disp, crtc); +} + static void zynqmp_disp_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state) @@ -1453,7 +1451,7 @@ zynqmp_disp_crtc_atomic_enable(struct drm_crtc *crtc, pm_runtime_get_sync(disp->dev); - zynqmp_disp_crtc_setup_clock(crtc, adjusted_mode); + zynqmp_disp_setup_clock(disp, adjusted_mode->clock * 1000); ret = clk_prepare_enable(disp->pclk); if (ret) { -- cgit From 36d1b456c5fe33c054e2d5ff0033d05e36fbf8a6 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Aug 2021 14:29:52 +0300 Subject: drm: xlnx: zynqmp_dpsub: Configure blender in zynqmp_disp_enable() To prepare for control of the blender outside of the CRTC code, move the setup of the blender to the zynqmp_disp_enable() function. This doesn't introduce any functional change. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/xlnx/zynqmp_disp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c b/drivers/gpu/drm/xlnx/zynqmp_disp.c index 380540fd08ff..212f5210e129 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_disp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c @@ -1386,6 +1386,9 @@ err: */ static void zynqmp_disp_enable(struct zynqmp_disp *disp) { + zynqmp_disp_blend_set_output_format(disp, ZYNQMP_DPSUB_FORMAT_RGB); + zynqmp_disp_blend_set_bg_color(disp, 0, 0, 0); + zynqmp_disp_avbuf_enable(disp); /* Choose clock source based on the DT clock handle. */ zynqmp_disp_avbuf_set_clocks_sources(disp, disp->pclk_from_ps, @@ -1460,9 +1463,6 @@ zynqmp_disp_crtc_atomic_enable(struct drm_crtc *crtc, return; } - zynqmp_disp_blend_set_output_format(disp, ZYNQMP_DPSUB_FORMAT_RGB); - zynqmp_disp_blend_set_bg_color(disp, 0, 0, 0); - zynqmp_disp_enable(disp); /* Delay of 3 vblank intervals for timing gen to be stable */ -- cgit From 457d7180d628a303cd3c579e95f24746d915591e Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Aug 2021 14:29:52 +0300 Subject: drm: xlnx: zynqmp_dpsub: Use local variable in zynqmp_disp_layer_update() Reuse the local info variable instead of going through the layer pointer in zynqmp_disp_layer_update(). This doesn't introduce any functional change. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/xlnx/zynqmp_disp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c b/drivers/gpu/drm/xlnx/zynqmp_disp.c index 212f5210e129..e3f1d9e2982b 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_disp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c @@ -1088,7 +1088,7 @@ static int zynqmp_disp_layer_update(struct zynqmp_disp_layer *layer, const struct drm_format_info *info = layer->drm_fmt; unsigned int i; - for (i = 0; i < layer->drm_fmt->num_planes; i++) { + for (i = 0; i < info->num_planes; i++) { unsigned int width = state->crtc_w / (i ? info->hsub : 1); unsigned int height = state->crtc_h / (i ? info->vsub : 1); struct zynqmp_disp_layer_dma *dma = &layer->dmas[i]; -- cgit From 98c4ecec55d3bd2a8a79eba0adee0285724ea50f Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Aug 2021 14:29:52 +0300 Subject: drm: xlnx: zynqmp_dpsub: Pass format info to zynqmp_disp_layer_set_format() The zynqmp_disp_layer_set_format() function only needs format information, not a full plane state. Get the necessary info from the plane state in the caller and pass it to zynqmp_disp_layer_set_format(). This prepares for calling the function from non-DRM code. This doesn't introduce any functional change. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/xlnx/zynqmp_disp.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c b/drivers/gpu/drm/xlnx/zynqmp_disp.c index e3f1d9e2982b..c0d27f5e28b5 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_disp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c @@ -1037,15 +1037,13 @@ static void zynqmp_disp_layer_disable(struct zynqmp_disp_layer *layer) /** * zynqmp_disp_layer_set_format - Set the layer format * @layer: The layer - * @state: The plane state + * @info: The format info * - * Set the format for @layer based on @state->fb->format. The layer must be - * disabled. + * Set the format for @layer to @info. The layer must be disabled. */ static void zynqmp_disp_layer_set_format(struct zynqmp_disp_layer *layer, - struct drm_plane_state *state) + const struct drm_format_info *info) { - const struct drm_format_info *info = state->fb->format; unsigned int i; layer->disp_fmt = zynqmp_disp_layer_find_format(layer, info->format); @@ -1190,7 +1188,7 @@ zynqmp_disp_plane_atomic_update(struct drm_plane *plane, if (old_state->fb) zynqmp_disp_layer_disable(layer); - zynqmp_disp_layer_set_format(layer, new_state); + zynqmp_disp_layer_set_format(layer, new_state->fb->format); } zynqmp_disp_layer_update(layer, new_state); -- cgit From 531306f54e84b9502f18db66f81729df7bc5fbe3 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Aug 2021 14:29:52 +0300 Subject: drm: xlnx: zynqmp_dpsub: Remplace hardcoded values with ARRAY_SIZE() Use the ARRAY_SIZE() macro to iterate over arrays, instead of hardcoding their size. This makes the code less error-prone should the array size change. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/xlnx/zynqmp_disp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c b/drivers/gpu/drm/xlnx/zynqmp_disp.c index c0d27f5e28b5..e722af0e59a9 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_disp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c @@ -1222,7 +1222,7 @@ static int zynqmp_disp_create_planes(struct zynqmp_disp *disp) unsigned int i, j; int ret; - for (i = 0; i < ZYNQMP_DISP_NUM_LAYERS; i++) { + for (i = 0; i < ARRAY_SIZE(disp->layers); i++) { struct zynqmp_disp_layer *layer = &disp->layers[i]; enum drm_plane_type type; u32 *drm_formats; @@ -1293,7 +1293,7 @@ static void zynqmp_disp_destroy_layers(struct zynqmp_disp *disp) { unsigned int i; - for (i = 0; i < ZYNQMP_DISP_NUM_LAYERS; i++) + for (i = 0; i < ARRAY_SIZE(disp->layers); i++) zynqmp_disp_layer_release_dma(disp, &disp->layers[i]); } @@ -1355,7 +1355,7 @@ static int zynqmp_disp_create_layers(struct zynqmp_disp *disp) unsigned int i; int ret; - for (i = 0; i < ZYNQMP_DISP_NUM_LAYERS; i++) { + for (i = 0; i < ARRAY_SIZE(disp->layers); i++) { struct zynqmp_disp_layer *layer = &disp->layers[i]; layer->id = i; @@ -1592,7 +1592,7 @@ static void zynqmp_disp_map_crtc_to_plane(struct zynqmp_disp *disp) u32 possible_crtcs = drm_crtc_mask(&disp->crtc); unsigned int i; - for (i = 0; i < ZYNQMP_DISP_NUM_LAYERS; i++) + for (i = 0; i < ARRAY_SIZE(disp->layers); i++) disp->layers[i].plane.possible_crtcs = possible_crtcs; } -- cgit From 96e0e3e3a210ab9c4894da2250bb583dd61ab3a2 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Aug 2021 14:29:52 +0300 Subject: drm: xlnx: zynqmp_dpsub: Don't use drmm_kcalloc() for temporary data The array of formats passed to drm_universal_plane_init() doesn't need to outlive the function call, as it's copied internally. Use kcalloc() instead of drmm_kcalloc() to allocate it, and free it right after usage. While at it, move the allocation and initialization of the formats array to a separate function, to prepare for splitting the DRM plane handling to a separate file. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/xlnx/zynqmp_disp.c | 45 ++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c b/drivers/gpu/drm/xlnx/zynqmp_disp.c index e722af0e59a9..4f6c9af799e9 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_disp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c @@ -1000,6 +1000,33 @@ zynqmp_disp_layer_find_format(struct zynqmp_disp_layer *layer, return NULL; } +/** + * zynqmp_disp_layer_drm_formats - Return the DRM formats supported by the layer + * @layer: The layer + * @num_formats: Pointer to the returned number of formats + * + * Return: A newly allocated u32 array that stores all the DRM formats + * supported by the layer. The number of formats in the array is returned + * through the num_formats argument. + */ +static u32 *zynqmp_disp_layer_drm_formats(struct zynqmp_disp_layer *layer, + unsigned int *num_formats) +{ + unsigned int i; + u32 *formats; + + formats = kcalloc(layer->info->num_formats, sizeof(*formats), + GFP_KERNEL); + if (!formats) + return NULL; + + for (i = 0; i < layer->info->num_formats; ++i) + formats[i] = layer->info->formats[i].drm_fmt; + + *num_formats = layer->info->num_formats; + return formats; +} + /** * zynqmp_disp_layer_enable - Enable a layer * @layer: The layer @@ -1219,31 +1246,27 @@ static const struct drm_plane_funcs zynqmp_disp_plane_funcs = { static int zynqmp_disp_create_planes(struct zynqmp_disp *disp) { - unsigned int i, j; + unsigned int i; int ret; for (i = 0; i < ARRAY_SIZE(disp->layers); i++) { struct zynqmp_disp_layer *layer = &disp->layers[i]; enum drm_plane_type type; - u32 *drm_formats; + unsigned int num_formats; + u32 *formats; - drm_formats = drmm_kcalloc(disp->drm, sizeof(*drm_formats), - layer->info->num_formats, - GFP_KERNEL); - if (!drm_formats) + formats = zynqmp_disp_layer_drm_formats(layer, &num_formats); + if (!formats) return -ENOMEM; - for (j = 0; j < layer->info->num_formats; ++j) - drm_formats[j] = layer->info->formats[j].drm_fmt; - /* Graphics layer is primary, and video layer is overlay. */ type = zynqmp_disp_layer_is_video(layer) ? DRM_PLANE_TYPE_OVERLAY : DRM_PLANE_TYPE_PRIMARY; ret = drm_universal_plane_init(disp->drm, &layer->plane, 0, &zynqmp_disp_plane_funcs, - drm_formats, - layer->info->num_formats, + formats, num_formats, NULL, type, NULL); + kfree(formats); if (ret) return ret; -- cgit From 1682ade6630823dd186723b44991d9933503dfc3 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Aug 2021 14:29:52 +0300 Subject: drm: xlnx: zynqmp_dpsub: Move pclk from zynqmp_disp to zynqmp_dpsub The video clock is an external resource from the DPSUB point of view, not a resource internal to the display controller. Move it to the zynqmp_dpsub structure, to allow accessing it from outside the disp code. While at it, rename the fields from pclk and pclk_from_ps to vid_clk and vid_clk_from_ps, to better reflect their purpose and match the documentation. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/xlnx/zynqmp_disp.c | 36 +++++++----------------------------- drivers/gpu/drm/xlnx/zynqmp_dpsub.c | 17 +++++++++++++++++ drivers/gpu/drm/xlnx/zynqmp_dpsub.h | 4 ++++ 3 files changed, 28 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c b/drivers/gpu/drm/xlnx/zynqmp_disp.c index 4f6c9af799e9..d03066577b10 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_disp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c @@ -169,8 +169,6 @@ struct zynqmp_disp_layer { * @audio.clk: Audio clock * @audio.clk_from_ps: True of the audio clock comes from PS, false from PL * @layers: Layers (planes) - * @pclk: Pixel clock - * @pclk_from_ps: True of the video clock comes from PS, false from PL */ struct zynqmp_disp { struct device *dev; @@ -192,9 +190,6 @@ struct zynqmp_disp { } audio; struct zynqmp_disp_layer layers[ZYNQMP_DISP_NUM_LAYERS]; - - struct clk *pclk; - bool pclk_from_ps; }; /* ----------------------------------------------------------------------------- @@ -1412,7 +1407,7 @@ static void zynqmp_disp_enable(struct zynqmp_disp *disp) zynqmp_disp_avbuf_enable(disp); /* Choose clock source based on the DT clock handle. */ - zynqmp_disp_avbuf_set_clocks_sources(disp, disp->pclk_from_ps, + zynqmp_disp_avbuf_set_clocks_sources(disp, disp->dpsub->vid_clk_from_ps, disp->audio.clk_from_ps, true); zynqmp_disp_avbuf_enable_channels(disp); zynqmp_disp_avbuf_enable_audio(disp); @@ -1440,13 +1435,13 @@ static int zynqmp_disp_setup_clock(struct zynqmp_disp *disp, long diff; int ret; - ret = clk_set_rate(disp->pclk, mode_clock); + ret = clk_set_rate(disp->dpsub->vid_clk, mode_clock); if (ret) { - dev_err(disp->dev, "failed to set a pixel clock\n"); + dev_err(disp->dev, "failed to set the video clock\n"); return ret; } - rate = clk_get_rate(disp->pclk); + rate = clk_get_rate(disp->dpsub->vid_clk); diff = rate - mode_clock; if (abs(diff) > mode_clock / 20) dev_info(disp->dev, @@ -1477,9 +1472,9 @@ zynqmp_disp_crtc_atomic_enable(struct drm_crtc *crtc, zynqmp_disp_setup_clock(disp, adjusted_mode->clock * 1000); - ret = clk_prepare_enable(disp->pclk); + ret = clk_prepare_enable(disp->dpsub->vid_clk); if (ret) { - dev_err(disp->dev, "failed to enable a pixel clock\n"); + dev_err(disp->dev, "failed to enable the video clock\n"); pm_runtime_put_sync(disp->dev); return; } @@ -1519,7 +1514,7 @@ zynqmp_disp_crtc_atomic_disable(struct drm_crtc *crtc, } spin_unlock_irq(&crtc->dev->event_lock); - clk_disable_unprepare(disp->pclk); + clk_disable_unprepare(disp->dpsub->vid_clk); pm_runtime_put_sync(disp->dev); } @@ -1674,23 +1669,6 @@ int zynqmp_disp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm) if (IS_ERR(disp->audio.base)) return PTR_ERR(disp->audio.base); - /* Try the live PL video clock */ - disp->pclk = devm_clk_get(disp->dev, "dp_live_video_in_clk"); - if (!IS_ERR(disp->pclk)) - disp->pclk_from_ps = false; - else if (PTR_ERR(disp->pclk) == -EPROBE_DEFER) - return PTR_ERR(disp->pclk); - - /* If the live PL video clock is not valid, fall back to PS clock */ - if (IS_ERR_OR_NULL(disp->pclk)) { - disp->pclk = devm_clk_get(disp->dev, "dp_vtc_pixel_clk_in"); - if (IS_ERR(disp->pclk)) { - dev_err(disp->dev, "failed to init any video clock\n"); - return PTR_ERR(disp->pclk); - } - disp->pclk_from_ps = true; - } - zynqmp_disp_audio_init(disp); ret = zynqmp_disp_create_layers(disp); diff --git a/drivers/gpu/drm/xlnx/zynqmp_dpsub.c b/drivers/gpu/drm/xlnx/zynqmp_dpsub.c index 6f6e7c67d370..7d6c30a599d9 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dpsub.c +++ b/drivers/gpu/drm/xlnx/zynqmp_dpsub.c @@ -214,6 +214,23 @@ static int zynqmp_dpsub_init_clocks(struct zynqmp_dpsub *dpsub) return ret; } + /* Try the live PL video clock */ + dpsub->vid_clk = devm_clk_get(dpsub->dev, "dp_live_video_in_clk"); + if (!IS_ERR(dpsub->vid_clk)) + dpsub->vid_clk_from_ps = false; + else if (PTR_ERR(dpsub->vid_clk) == -EPROBE_DEFER) + return PTR_ERR(dpsub->vid_clk); + + /* If the live PL video clock is not valid, fall back to PS clock */ + if (IS_ERR_OR_NULL(dpsub->vid_clk)) { + dpsub->vid_clk = devm_clk_get(dpsub->dev, "dp_vtc_pixel_clk_in"); + if (IS_ERR(dpsub->vid_clk)) { + dev_err(dpsub->dev, "failed to init any video clock\n"); + return PTR_ERR(dpsub->vid_clk); + } + dpsub->vid_clk_from_ps = true; + } + return 0; } diff --git a/drivers/gpu/drm/xlnx/zynqmp_dpsub.h b/drivers/gpu/drm/xlnx/zynqmp_dpsub.h index 66820bbc4507..bcb119bb97e1 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dpsub.h +++ b/drivers/gpu/drm/xlnx/zynqmp_dpsub.h @@ -33,6 +33,8 @@ enum zynqmp_dpsub_format { * @drm: The DRM/KMS device * @dev: The physical device * @apb_clk: The APB clock + * @vid_clk: Video clock + * @vid_clk_from_ps: True of the video clock comes from PS, false from PL * @encoder: The dummy DRM encoder * @bridge: The DP encoder bridge * @disp: The display controller @@ -44,6 +46,8 @@ struct zynqmp_dpsub { struct device *dev; struct clk *apb_clk; + struct clk *vid_clk; + bool vid_clk_from_ps; struct drm_encoder encoder; struct drm_bridge *bridge; -- cgit From c979296ef60cdd37b4354c9507a624ae3c5e4bd6 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Aug 2021 14:29:52 +0300 Subject: drm: xlnx: zynqmp_dpsub: Move audio clk from zynqmp_disp to zynqmp_dpsub The audio clock is an external resource from the DPSUB point of view, not a resource internal to the display controller. Move it to the zynqmp_dpsub structure, to allow accessing it from outside the disp code. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/xlnx/zynqmp_disp.c | 54 ++----------------------------------- drivers/gpu/drm/xlnx/zynqmp_disp.h | 2 -- drivers/gpu/drm/xlnx/zynqmp_dp.c | 8 +++--- drivers/gpu/drm/xlnx/zynqmp_dpsub.c | 54 +++++++++++++++++++++++++++++++++++-- drivers/gpu/drm/xlnx/zynqmp_dpsub.h | 7 +++++ 5 files changed, 65 insertions(+), 60 deletions(-) diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c b/drivers/gpu/drm/xlnx/zynqmp_disp.c index d03066577b10..a6e7ccf60525 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_disp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c @@ -166,8 +166,6 @@ struct zynqmp_disp_layer { * @blend.base: Register I/O base address for the blender * @avbuf.base: Register I/O base address for the audio/video buffer manager * @audio.base: Registers I/O base address for the audio mixer - * @audio.clk: Audio clock - * @audio.clk_from_ps: True of the audio clock comes from PS, false from PL * @layers: Layers (planes) */ struct zynqmp_disp { @@ -185,8 +183,6 @@ struct zynqmp_disp { } avbuf; struct { void __iomem *base; - struct clk *clk; - bool clk_from_ps; } audio; struct zynqmp_disp_layer layers[ZYNQMP_DISP_NUM_LAYERS]; @@ -892,25 +888,6 @@ static void zynqmp_disp_audio_disable(struct zynqmp_disp *disp) ZYNQMP_DISP_AUD_SOFT_RESET_AUD_SRST); } -static void zynqmp_disp_audio_init(struct zynqmp_disp *disp) -{ - /* Try the live PL audio clock. */ - disp->audio.clk = devm_clk_get(disp->dev, "dp_live_audio_aclk"); - if (!IS_ERR(disp->audio.clk)) { - disp->audio.clk_from_ps = false; - return; - } - - /* If the live PL audio clock is not valid, fall back to PS clock. */ - disp->audio.clk = devm_clk_get(disp->dev, "dp_aud_clk"); - if (!IS_ERR(disp->audio.clk)) { - disp->audio.clk_from_ps = true; - return; - } - - dev_err(disp->dev, "audio disabled due to missing clock\n"); -} - /* ----------------------------------------------------------------------------- * ZynqMP Display external functions for zynqmp_dp */ @@ -929,32 +906,6 @@ void zynqmp_disp_handle_vblank(struct zynqmp_disp *disp) drm_crtc_handle_vblank(crtc); } -/** - * zynqmp_disp_audio_enabled - If the audio is enabled - * @disp: Display controller - * - * Return if the audio is enabled depending on the audio clock. - * - * Return: true if audio is enabled, or false. - */ -bool zynqmp_disp_audio_enabled(struct zynqmp_disp *disp) -{ - return !!disp->audio.clk; -} - -/** - * zynqmp_disp_get_audio_clk_rate - Get the current audio clock rate - * @disp: Display controller - * - * Return: the current audio clock rate. - */ -unsigned int zynqmp_disp_get_audio_clk_rate(struct zynqmp_disp *disp) -{ - if (zynqmp_disp_audio_enabled(disp)) - return 0; - return clk_get_rate(disp->audio.clk); -} - /** * zynqmp_disp_get_crtc_mask - Return the CRTC bit mask * @disp: Display controller @@ -1408,7 +1359,8 @@ static void zynqmp_disp_enable(struct zynqmp_disp *disp) zynqmp_disp_avbuf_enable(disp); /* Choose clock source based on the DT clock handle. */ zynqmp_disp_avbuf_set_clocks_sources(disp, disp->dpsub->vid_clk_from_ps, - disp->audio.clk_from_ps, true); + disp->dpsub->aud_clk_from_ps, + true); zynqmp_disp_avbuf_enable_channels(disp); zynqmp_disp_avbuf_enable_audio(disp); @@ -1669,8 +1621,6 @@ int zynqmp_disp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm) if (IS_ERR(disp->audio.base)) return PTR_ERR(disp->audio.base); - zynqmp_disp_audio_init(disp); - ret = zynqmp_disp_create_layers(disp); if (ret) return ret; diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.h b/drivers/gpu/drm/xlnx/zynqmp_disp.h index f402901afb23..1b7f90a81857 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_disp.h +++ b/drivers/gpu/drm/xlnx/zynqmp_disp.h @@ -31,8 +31,6 @@ struct zynqmp_disp; struct zynqmp_dpsub; void zynqmp_disp_handle_vblank(struct zynqmp_disp *disp); -bool zynqmp_disp_audio_enabled(struct zynqmp_disp *disp); -unsigned int zynqmp_disp_get_audio_clk_rate(struct zynqmp_disp *disp); uint32_t zynqmp_disp_get_crtc_mask(struct zynqmp_disp *disp); int zynqmp_disp_drm_init(struct zynqmp_dpsub *dpsub); diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c index 33fd69ed7550..3e4d164d40fe 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c @@ -1252,7 +1252,7 @@ static void zynqmp_dp_encoder_mode_set_stream(struct zynqmp_dp *dp, reg = drm_dp_bw_code_to_link_rate(dp->mode.bw_code); zynqmp_dp_write(dp, ZYNQMP_DP_MAIN_STREAM_N_VID, reg); zynqmp_dp_write(dp, ZYNQMP_DP_MAIN_STREAM_M_VID, mode->clock); - rate = zynqmp_disp_get_audio_clk_rate(dp->dpsub->disp); + rate = zynqmp_dpsub_get_audio_clk_rate(dp->dpsub); if (rate) { dev_dbg(dp->dev, "Audio rate: %d\n", rate / 512); zynqmp_dp_write(dp, ZYNQMP_DP_TX_N_AUD, reg); @@ -1261,7 +1261,7 @@ static void zynqmp_dp_encoder_mode_set_stream(struct zynqmp_dp *dp, } /* Only 2 channel audio is supported now */ - if (zynqmp_disp_audio_enabled(dp->dpsub->disp)) + if (zynqmp_dpsub_audio_enabled(dp->dpsub)) zynqmp_dp_write(dp, ZYNQMP_DP_TX_AUDIO_CHANNELS, 1); zynqmp_dp_write(dp, ZYNQMP_DP_USER_PIX_WIDTH, 1); @@ -1372,7 +1372,7 @@ static void zynqmp_dp_bridge_atomic_enable(struct drm_bridge *bridge, /* Enable the encoder */ dp->enabled = true; zynqmp_dp_update_misc(dp); - if (zynqmp_disp_audio_enabled(dp->dpsub->disp)) + if (zynqmp_dpsub_audio_enabled(dp->dpsub)) zynqmp_dp_write(dp, ZYNQMP_DP_TX_AUDIO_CONTROL, 1); zynqmp_dp_write(dp, ZYNQMP_DP_TX_PHY_POWER_DOWN, 0); if (dp->status == connector_status_connected) { @@ -1406,7 +1406,7 @@ static void zynqmp_dp_bridge_atomic_disable(struct drm_bridge *bridge, drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, DP_SET_POWER_D3); zynqmp_dp_write(dp, ZYNQMP_DP_TX_PHY_POWER_DOWN, ZYNQMP_DP_TX_PHY_POWER_DOWN_ALL); - if (zynqmp_disp_audio_enabled(dp->dpsub->disp)) + if (zynqmp_dpsub_audio_enabled(dp->dpsub)) zynqmp_dp_write(dp, ZYNQMP_DP_TX_AUDIO_CONTROL, 0); pm_runtime_put_sync(dp->dev); } diff --git a/drivers/gpu/drm/xlnx/zynqmp_dpsub.c b/drivers/gpu/drm/xlnx/zynqmp_dpsub.c index 7d6c30a599d9..6d60efbe1f39 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dpsub.c +++ b/drivers/gpu/drm/xlnx/zynqmp_dpsub.c @@ -196,6 +196,36 @@ static const struct dev_pm_ops zynqmp_dpsub_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(zynqmp_dpsub_suspend, zynqmp_dpsub_resume) }; +/* ----------------------------------------------------------------------------- + * DPSUB Configuration + */ + +/** + * zynqmp_dpsub_audio_enabled - If the audio is enabled + * @dpsub: DisplayPort subsystem + * + * Return if the audio is enabled depending on the audio clock. + * + * Return: true if audio is enabled, or false. + */ +bool zynqmp_dpsub_audio_enabled(struct zynqmp_dpsub *dpsub) +{ + return !!dpsub->aud_clk; +} + +/** + * zynqmp_dpsub_get_audio_clk_rate - Get the current audio clock rate + * @dpsub: DisplayPort subsystem + * + * Return: the current audio clock rate. + */ +unsigned int zynqmp_dpsub_get_audio_clk_rate(struct zynqmp_dpsub *dpsub) +{ + if (zynqmp_dpsub_audio_enabled(dpsub)) + return 0; + return clk_get_rate(dpsub->aud_clk); +} + /* ----------------------------------------------------------------------------- * Probe & Remove */ @@ -214,14 +244,16 @@ static int zynqmp_dpsub_init_clocks(struct zynqmp_dpsub *dpsub) return ret; } - /* Try the live PL video clock */ + /* + * Try the live PL video clock, and fall back to the PS clock if the + * live PL video clock isn't valid. + */ dpsub->vid_clk = devm_clk_get(dpsub->dev, "dp_live_video_in_clk"); if (!IS_ERR(dpsub->vid_clk)) dpsub->vid_clk_from_ps = false; else if (PTR_ERR(dpsub->vid_clk) == -EPROBE_DEFER) return PTR_ERR(dpsub->vid_clk); - /* If the live PL video clock is not valid, fall back to PS clock */ if (IS_ERR_OR_NULL(dpsub->vid_clk)) { dpsub->vid_clk = devm_clk_get(dpsub->dev, "dp_vtc_pixel_clk_in"); if (IS_ERR(dpsub->vid_clk)) { @@ -231,6 +263,24 @@ static int zynqmp_dpsub_init_clocks(struct zynqmp_dpsub *dpsub) dpsub->vid_clk_from_ps = true; } + /* + * Try the live PL audio clock, and fall back to the PS clock if the + * live PL audio clock isn't valid. Missing audio clock disables audio + * but isn't an error. + */ + dpsub->aud_clk = devm_clk_get(dpsub->dev, "dp_live_audio_aclk"); + if (!IS_ERR(dpsub->aud_clk)) { + dpsub->aud_clk_from_ps = false; + return 0; + } + + dpsub->aud_clk = devm_clk_get(dpsub->dev, "dp_aud_clk"); + if (!IS_ERR(dpsub->aud_clk)) { + dpsub->aud_clk_from_ps = true; + return 0; + } + + dev_info(dpsub->dev, "audio disabled due to missing clock\n"); return 0; } diff --git a/drivers/gpu/drm/xlnx/zynqmp_dpsub.h b/drivers/gpu/drm/xlnx/zynqmp_dpsub.h index bcb119bb97e1..5bd42e192e17 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dpsub.h +++ b/drivers/gpu/drm/xlnx/zynqmp_dpsub.h @@ -35,6 +35,8 @@ enum zynqmp_dpsub_format { * @apb_clk: The APB clock * @vid_clk: Video clock * @vid_clk_from_ps: True of the video clock comes from PS, false from PL + * @aud_clk: Audio clock + * @aud_clk_from_ps: True of the audio clock comes from PS, false from PL * @encoder: The dummy DRM encoder * @bridge: The DP encoder bridge * @disp: The display controller @@ -48,6 +50,8 @@ struct zynqmp_dpsub { struct clk *apb_clk; struct clk *vid_clk; bool vid_clk_from_ps; + struct clk *aud_clk; + bool aud_clk_from_ps; struct drm_encoder encoder; struct drm_bridge *bridge; @@ -63,4 +67,7 @@ static inline struct zynqmp_dpsub *to_zynqmp_dpsub(struct drm_device *drm) return container_of(drm, struct zynqmp_dpsub, drm); } +bool zynqmp_dpsub_audio_enabled(struct zynqmp_dpsub *dpsub); +unsigned int zynqmp_dpsub_get_audio_clk_rate(struct zynqmp_dpsub *dpsub); + #endif /* _ZYNQMP_DPSUB_H_ */ -- cgit From 68dcffea19dd3cb4528886b315f84b376f0c8f5d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Aug 2021 14:29:52 +0300 Subject: drm: xlnx: zynqmp_dpsub: Move CRTC to zynqmp_dpsub structure Decouple the zynqmp_disp, which handles the hardware configuration, from the DRM CRTC by moving the CRTC to the zynqmp_dpsub structure. The CRTC handling code will be moved to a separate file in a subsequent step. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/xlnx/zynqmp_disp.c | 20 +++++++++----------- drivers/gpu/drm/xlnx/zynqmp_dpsub.h | 3 +++ 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c b/drivers/gpu/drm/xlnx/zynqmp_disp.c index a6e7ccf60525..85d5475a6ecf 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_disp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c @@ -162,7 +162,6 @@ struct zynqmp_disp_layer { * @dev: Device structure * @drm: DRM core * @dpsub: Display subsystem - * @crtc: DRM CRTC * @blend.base: Register I/O base address for the blender * @avbuf.base: Register I/O base address for the audio/video buffer manager * @audio.base: Registers I/O base address for the audio mixer @@ -173,8 +172,6 @@ struct zynqmp_disp { struct drm_device *drm; struct zynqmp_dpsub *dpsub; - struct drm_crtc crtc; - struct { void __iomem *base; } blend; @@ -901,7 +898,7 @@ static void zynqmp_disp_audio_disable(struct zynqmp_disp *disp) */ void zynqmp_disp_handle_vblank(struct zynqmp_disp *disp) { - struct drm_crtc *crtc = &disp->crtc; + struct drm_crtc *crtc = &disp->dpsub->crtc; drm_crtc_handle_vblank(crtc); } @@ -914,7 +911,7 @@ void zynqmp_disp_handle_vblank(struct zynqmp_disp *disp) */ uint32_t zynqmp_disp_get_crtc_mask(struct zynqmp_disp *disp) { - return drm_crtc_mask(&disp->crtc); + return drm_crtc_mask(&disp->dpsub->crtc); } /* ----------------------------------------------------------------------------- @@ -1409,7 +1406,7 @@ static int zynqmp_disp_setup_clock(struct zynqmp_disp *disp, static inline struct zynqmp_disp *crtc_to_disp(struct drm_crtc *crtc) { - return container_of(crtc, struct zynqmp_disp, crtc); + return container_of(crtc, struct zynqmp_dpsub, crtc)->disp; } static void @@ -1457,7 +1454,7 @@ zynqmp_disp_crtc_atomic_disable(struct drm_crtc *crtc, zynqmp_disp_disable(disp); - drm_crtc_vblank_off(&disp->crtc); + drm_crtc_vblank_off(crtc); spin_lock_irq(&crtc->dev->event_lock); if (crtc->state->event) { @@ -1542,24 +1539,25 @@ static const struct drm_crtc_funcs zynqmp_disp_crtc_funcs = { static int zynqmp_disp_create_crtc(struct zynqmp_disp *disp) { struct drm_plane *plane = &disp->layers[ZYNQMP_DISP_LAYER_GFX].plane; + struct drm_crtc *crtc = &disp->dpsub->crtc; int ret; - ret = drm_crtc_init_with_planes(disp->drm, &disp->crtc, plane, + ret = drm_crtc_init_with_planes(disp->drm, crtc, plane, NULL, &zynqmp_disp_crtc_funcs, NULL); if (ret < 0) return ret; - drm_crtc_helper_add(&disp->crtc, &zynqmp_disp_crtc_helper_funcs); + drm_crtc_helper_add(crtc, &zynqmp_disp_crtc_helper_funcs); /* Start with vertical blanking interrupt reporting disabled. */ - drm_crtc_vblank_off(&disp->crtc); + drm_crtc_vblank_off(crtc); return 0; } static void zynqmp_disp_map_crtc_to_plane(struct zynqmp_disp *disp) { - u32 possible_crtcs = drm_crtc_mask(&disp->crtc); + u32 possible_crtcs = drm_crtc_mask(&disp->dpsub->crtc); unsigned int i; for (i = 0; i < ARRAY_SIZE(disp->layers); i++) diff --git a/drivers/gpu/drm/xlnx/zynqmp_dpsub.h b/drivers/gpu/drm/xlnx/zynqmp_dpsub.h index 5bd42e192e17..4ee0dc69ebee 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dpsub.h +++ b/drivers/gpu/drm/xlnx/zynqmp_dpsub.h @@ -12,6 +12,7 @@ #ifndef _ZYNQMP_DPSUB_H_ #define _ZYNQMP_DPSUB_H_ +#include #include struct clk; @@ -37,6 +38,7 @@ enum zynqmp_dpsub_format { * @vid_clk_from_ps: True of the video clock comes from PS, false from PL * @aud_clk: Audio clock * @aud_clk_from_ps: True of the audio clock comes from PS, false from PL + * @crtc: The DRM CRTC * @encoder: The dummy DRM encoder * @bridge: The DP encoder bridge * @disp: The display controller @@ -53,6 +55,7 @@ struct zynqmp_dpsub { struct clk *aud_clk; bool aud_clk_from_ps; + struct drm_crtc crtc; struct drm_encoder encoder; struct drm_bridge *bridge; -- cgit From 88beb8ccc03223dd2849f8c37cb8afd2e49a0239 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Aug 2021 14:29:52 +0300 Subject: drm: xlnx: zynqmp_dpsub: Move planes to zynqmp_dpsub structure Decouple the zynqmp_disp, which handles the hardware configuration, from the DRM planes by moving the planes to the zynqmp_dpsub structure. The planes handling code will be moved to a separate file in a subsequent step. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/xlnx/zynqmp_disp.c | 32 +++++++++++++------------------- drivers/gpu/drm/xlnx/zynqmp_dpsub.h | 5 +++++ 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c b/drivers/gpu/drm/xlnx/zynqmp_disp.c index 85d5475a6ecf..4d68a73a5990 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_disp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c @@ -72,7 +72,6 @@ #define ZYNQMP_DISP_AV_BUF_NUM_VID_GFX_BUFFERS 4 #define ZYNQMP_DISP_AV_BUF_NUM_BUFFERS 6 -#define ZYNQMP_DISP_NUM_LAYERS 2 #define ZYNQMP_DISP_MAX_NUM_SUB_PLANES 3 /** @@ -134,8 +133,7 @@ struct zynqmp_disp_layer_info { }; /** - * struct zynqmp_disp_layer - Display layer (DRM plane) - * @plane: DRM plane + * struct zynqmp_disp_layer - Display layer * @id: Layer ID * @disp: Back pointer to struct zynqmp_disp * @info: Static layer information @@ -145,7 +143,6 @@ struct zynqmp_disp_layer_info { * @mode: Current operation mode */ struct zynqmp_disp_layer { - struct drm_plane plane; enum zynqmp_disp_layer_id id; struct zynqmp_disp *disp; const struct zynqmp_disp_layer_info *info; @@ -182,7 +179,7 @@ struct zynqmp_disp { void __iomem *base; } audio; - struct zynqmp_disp_layer layers[ZYNQMP_DISP_NUM_LAYERS]; + struct zynqmp_disp_layer layers[ZYNQMP_DPSUB_NUM_LAYERS]; }; /* ----------------------------------------------------------------------------- @@ -1091,11 +1088,6 @@ static int zynqmp_disp_layer_update(struct zynqmp_disp_layer *layer, return 0; } -static inline struct zynqmp_disp_layer *plane_to_layer(struct drm_plane *plane) -{ - return container_of(plane, struct zynqmp_disp_layer, plane); -} - static int zynqmp_disp_plane_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state) @@ -1124,7 +1116,8 @@ zynqmp_disp_plane_atomic_disable(struct drm_plane *plane, { struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane); - struct zynqmp_disp_layer *layer = plane_to_layer(plane); + struct zynqmp_dpsub *dpsub = to_zynqmp_dpsub(plane->dev); + struct zynqmp_disp_layer *layer = &dpsub->disp->layers[plane->index]; if (!old_state->fb) return; @@ -1142,7 +1135,8 @@ zynqmp_disp_plane_atomic_update(struct drm_plane *plane, { struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane); struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane); - struct zynqmp_disp_layer *layer = plane_to_layer(plane); + struct zynqmp_dpsub *dpsub = to_zynqmp_dpsub(plane->dev); + struct zynqmp_disp_layer *layer = &dpsub->disp->layers[plane->index]; bool format_changed = false; if (!old_state->fb || @@ -1194,6 +1188,7 @@ static int zynqmp_disp_create_planes(struct zynqmp_disp *disp) for (i = 0; i < ARRAY_SIZE(disp->layers); i++) { struct zynqmp_disp_layer *layer = &disp->layers[i]; + struct drm_plane *plane = &disp->dpsub->planes[i]; enum drm_plane_type type; unsigned int num_formats; u32 *formats; @@ -1205,7 +1200,7 @@ static int zynqmp_disp_create_planes(struct zynqmp_disp *disp) /* Graphics layer is primary, and video layer is overlay. */ type = zynqmp_disp_layer_is_video(layer) ? DRM_PLANE_TYPE_OVERLAY : DRM_PLANE_TYPE_PRIMARY; - ret = drm_universal_plane_init(disp->drm, &layer->plane, 0, + ret = drm_universal_plane_init(disp->drm, plane, 0, &zynqmp_disp_plane_funcs, formats, num_formats, NULL, type, NULL); @@ -1213,12 +1208,11 @@ static int zynqmp_disp_create_planes(struct zynqmp_disp *disp) if (ret) return ret; - drm_plane_helper_add(&layer->plane, - &zynqmp_disp_plane_helper_funcs); + drm_plane_helper_add(plane, &zynqmp_disp_plane_helper_funcs); - drm_plane_create_zpos_immutable_property(&layer->plane, i); + drm_plane_create_zpos_immutable_property(plane, i); if (zynqmp_disp_layer_is_gfx(layer)) - drm_plane_create_alpha_property(&layer->plane); + drm_plane_create_alpha_property(plane); } return 0; @@ -1538,7 +1532,7 @@ static const struct drm_crtc_funcs zynqmp_disp_crtc_funcs = { static int zynqmp_disp_create_crtc(struct zynqmp_disp *disp) { - struct drm_plane *plane = &disp->layers[ZYNQMP_DISP_LAYER_GFX].plane; + struct drm_plane *plane = &disp->dpsub->planes[ZYNQMP_DISP_LAYER_GFX]; struct drm_crtc *crtc = &disp->dpsub->crtc; int ret; @@ -1561,7 +1555,7 @@ static void zynqmp_disp_map_crtc_to_plane(struct zynqmp_disp *disp) unsigned int i; for (i = 0; i < ARRAY_SIZE(disp->layers); i++) - disp->layers[i].plane.possible_crtcs = possible_crtcs; + disp->dpsub->planes[i].possible_crtcs = possible_crtcs; } /* ----------------------------------------------------------------------------- diff --git a/drivers/gpu/drm/xlnx/zynqmp_dpsub.h b/drivers/gpu/drm/xlnx/zynqmp_dpsub.h index 4ee0dc69ebee..2a955895404f 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dpsub.h +++ b/drivers/gpu/drm/xlnx/zynqmp_dpsub.h @@ -14,6 +14,7 @@ #include #include +#include struct clk; struct device; @@ -22,6 +23,8 @@ struct drm_device; struct zynqmp_disp; struct zynqmp_dp; +#define ZYNQMP_DPSUB_NUM_LAYERS 2 + enum zynqmp_dpsub_format { ZYNQMP_DPSUB_FORMAT_RGB, ZYNQMP_DPSUB_FORMAT_YCRCB444, @@ -38,6 +41,7 @@ enum zynqmp_dpsub_format { * @vid_clk_from_ps: True of the video clock comes from PS, false from PL * @aud_clk: Audio clock * @aud_clk_from_ps: True of the audio clock comes from PS, false from PL + * @planes: The DRM planes * @crtc: The DRM CRTC * @encoder: The dummy DRM encoder * @bridge: The DP encoder bridge @@ -55,6 +59,7 @@ struct zynqmp_dpsub { struct clk *aud_clk; bool aud_clk_from_ps; + struct drm_plane planes[ZYNQMP_DPSUB_NUM_LAYERS]; struct drm_crtc crtc; struct drm_encoder encoder; struct drm_bridge *bridge; -- cgit From 76c8eeb72dbbe31770c645e4039846f6f4019475 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 29 Sep 2022 00:25:56 +0300 Subject: drm: xlnx: zynqmp_dpsub: Move DRM/KMS initialization to separate file Start preparation for using the DPSUB as a standalone DisplayPort encoder without a display controller by moving the DRM/KMS initialization to a new zynqmp_kms.c file. No functional change intended. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/xlnx/Makefile | 2 +- drivers/gpu/drm/xlnx/zynqmp_dpsub.c | 43 ++--------------------- drivers/gpu/drm/xlnx/zynqmp_kms.c | 70 +++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/xlnx/zynqmp_kms.h | 19 ++++++++++ 4 files changed, 93 insertions(+), 41 deletions(-) create mode 100644 drivers/gpu/drm/xlnx/zynqmp_kms.c create mode 100644 drivers/gpu/drm/xlnx/zynqmp_kms.h diff --git a/drivers/gpu/drm/xlnx/Makefile b/drivers/gpu/drm/xlnx/Makefile index 51c24b72217b..ea1422a39502 100644 --- a/drivers/gpu/drm/xlnx/Makefile +++ b/drivers/gpu/drm/xlnx/Makefile @@ -1,2 +1,2 @@ -zynqmp-dpsub-y := zynqmp_disp.o zynqmp_dpsub.o zynqmp_dp.o +zynqmp-dpsub-y := zynqmp_disp.o zynqmp_dpsub.o zynqmp_dp.o zynqmp_kms.o obj-$(CONFIG_DRM_ZYNQMP_DPSUB) += zynqmp-dpsub.o diff --git a/drivers/gpu/drm/xlnx/zynqmp_dpsub.c b/drivers/gpu/drm/xlnx/zynqmp_dpsub.c index 6d60efbe1f39..5d61f6c7aee5 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dpsub.c +++ b/drivers/gpu/drm/xlnx/zynqmp_dpsub.c @@ -17,9 +17,7 @@ #include #include -#include #include -#include #include #include #include @@ -30,12 +28,12 @@ #include #include #include -#include #include #include "zynqmp_disp.h" #include "zynqmp_dp.h" #include "zynqmp_dpsub.h" +#include "zynqmp_kms.h" /* ----------------------------------------------------------------------------- * Dumb Buffer & Framebuffer Allocation @@ -98,8 +96,6 @@ static const struct drm_driver zynqmp_dpsub_drm_driver = { static int zynqmp_dpsub_drm_init(struct zynqmp_dpsub *dpsub) { - struct drm_encoder *encoder = &dpsub->encoder; - struct drm_connector *connector; struct drm_device *drm = &dpsub->drm; int ret; @@ -120,42 +116,9 @@ static int zynqmp_dpsub_drm_init(struct zynqmp_dpsub *dpsub) drm_kms_helper_poll_init(drm); - /* - * Initialize the DISP and DP components. This will creates planes, - * CRTC, and a bridge for the DP encoder. - */ - ret = zynqmp_disp_drm_init(dpsub); - if (ret) - goto err_poll_fini; - - ret = zynqmp_dp_drm_init(dpsub); - if (ret) - goto err_poll_fini; - - /* Create the encoder and attach the bridge. */ - encoder->possible_crtcs |= zynqmp_disp_get_crtc_mask(dpsub->disp); - drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_NONE); - - ret = drm_bridge_attach(encoder, dpsub->bridge, NULL, - DRM_BRIDGE_ATTACH_NO_CONNECTOR); - if (ret) { - dev_err(dpsub->dev, "failed to attach bridge to encoder\n"); - goto err_poll_fini; - } - - /* Create the connector for the chain of bridges. */ - connector = drm_bridge_connector_init(drm, encoder); - if (IS_ERR(connector)) { - dev_err(dpsub->dev, "failed to created connector\n"); - ret = PTR_ERR(connector); - goto err_poll_fini; - } - - ret = drm_connector_attach_encoder(connector, encoder); - if (ret < 0) { - dev_err(dpsub->dev, "failed to attach connector to encoder\n"); + ret = zynqmp_dpsub_kms_init(dpsub); + if (ret < 0) goto err_poll_fini; - } /* Reset all components and register the DRM device. */ drm_mode_config_reset(drm); diff --git a/drivers/gpu/drm/xlnx/zynqmp_kms.c b/drivers/gpu/drm/xlnx/zynqmp_kms.c new file mode 100644 index 000000000000..e4e7f8fd96d2 --- /dev/null +++ b/drivers/gpu/drm/xlnx/zynqmp_kms.c @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ZynqMP DisplayPort Subsystem - KMS API + * + * Copyright (C) 2017 - 2021 Xilinx, Inc. + * + * Authors: + * - Hyun Woo Kwon + * - Laurent Pinchart + */ + +#include +#include +#include +#include +#include + +#include "zynqmp_disp.h" +#include "zynqmp_dp.h" +#include "zynqmp_dpsub.h" +#include "zynqmp_kms.h" + +/* ----------------------------------------------------------------------------- + * Initialization + */ + +int zynqmp_dpsub_kms_init(struct zynqmp_dpsub *dpsub) +{ + struct drm_encoder *encoder = &dpsub->encoder; + struct drm_connector *connector; + int ret; + + /* + * Initialize the DISP and DP components. This will creates planes, + * CRTC, and a bridge for the DP encoder. + */ + ret = zynqmp_disp_drm_init(dpsub); + if (ret) + return ret; + + ret = zynqmp_dp_drm_init(dpsub); + if (ret) + return ret; + + /* Create the encoder and attach the bridge. */ + encoder->possible_crtcs |= zynqmp_disp_get_crtc_mask(dpsub->disp); + drm_simple_encoder_init(&dpsub->drm, encoder, DRM_MODE_ENCODER_NONE); + + ret = drm_bridge_attach(encoder, dpsub->bridge, NULL, + DRM_BRIDGE_ATTACH_NO_CONNECTOR); + if (ret) { + dev_err(dpsub->dev, "failed to attach bridge to encoder\n"); + return ret; + } + + /* Create the connector for the chain of bridges. */ + connector = drm_bridge_connector_init(&dpsub->drm, encoder); + if (IS_ERR(connector)) { + dev_err(dpsub->dev, "failed to created connector\n"); + return PTR_ERR(connector); + } + + ret = drm_connector_attach_encoder(connector, encoder); + if (ret < 0) { + dev_err(dpsub->dev, "failed to attach connector to encoder\n"); + return ret; + } + + return 0; +} diff --git a/drivers/gpu/drm/xlnx/zynqmp_kms.h b/drivers/gpu/drm/xlnx/zynqmp_kms.h new file mode 100644 index 000000000000..a6729d9d82cc --- /dev/null +++ b/drivers/gpu/drm/xlnx/zynqmp_kms.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * ZynqMP DisplayPort Subsystem - KMS API + * + * Copyright (C) 2017 - 2021 Xilinx, Inc. + * + * Authors: + * - Hyun Woo Kwon + * - Laurent Pinchart + */ + +#ifndef _ZYNQMP_KMS_H_ +#define _ZYNQMP_KMS_H_ + +struct zynqmp_dpsub; + +int zynqmp_dpsub_kms_init(struct zynqmp_dpsub *dpsub); + +#endif /* _ZYNQMP_KMS_H_ */ -- cgit From 83a956d3c316ca63cc4cc931afce474f9e0199a1 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Aug 2021 14:29:52 +0300 Subject: drm: xlnx: zynqmp_dpsub: Move CRTC handling to zynqmp_kms.c Decouple the CRTC handling from the display controller programming by moving the corresponding code from zynqmp_disp.c to zynqmp_kms.c. This prepares for using the DPSUB with a live video input, without creating a DRM CRTC in the DPSUB driver. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/xlnx/zynqmp_disp.c | 251 +++---------------------------------- drivers/gpu/drm/xlnx/zynqmp_disp.h | 21 +++- drivers/gpu/drm/xlnx/zynqmp_dp.c | 3 +- drivers/gpu/drm/xlnx/zynqmp_kms.c | 190 +++++++++++++++++++++++++++- drivers/gpu/drm/xlnx/zynqmp_kms.h | 2 + 5 files changed, 232 insertions(+), 235 deletions(-) diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c b/drivers/gpu/drm/xlnx/zynqmp_disp.c index 4d68a73a5990..c7d95f3d2a84 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_disp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c @@ -11,27 +11,21 @@ #include #include -#include #include -#include #include #include #include #include #include #include -#include #include -#include #include #include #include #include #include #include -#include -#include #include "zynqmp_disp.h" #include "zynqmp_disp_regs.h" @@ -88,16 +82,6 @@ struct zynqmp_disp_format { const u32 *sf; }; -/** - * enum zynqmp_disp_layer_id - Layer identifier - * @ZYNQMP_DISP_LAYER_VID: Video layer - * @ZYNQMP_DISP_LAYER_GFX: Graphics layer - */ -enum zynqmp_disp_layer_id { - ZYNQMP_DISP_LAYER_VID, - ZYNQMP_DISP_LAYER_GFX -}; - /** * enum zynqmp_disp_layer_mode - Layer mode * @ZYNQMP_DISP_LAYER_NONLIVE: non-live (memory) mode @@ -143,7 +127,7 @@ struct zynqmp_disp_layer_info { * @mode: Current operation mode */ struct zynqmp_disp_layer { - enum zynqmp_disp_layer_id id; + enum zynqmp_dpsub_layer_id id; struct zynqmp_disp *disp; const struct zynqmp_disp_layer_info *info; @@ -398,12 +382,12 @@ static void zynqmp_disp_avbuf_write(struct zynqmp_disp *disp, int reg, u32 val) static bool zynqmp_disp_layer_is_gfx(const struct zynqmp_disp_layer *layer) { - return layer->id == ZYNQMP_DISP_LAYER_GFX; + return layer->id == ZYNQMP_DPSUB_LAYER_GFX; } static bool zynqmp_disp_layer_is_video(const struct zynqmp_disp_layer *layer) { - return layer->id == ZYNQMP_DISP_LAYER_VID; + return layer->id == ZYNQMP_DPSUB_LAYER_VID; } /** @@ -882,35 +866,6 @@ static void zynqmp_disp_audio_disable(struct zynqmp_disp *disp) ZYNQMP_DISP_AUD_SOFT_RESET_AUD_SRST); } -/* ----------------------------------------------------------------------------- - * ZynqMP Display external functions for zynqmp_dp - */ - -/** - * zynqmp_disp_handle_vblank - Handle the vblank event - * @disp: Display controller - * - * This function handles the vblank interrupt, and sends an event to - * CRTC object. This will be called by the DP vblank interrupt handler. - */ -void zynqmp_disp_handle_vblank(struct zynqmp_disp *disp) -{ - struct drm_crtc *crtc = &disp->dpsub->crtc; - - drm_crtc_handle_vblank(crtc); -} - -/** - * zynqmp_disp_get_crtc_mask - Return the CRTC bit mask - * @disp: Display controller - * - * Return: the crtc mask of the zyqnmp_disp CRTC. - */ -uint32_t zynqmp_disp_get_crtc_mask(struct zynqmp_disp *disp) -{ - return drm_crtc_mask(&disp->dpsub->crtc); -} - /* ----------------------------------------------------------------------------- * ZynqMP Display Layer & DRM Plane */ @@ -1110,7 +1065,7 @@ zynqmp_disp_plane_atomic_check(struct drm_plane *plane, false, false); } -static void +void zynqmp_disp_plane_atomic_disable(struct drm_plane *plane, struct drm_atomic_state *state) { @@ -1300,12 +1255,12 @@ static int zynqmp_disp_layer_request_dma(struct zynqmp_disp *disp, static int zynqmp_disp_create_layers(struct zynqmp_disp *disp) { static const struct zynqmp_disp_layer_info layer_info[] = { - [ZYNQMP_DISP_LAYER_VID] = { + [ZYNQMP_DPSUB_LAYER_VID] = { .formats = avbuf_vid_fmts, .num_formats = ARRAY_SIZE(avbuf_vid_fmts), .num_channels = 3, }, - [ZYNQMP_DISP_LAYER_GFX] = { + [ZYNQMP_DPSUB_LAYER_GFX] = { .formats = avbuf_gfx_fmts, .num_formats = ARRAY_SIZE(avbuf_gfx_fmts), .num_channels = 1, @@ -1335,14 +1290,14 @@ err: } /* ----------------------------------------------------------------------------- - * ZynqMP Display & DRM CRTC + * ZynqMP Display */ /** * zynqmp_disp_enable - Enable the display controller * @disp: Display controller */ -static void zynqmp_disp_enable(struct zynqmp_disp *disp) +void zynqmp_disp_enable(struct zynqmp_disp *disp) { zynqmp_disp_blend_set_output_format(disp, ZYNQMP_DPSUB_FORMAT_RGB); zynqmp_disp_blend_set_bg_color(disp, 0, 0, 0); @@ -1362,7 +1317,7 @@ static void zynqmp_disp_enable(struct zynqmp_disp *disp) * zynqmp_disp_disable - Disable the display controller * @disp: Display controller */ -static void zynqmp_disp_disable(struct zynqmp_disp *disp) +void zynqmp_disp_disable(struct zynqmp_disp *disp) { zynqmp_disp_audio_disable(disp); @@ -1371,8 +1326,15 @@ static void zynqmp_disp_disable(struct zynqmp_disp *disp) zynqmp_disp_avbuf_disable(disp); } -static int zynqmp_disp_setup_clock(struct zynqmp_disp *disp, - unsigned long mode_clock) +/** + * zynqmp_disp_setup_clock - Configure the display controller pixel clock rate + * @disp: Display controller + * @mode_clock: The pixel clock rate, in Hz + * + * Return: 0 on success, or a negative error clock otherwise + */ +int zynqmp_disp_setup_clock(struct zynqmp_disp *disp, + unsigned long mode_clock) { unsigned long rate; long diff; @@ -1398,186 +1360,13 @@ static int zynqmp_disp_setup_clock(struct zynqmp_disp *disp, return 0; } -static inline struct zynqmp_disp *crtc_to_disp(struct drm_crtc *crtc) -{ - return container_of(crtc, struct zynqmp_dpsub, crtc)->disp; -} - -static void -zynqmp_disp_crtc_atomic_enable(struct drm_crtc *crtc, - struct drm_atomic_state *state) -{ - struct zynqmp_disp *disp = crtc_to_disp(crtc); - struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode; - int ret, vrefresh; - - pm_runtime_get_sync(disp->dev); - - zynqmp_disp_setup_clock(disp, adjusted_mode->clock * 1000); - - ret = clk_prepare_enable(disp->dpsub->vid_clk); - if (ret) { - dev_err(disp->dev, "failed to enable the video clock\n"); - pm_runtime_put_sync(disp->dev); - return; - } - - zynqmp_disp_enable(disp); - - /* Delay of 3 vblank intervals for timing gen to be stable */ - vrefresh = (adjusted_mode->clock * 1000) / - (adjusted_mode->vtotal * adjusted_mode->htotal); - msleep(3 * 1000 / vrefresh); -} - -static void -zynqmp_disp_crtc_atomic_disable(struct drm_crtc *crtc, - struct drm_atomic_state *state) -{ - struct zynqmp_disp *disp = crtc_to_disp(crtc); - struct drm_plane_state *old_plane_state; - - /* - * Disable the plane if active. The old plane state can be NULL in the - * .shutdown() path if the plane is already disabled, skip - * zynqmp_disp_plane_atomic_disable() in that case. - */ - old_plane_state = drm_atomic_get_old_plane_state(state, crtc->primary); - if (old_plane_state) - zynqmp_disp_plane_atomic_disable(crtc->primary, state); - - zynqmp_disp_disable(disp); - - drm_crtc_vblank_off(crtc); - - spin_lock_irq(&crtc->dev->event_lock); - if (crtc->state->event) { - drm_crtc_send_vblank_event(crtc, crtc->state->event); - crtc->state->event = NULL; - } - spin_unlock_irq(&crtc->dev->event_lock); - - clk_disable_unprepare(disp->dpsub->vid_clk); - pm_runtime_put_sync(disp->dev); -} - -static int zynqmp_disp_crtc_atomic_check(struct drm_crtc *crtc, - struct drm_atomic_state *state) -{ - return drm_atomic_add_affected_planes(state, crtc); -} - -static void -zynqmp_disp_crtc_atomic_begin(struct drm_crtc *crtc, - struct drm_atomic_state *state) -{ - drm_crtc_vblank_on(crtc); -} - -static void -zynqmp_disp_crtc_atomic_flush(struct drm_crtc *crtc, - struct drm_atomic_state *state) -{ - if (crtc->state->event) { - struct drm_pending_vblank_event *event; - - /* Consume the flip_done event from atomic helper. */ - event = crtc->state->event; - crtc->state->event = NULL; - - event->pipe = drm_crtc_index(crtc); - - WARN_ON(drm_crtc_vblank_get(crtc) != 0); - - spin_lock_irq(&crtc->dev->event_lock); - drm_crtc_arm_vblank_event(crtc, event); - spin_unlock_irq(&crtc->dev->event_lock); - } -} - -static const struct drm_crtc_helper_funcs zynqmp_disp_crtc_helper_funcs = { - .atomic_enable = zynqmp_disp_crtc_atomic_enable, - .atomic_disable = zynqmp_disp_crtc_atomic_disable, - .atomic_check = zynqmp_disp_crtc_atomic_check, - .atomic_begin = zynqmp_disp_crtc_atomic_begin, - .atomic_flush = zynqmp_disp_crtc_atomic_flush, -}; - -static int zynqmp_disp_crtc_enable_vblank(struct drm_crtc *crtc) -{ - struct zynqmp_disp *disp = crtc_to_disp(crtc); - - zynqmp_dp_enable_vblank(disp->dpsub->dp); - - return 0; -} - -static void zynqmp_disp_crtc_disable_vblank(struct drm_crtc *crtc) -{ - struct zynqmp_disp *disp = crtc_to_disp(crtc); - - zynqmp_dp_disable_vblank(disp->dpsub->dp); -} - -static const struct drm_crtc_funcs zynqmp_disp_crtc_funcs = { - .destroy = drm_crtc_cleanup, - .set_config = drm_atomic_helper_set_config, - .page_flip = drm_atomic_helper_page_flip, - .reset = drm_atomic_helper_crtc_reset, - .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, - .enable_vblank = zynqmp_disp_crtc_enable_vblank, - .disable_vblank = zynqmp_disp_crtc_disable_vblank, -}; - -static int zynqmp_disp_create_crtc(struct zynqmp_disp *disp) -{ - struct drm_plane *plane = &disp->dpsub->planes[ZYNQMP_DISP_LAYER_GFX]; - struct drm_crtc *crtc = &disp->dpsub->crtc; - int ret; - - ret = drm_crtc_init_with_planes(disp->drm, crtc, plane, - NULL, &zynqmp_disp_crtc_funcs, NULL); - if (ret < 0) - return ret; - - drm_crtc_helper_add(crtc, &zynqmp_disp_crtc_helper_funcs); - - /* Start with vertical blanking interrupt reporting disabled. */ - drm_crtc_vblank_off(crtc); - - return 0; -} - -static void zynqmp_disp_map_crtc_to_plane(struct zynqmp_disp *disp) -{ - u32 possible_crtcs = drm_crtc_mask(&disp->dpsub->crtc); - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(disp->layers); i++) - disp->dpsub->planes[i].possible_crtcs = possible_crtcs; -} - /* ----------------------------------------------------------------------------- * Initialization & Cleanup */ int zynqmp_disp_drm_init(struct zynqmp_dpsub *dpsub) { - struct zynqmp_disp *disp = dpsub->disp; - int ret; - - ret = zynqmp_disp_create_planes(disp); - if (ret) - return ret; - - ret = zynqmp_disp_create_crtc(disp); - if (ret < 0) - return ret; - - zynqmp_disp_map_crtc_to_plane(disp); - - return 0; + return zynqmp_disp_create_planes(dpsub->disp); } int zynqmp_disp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm) @@ -1617,7 +1406,7 @@ int zynqmp_disp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm) if (ret) return ret; - layer = &disp->layers[ZYNQMP_DISP_LAYER_VID]; + layer = &disp->layers[ZYNQMP_DPSUB_LAYER_VID]; dpsub->dma_align = 1 << layer->dmas[0].chan->device->copy_align; return 0; diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.h b/drivers/gpu/drm/xlnx/zynqmp_disp.h index 1b7f90a81857..57cd540f550f 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_disp.h +++ b/drivers/gpu/drm/xlnx/zynqmp_disp.h @@ -25,13 +25,30 @@ #define ZYNQMP_DISP_MAX_DMA_BIT 44 struct device; +struct drm_atomic_state; struct drm_device; +struct drm_plane; struct platform_device; struct zynqmp_disp; struct zynqmp_dpsub; -void zynqmp_disp_handle_vblank(struct zynqmp_disp *disp); -uint32_t zynqmp_disp_get_crtc_mask(struct zynqmp_disp *disp); +/** + * enum zynqmp_dpsub_layer_id - Layer identifier + * @ZYNQMP_DPSUB_LAYER_VID: Video layer + * @ZYNQMP_DPSUB_LAYER_GFX: Graphics layer + */ +enum zynqmp_dpsub_layer_id { + ZYNQMP_DPSUB_LAYER_VID, + ZYNQMP_DPSUB_LAYER_GFX, +}; + +void zynqmp_disp_enable(struct zynqmp_disp *disp); +void zynqmp_disp_disable(struct zynqmp_disp *disp); +int zynqmp_disp_setup_clock(struct zynqmp_disp *disp, + unsigned long mode_clock); + +void zynqmp_disp_plane_atomic_disable(struct drm_plane *plane, + struct drm_atomic_state *state); int zynqmp_disp_drm_init(struct zynqmp_dpsub *dpsub); int zynqmp_disp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm); diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c index 3e4d164d40fe..7ad6a5d96c5f 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c @@ -31,6 +31,7 @@ #include "zynqmp_disp.h" #include "zynqmp_dp.h" #include "zynqmp_dpsub.h" +#include "zynqmp_kms.h" static uint zynqmp_dp_aux_timeout_ms = 50; module_param_named(aux_timeout_ms, zynqmp_dp_aux_timeout_ms, uint, 0444); @@ -1560,7 +1561,7 @@ static irqreturn_t zynqmp_dp_irq_handler(int irq, void *data) zynqmp_dp_write(dp, ZYNQMP_DP_INT_STATUS, status); if (status & ZYNQMP_DP_INT_VBLANK_START) - zynqmp_disp_handle_vblank(dp->dpsub->disp); + zynqmp_dpsub_handle_vblank(dp->dpsub); if (status & ZYNQMP_DP_INT_HPD_EVENT) schedule_delayed_work(&dp->hpd_work, 0); diff --git a/drivers/gpu/drm/xlnx/zynqmp_kms.c b/drivers/gpu/drm/xlnx/zynqmp_kms.c index e4e7f8fd96d2..8162bf18537b 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_kms.c +++ b/drivers/gpu/drm/xlnx/zynqmp_kms.c @@ -9,17 +9,199 @@ * - Laurent Pinchart */ +#include +#include #include #include #include +#include #include +#include #include +#include + +#include +#include +#include +#include #include "zynqmp_disp.h" #include "zynqmp_dp.h" #include "zynqmp_dpsub.h" #include "zynqmp_kms.h" +/* ----------------------------------------------------------------------------- + * DRM CRTC + */ + +static inline struct zynqmp_dpsub *crtc_to_dpsub(struct drm_crtc *crtc) +{ + return container_of(crtc, struct zynqmp_dpsub, crtc); +} + +static void zynqmp_dpsub_crtc_atomic_enable(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + struct zynqmp_dpsub *dpsub = crtc_to_dpsub(crtc); + struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode; + int ret, vrefresh; + + pm_runtime_get_sync(dpsub->dev); + + zynqmp_disp_setup_clock(dpsub->disp, adjusted_mode->clock * 1000); + + ret = clk_prepare_enable(dpsub->vid_clk); + if (ret) { + dev_err(dpsub->dev, "failed to enable a pixel clock\n"); + pm_runtime_put_sync(dpsub->dev); + return; + } + + zynqmp_disp_enable(dpsub->disp); + + /* Delay of 3 vblank intervals for timing gen to be stable */ + vrefresh = (adjusted_mode->clock * 1000) / + (adjusted_mode->vtotal * adjusted_mode->htotal); + msleep(3 * 1000 / vrefresh); +} + +static void zynqmp_dpsub_crtc_atomic_disable(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + struct zynqmp_dpsub *dpsub = crtc_to_dpsub(crtc); + struct drm_plane_state *old_plane_state; + + /* + * Disable the plane if active. The old plane state can be NULL in the + * .shutdown() path if the plane is already disabled, skip + * zynqmp_disp_plane_atomic_disable() in that case. + */ + old_plane_state = drm_atomic_get_old_plane_state(state, crtc->primary); + if (old_plane_state) + zynqmp_disp_plane_atomic_disable(crtc->primary, state); + + zynqmp_disp_disable(dpsub->disp); + + drm_crtc_vblank_off(crtc); + + spin_lock_irq(&crtc->dev->event_lock); + if (crtc->state->event) { + drm_crtc_send_vblank_event(crtc, crtc->state->event); + crtc->state->event = NULL; + } + spin_unlock_irq(&crtc->dev->event_lock); + + clk_disable_unprepare(dpsub->vid_clk); + pm_runtime_put_sync(dpsub->dev); +} + +static int zynqmp_dpsub_crtc_atomic_check(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + return drm_atomic_add_affected_planes(state, crtc); +} + +static void zynqmp_dpsub_crtc_atomic_begin(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + drm_crtc_vblank_on(crtc); +} + +static void zynqmp_dpsub_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + if (crtc->state->event) { + struct drm_pending_vblank_event *event; + + /* Consume the flip_done event from atomic helper. */ + event = crtc->state->event; + crtc->state->event = NULL; + + event->pipe = drm_crtc_index(crtc); + + WARN_ON(drm_crtc_vblank_get(crtc) != 0); + + spin_lock_irq(&crtc->dev->event_lock); + drm_crtc_arm_vblank_event(crtc, event); + spin_unlock_irq(&crtc->dev->event_lock); + } +} + +static const struct drm_crtc_helper_funcs zynqmp_dpsub_crtc_helper_funcs = { + .atomic_enable = zynqmp_dpsub_crtc_atomic_enable, + .atomic_disable = zynqmp_dpsub_crtc_atomic_disable, + .atomic_check = zynqmp_dpsub_crtc_atomic_check, + .atomic_begin = zynqmp_dpsub_crtc_atomic_begin, + .atomic_flush = zynqmp_dpsub_crtc_atomic_flush, +}; + +static int zynqmp_dpsub_crtc_enable_vblank(struct drm_crtc *crtc) +{ + struct zynqmp_dpsub *dpsub = crtc_to_dpsub(crtc); + + zynqmp_dp_enable_vblank(dpsub->dp); + + return 0; +} + +static void zynqmp_dpsub_crtc_disable_vblank(struct drm_crtc *crtc) +{ + struct zynqmp_dpsub *dpsub = crtc_to_dpsub(crtc); + + zynqmp_dp_disable_vblank(dpsub->dp); +} + +static const struct drm_crtc_funcs zynqmp_dpsub_crtc_funcs = { + .destroy = drm_crtc_cleanup, + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, + .reset = drm_atomic_helper_crtc_reset, + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, + .enable_vblank = zynqmp_dpsub_crtc_enable_vblank, + .disable_vblank = zynqmp_dpsub_crtc_disable_vblank, +}; + +static int zynqmp_dpsub_create_crtc(struct zynqmp_dpsub *dpsub) +{ + struct drm_plane *plane = &dpsub->planes[ZYNQMP_DPSUB_LAYER_GFX]; + struct drm_crtc *crtc = &dpsub->crtc; + int ret; + + ret = drm_crtc_init_with_planes(&dpsub->drm, crtc, plane, + NULL, &zynqmp_dpsub_crtc_funcs, NULL); + if (ret < 0) + return ret; + + drm_crtc_helper_add(crtc, &zynqmp_dpsub_crtc_helper_funcs); + + /* Start with vertical blanking interrupt reporting disabled. */ + drm_crtc_vblank_off(crtc); + + return 0; +} + +static void zynqmp_dpsub_map_crtc_to_plane(struct zynqmp_dpsub *dpsub) +{ + u32 possible_crtcs = drm_crtc_mask(&dpsub->crtc); + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(dpsub->planes); i++) + dpsub->planes[i].possible_crtcs = possible_crtcs; +} + +/** + * zynqmp_dpsub_handle_vblank - Handle the vblank event + * @dpsub: DisplayPort subsystem + * + * This function handles the vblank interrupt, and sends an event to + * CRTC object. This will be called by the DP vblank interrupt handler. + */ +void zynqmp_dpsub_handle_vblank(struct zynqmp_dpsub *dpsub) +{ + drm_crtc_handle_vblank(&dpsub->crtc); +} + /* ----------------------------------------------------------------------------- * Initialization */ @@ -38,12 +220,18 @@ int zynqmp_dpsub_kms_init(struct zynqmp_dpsub *dpsub) if (ret) return ret; + ret = zynqmp_dpsub_create_crtc(dpsub); + if (ret < 0) + return ret; + + zynqmp_dpsub_map_crtc_to_plane(dpsub); + ret = zynqmp_dp_drm_init(dpsub); if (ret) return ret; /* Create the encoder and attach the bridge. */ - encoder->possible_crtcs |= zynqmp_disp_get_crtc_mask(dpsub->disp); + encoder->possible_crtcs |= drm_crtc_mask(&dpsub->crtc); drm_simple_encoder_init(&dpsub->drm, encoder, DRM_MODE_ENCODER_NONE); ret = drm_bridge_attach(encoder, dpsub->bridge, NULL, diff --git a/drivers/gpu/drm/xlnx/zynqmp_kms.h b/drivers/gpu/drm/xlnx/zynqmp_kms.h index a6729d9d82cc..a8934b1abb05 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_kms.h +++ b/drivers/gpu/drm/xlnx/zynqmp_kms.h @@ -14,6 +14,8 @@ struct zynqmp_dpsub; +void zynqmp_dpsub_handle_vblank(struct zynqmp_dpsub *dpsub); + int zynqmp_dpsub_kms_init(struct zynqmp_dpsub *dpsub); #endif /* _ZYNQMP_KMS_H_ */ -- cgit From ee1229b35d20d00ed13009d81401032de06ac58e Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Aug 2021 14:29:52 +0300 Subject: drm: xlnx: zynqmp_dpsub: Move planes handling to zynqmp_kms.c Decouple the planes handling from the display controller programming by moving the corresponding code from zynqmp_disp.c to zynqmp_kms.c. This prepares for using the DPSUB with a live video input, without creating DRM planes in the DPSUB driver. While at it, fix a typo in a comment. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/xlnx/zynqmp_disp.c | 169 +++--------------------------------- drivers/gpu/drm/xlnx/zynqmp_disp.h | 19 ++-- drivers/gpu/drm/xlnx/zynqmp_dpsub.h | 2 + drivers/gpu/drm/xlnx/zynqmp_kms.c | 145 +++++++++++++++++++++++++++++-- 4 files changed, 167 insertions(+), 168 deletions(-) diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c b/drivers/gpu/drm/xlnx/zynqmp_disp.c index c7d95f3d2a84..e1d6bb43d5f1 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_disp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c @@ -9,10 +9,6 @@ * - Laurent Pinchart */ -#include -#include -#include -#include #include #include #include @@ -141,7 +137,6 @@ struct zynqmp_disp_layer { /** * struct zynqmp_disp - Display controller * @dev: Device structure - * @drm: DRM core * @dpsub: Display subsystem * @blend.base: Register I/O base address for the blender * @avbuf.base: Register I/O base address for the audio/video buffer manager @@ -150,7 +145,6 @@ struct zynqmp_disp_layer { */ struct zynqmp_disp { struct device *dev; - struct drm_device *drm; struct zynqmp_dpsub *dpsub; struct { @@ -380,11 +374,6 @@ static void zynqmp_disp_avbuf_write(struct zynqmp_disp *disp, int reg, u32 val) writel(val, disp->avbuf.base + reg); } -static bool zynqmp_disp_layer_is_gfx(const struct zynqmp_disp_layer *layer) -{ - return layer->id == ZYNQMP_DPSUB_LAYER_GFX; -} - static bool zynqmp_disp_layer_is_video(const struct zynqmp_disp_layer *layer) { return layer->id == ZYNQMP_DPSUB_LAYER_VID; @@ -722,8 +711,8 @@ static void zynqmp_disp_blend_set_bg_color(struct zynqmp_disp *disp, * @enable: True to enable global alpha blending * @alpha: Global alpha value (ignored if @enabled is false) */ -static void zynqmp_disp_blend_set_global_alpha(struct zynqmp_disp *disp, - bool enable, u32 alpha) +void zynqmp_disp_blend_set_global_alpha(struct zynqmp_disp *disp, + bool enable, u32 alpha) { zynqmp_disp_blend_write(disp, ZYNQMP_DISP_V_BLEND_SET_GLOBAL_ALPHA, ZYNQMP_DISP_V_BLEND_SET_GLOBAL_ALPHA_VALUE(alpha) | @@ -904,8 +893,8 @@ zynqmp_disp_layer_find_format(struct zynqmp_disp_layer *layer, * supported by the layer. The number of formats in the array is returned * through the num_formats argument. */ -static u32 *zynqmp_disp_layer_drm_formats(struct zynqmp_disp_layer *layer, - unsigned int *num_formats) +u32 *zynqmp_disp_layer_drm_formats(struct zynqmp_disp_layer *layer, + unsigned int *num_formats) { unsigned int i; u32 *formats; @@ -929,7 +918,7 @@ static u32 *zynqmp_disp_layer_drm_formats(struct zynqmp_disp_layer *layer, * Enable the @layer in the audio/video buffer manager and the blender. DMA * channels are started separately by zynqmp_disp_layer_update(). */ -static void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer) +void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer) { zynqmp_disp_avbuf_enable_video(layer->disp, layer, ZYNQMP_DISP_LAYER_NONLIVE); @@ -945,7 +934,7 @@ static void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer) * Disable the layer by stopping its DMA channels and disabling it in the * audio/video buffer manager and the blender. */ -static void zynqmp_disp_layer_disable(struct zynqmp_disp_layer *layer) +void zynqmp_disp_layer_disable(struct zynqmp_disp_layer *layer) { unsigned int i; @@ -963,8 +952,8 @@ static void zynqmp_disp_layer_disable(struct zynqmp_disp_layer *layer) * * Set the format for @layer to @info. The layer must be disabled. */ -static void zynqmp_disp_layer_set_format(struct zynqmp_disp_layer *layer, - const struct drm_format_info *info) +void zynqmp_disp_layer_set_format(struct zynqmp_disp_layer *layer, + const struct drm_format_info *info) { unsigned int i; @@ -1002,8 +991,8 @@ static void zynqmp_disp_layer_set_format(struct zynqmp_disp_layer *layer, * * Return: 0 on success, or the DMA descriptor failure error otherwise */ -static int zynqmp_disp_layer_update(struct zynqmp_disp_layer *layer, - struct drm_plane_state *state) +int zynqmp_disp_layer_update(struct zynqmp_disp_layer *layer, + struct drm_plane_state *state) { const struct drm_format_info *info = layer->drm_fmt; unsigned int i; @@ -1043,136 +1032,6 @@ static int zynqmp_disp_layer_update(struct zynqmp_disp_layer *layer, return 0; } -static int -zynqmp_disp_plane_atomic_check(struct drm_plane *plane, - struct drm_atomic_state *state) -{ - struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, - plane); - struct drm_crtc_state *crtc_state; - - if (!new_plane_state->crtc) - return 0; - - crtc_state = drm_atomic_get_crtc_state(state, new_plane_state->crtc); - if (IS_ERR(crtc_state)) - return PTR_ERR(crtc_state); - - return drm_atomic_helper_check_plane_state(new_plane_state, - crtc_state, - DRM_PLANE_NO_SCALING, - DRM_PLANE_NO_SCALING, - false, false); -} - -void -zynqmp_disp_plane_atomic_disable(struct drm_plane *plane, - struct drm_atomic_state *state) -{ - struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, - plane); - struct zynqmp_dpsub *dpsub = to_zynqmp_dpsub(plane->dev); - struct zynqmp_disp_layer *layer = &dpsub->disp->layers[plane->index]; - - if (!old_state->fb) - return; - - zynqmp_disp_layer_disable(layer); - - if (zynqmp_disp_layer_is_gfx(layer)) - zynqmp_disp_blend_set_global_alpha(layer->disp, false, - plane->state->alpha >> 8); -} - -static void -zynqmp_disp_plane_atomic_update(struct drm_plane *plane, - struct drm_atomic_state *state) -{ - struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane); - struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane); - struct zynqmp_dpsub *dpsub = to_zynqmp_dpsub(plane->dev); - struct zynqmp_disp_layer *layer = &dpsub->disp->layers[plane->index]; - bool format_changed = false; - - if (!old_state->fb || - old_state->fb->format->format != new_state->fb->format->format) - format_changed = true; - - /* - * If the format has changed (including going from a previously - * disabled state to any format), reconfigure the format. Disable the - * plane first if needed. - */ - if (format_changed) { - if (old_state->fb) - zynqmp_disp_layer_disable(layer); - - zynqmp_disp_layer_set_format(layer, new_state->fb->format); - } - - zynqmp_disp_layer_update(layer, new_state); - - if (zynqmp_disp_layer_is_gfx(layer)) - zynqmp_disp_blend_set_global_alpha(layer->disp, true, - plane->state->alpha >> 8); - - /* Enable or re-enable the plane is the format has changed. */ - if (format_changed) - zynqmp_disp_layer_enable(layer); -} - -static const struct drm_plane_helper_funcs zynqmp_disp_plane_helper_funcs = { - .atomic_check = zynqmp_disp_plane_atomic_check, - .atomic_update = zynqmp_disp_plane_atomic_update, - .atomic_disable = zynqmp_disp_plane_atomic_disable, -}; - -static const struct drm_plane_funcs zynqmp_disp_plane_funcs = { - .update_plane = drm_atomic_helper_update_plane, - .disable_plane = drm_atomic_helper_disable_plane, - .destroy = drm_plane_cleanup, - .reset = drm_atomic_helper_plane_reset, - .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, -}; - -static int zynqmp_disp_create_planes(struct zynqmp_disp *disp) -{ - unsigned int i; - int ret; - - for (i = 0; i < ARRAY_SIZE(disp->layers); i++) { - struct zynqmp_disp_layer *layer = &disp->layers[i]; - struct drm_plane *plane = &disp->dpsub->planes[i]; - enum drm_plane_type type; - unsigned int num_formats; - u32 *formats; - - formats = zynqmp_disp_layer_drm_formats(layer, &num_formats); - if (!formats) - return -ENOMEM; - - /* Graphics layer is primary, and video layer is overlay. */ - type = zynqmp_disp_layer_is_video(layer) - ? DRM_PLANE_TYPE_OVERLAY : DRM_PLANE_TYPE_PRIMARY; - ret = drm_universal_plane_init(disp->drm, plane, 0, - &zynqmp_disp_plane_funcs, - formats, num_formats, - NULL, type, NULL); - kfree(formats); - if (ret) - return ret; - - drm_plane_helper_add(plane, &zynqmp_disp_plane_helper_funcs); - - drm_plane_create_zpos_immutable_property(plane, i); - if (zynqmp_disp_layer_is_gfx(layer)) - drm_plane_create_alpha_property(plane); - } - - return 0; -} - /** * zynqmp_disp_layer_release_dma - Release DMA channels for a layer * @disp: Display controller @@ -1280,6 +1139,8 @@ static int zynqmp_disp_create_layers(struct zynqmp_disp *disp) ret = zynqmp_disp_layer_request_dma(disp, layer); if (ret) goto err; + + disp->dpsub->layers[i] = layer; } return 0; @@ -1364,11 +1225,6 @@ int zynqmp_disp_setup_clock(struct zynqmp_disp *disp, * Initialization & Cleanup */ -int zynqmp_disp_drm_init(struct zynqmp_dpsub *dpsub) -{ - return zynqmp_disp_create_planes(dpsub->disp); -} - int zynqmp_disp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm) { struct platform_device *pdev = to_platform_device(dpsub->dev); @@ -1383,7 +1239,6 @@ int zynqmp_disp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm) disp->dev = &pdev->dev; disp->dpsub = dpsub; - disp->drm = drm; dpsub->disp = disp; diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.h b/drivers/gpu/drm/xlnx/zynqmp_disp.h index 57cd540f550f..663f7d67c78f 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_disp.h +++ b/drivers/gpu/drm/xlnx/zynqmp_disp.h @@ -25,11 +25,12 @@ #define ZYNQMP_DISP_MAX_DMA_BIT 44 struct device; -struct drm_atomic_state; struct drm_device; -struct drm_plane; +struct drm_format_info; +struct drm_plane_state; struct platform_device; struct zynqmp_disp; +struct zynqmp_disp_layer; struct zynqmp_dpsub; /** @@ -47,10 +48,18 @@ void zynqmp_disp_disable(struct zynqmp_disp *disp); int zynqmp_disp_setup_clock(struct zynqmp_disp *disp, unsigned long mode_clock); -void zynqmp_disp_plane_atomic_disable(struct drm_plane *plane, - struct drm_atomic_state *state); +void zynqmp_disp_blend_set_global_alpha(struct zynqmp_disp *disp, + bool enable, u32 alpha); + +u32 *zynqmp_disp_layer_drm_formats(struct zynqmp_disp_layer *layer, + unsigned int *num_formats); +void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer); +void zynqmp_disp_layer_disable(struct zynqmp_disp_layer *layer); +void zynqmp_disp_layer_set_format(struct zynqmp_disp_layer *layer, + const struct drm_format_info *info); +int zynqmp_disp_layer_update(struct zynqmp_disp_layer *layer, + struct drm_plane_state *state); -int zynqmp_disp_drm_init(struct zynqmp_dpsub *dpsub); int zynqmp_disp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm); void zynqmp_disp_remove(struct zynqmp_dpsub *dpsub); diff --git a/drivers/gpu/drm/xlnx/zynqmp_dpsub.h b/drivers/gpu/drm/xlnx/zynqmp_dpsub.h index 2a955895404f..bad9148d2d3e 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dpsub.h +++ b/drivers/gpu/drm/xlnx/zynqmp_dpsub.h @@ -21,6 +21,7 @@ struct device; struct drm_bridge; struct drm_device; struct zynqmp_disp; +struct zynqmp_disp_layer; struct zynqmp_dp; #define ZYNQMP_DPSUB_NUM_LAYERS 2 @@ -65,6 +66,7 @@ struct zynqmp_dpsub { struct drm_bridge *bridge; struct zynqmp_disp *disp; + struct zynqmp_disp_layer *layers[ZYNQMP_DPSUB_NUM_LAYERS]; struct zynqmp_dp *dp; unsigned int dma_align; diff --git a/drivers/gpu/drm/xlnx/zynqmp_kms.c b/drivers/gpu/drm/xlnx/zynqmp_kms.c index 8162bf18537b..a2ad4c9167ab 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_kms.c +++ b/drivers/gpu/drm/xlnx/zynqmp_kms.c @@ -11,12 +11,17 @@ #include #include +#include #include #include #include #include #include +#include +#include +#include #include +#include #include #include @@ -30,6 +35,137 @@ #include "zynqmp_dpsub.h" #include "zynqmp_kms.h" +/* ----------------------------------------------------------------------------- + * DRM Planes + */ + +static int zynqmp_dpsub_plane_atomic_check(struct drm_plane *plane, + struct drm_atomic_state *state) +{ + struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, + plane); + struct drm_crtc_state *crtc_state; + + if (!new_plane_state->crtc) + return 0; + + crtc_state = drm_atomic_get_crtc_state(state, new_plane_state->crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + return drm_atomic_helper_check_plane_state(new_plane_state, + crtc_state, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, + false, false); +} + +static void zynqmp_dpsub_plane_atomic_disable(struct drm_plane *plane, + struct drm_atomic_state *state) +{ + struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, + plane); + struct zynqmp_dpsub *dpsub = to_zynqmp_dpsub(plane->dev); + struct zynqmp_disp_layer *layer = dpsub->layers[plane->index]; + + if (!old_state->fb) + return; + + zynqmp_disp_layer_disable(layer); + + if (plane->index == ZYNQMP_DPSUB_LAYER_GFX) + zynqmp_disp_blend_set_global_alpha(dpsub->disp, false, + plane->state->alpha >> 8); +} + +static void zynqmp_dpsub_plane_atomic_update(struct drm_plane *plane, + struct drm_atomic_state *state) +{ + struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane); + struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane); + struct zynqmp_dpsub *dpsub = to_zynqmp_dpsub(plane->dev); + struct zynqmp_disp_layer *layer = dpsub->layers[plane->index]; + bool format_changed = false; + + if (!old_state->fb || + old_state->fb->format->format != new_state->fb->format->format) + format_changed = true; + + /* + * If the format has changed (including going from a previously + * disabled state to any format), reconfigure the format. Disable the + * plane first if needed. + */ + if (format_changed) { + if (old_state->fb) + zynqmp_disp_layer_disable(layer); + + zynqmp_disp_layer_set_format(layer, new_state->fb->format); + } + + zynqmp_disp_layer_update(layer, new_state); + + if (plane->index == ZYNQMP_DPSUB_LAYER_GFX) + zynqmp_disp_blend_set_global_alpha(dpsub->disp, true, + plane->state->alpha >> 8); + + /* Enable or re-enable the plane if the format has changed. */ + if (format_changed) + zynqmp_disp_layer_enable(layer); +} + +static const struct drm_plane_helper_funcs zynqmp_dpsub_plane_helper_funcs = { + .atomic_check = zynqmp_dpsub_plane_atomic_check, + .atomic_update = zynqmp_dpsub_plane_atomic_update, + .atomic_disable = zynqmp_dpsub_plane_atomic_disable, +}; + +static const struct drm_plane_funcs zynqmp_dpsub_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = drm_plane_cleanup, + .reset = drm_atomic_helper_plane_reset, + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, +}; + +static int zynqmp_dpsub_create_planes(struct zynqmp_dpsub *dpsub) +{ + unsigned int i; + int ret; + + for (i = 0; i < ARRAY_SIZE(dpsub->planes); i++) { + struct zynqmp_disp_layer *layer = dpsub->layers[i]; + struct drm_plane *plane = &dpsub->planes[i]; + enum drm_plane_type type; + unsigned int num_formats; + u32 *formats; + + formats = zynqmp_disp_layer_drm_formats(layer, &num_formats); + if (!formats) + return -ENOMEM; + + /* Graphics layer is primary, and video layer is overlay. */ + type = i == ZYNQMP_DPSUB_LAYER_VID + ? DRM_PLANE_TYPE_OVERLAY : DRM_PLANE_TYPE_PRIMARY; + ret = drm_universal_plane_init(&dpsub->drm, plane, 0, + &zynqmp_dpsub_plane_funcs, + formats, num_formats, + NULL, type, NULL); + kfree(formats); + if (ret) + return ret; + + drm_plane_helper_add(plane, &zynqmp_dpsub_plane_helper_funcs); + + drm_plane_create_zpos_immutable_property(plane, i); + if (i == ZYNQMP_DPSUB_LAYER_GFX) + drm_plane_create_alpha_property(plane); + } + + return 0; +} + /* ----------------------------------------------------------------------------- * DRM CRTC */ @@ -78,7 +214,7 @@ static void zynqmp_dpsub_crtc_atomic_disable(struct drm_crtc *crtc, */ old_plane_state = drm_atomic_get_old_plane_state(state, crtc->primary); if (old_plane_state) - zynqmp_disp_plane_atomic_disable(crtc->primary, state); + zynqmp_dpsub_plane_atomic_disable(crtc->primary, state); zynqmp_disp_disable(dpsub->disp); @@ -212,11 +348,8 @@ int zynqmp_dpsub_kms_init(struct zynqmp_dpsub *dpsub) struct drm_connector *connector; int ret; - /* - * Initialize the DISP and DP components. This will creates planes, - * CRTC, and a bridge for the DP encoder. - */ - ret = zynqmp_disp_drm_init(dpsub); + /* Create the planes and the CRTC, and initialize the DP encoder. */ + ret = zynqmp_dpsub_create_planes(dpsub); if (ret) return ret; -- cgit From 2dfd045c84359e3fefe9967f5a3579f8d8587ead Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Aug 2021 14:29:52 +0300 Subject: drm: xlnx: zynqmp_dpsub: Register AUX bus at bridge attach time To prepare for operating as a standalone DP bridge with the DRM device implemented in the PL, move registration of the AUX bus to bridge attach time, as that's the earliest point when a DRM device is available. The DRM device pointer stored in zynqmp_dp isn't used anymore, drop it. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/xlnx/zynqmp_dp.c | 41 +++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c index 7ad6a5d96c5f..544b062ce723 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c @@ -276,7 +276,6 @@ struct zynqmp_dp_config { * struct zynqmp_dp - Xilinx DisplayPort core * @dev: device structure * @dpsub: Display subsystem - * @drm: DRM core * @iomem: device I/O memory for register access * @reset: reset controller * @irq: irq @@ -297,7 +296,6 @@ struct zynqmp_dp_config { struct zynqmp_dp { struct device *dev; struct zynqmp_dpsub *dpsub; - struct drm_device *drm; void __iomem *iomem; struct reset_control *reset; int irq; @@ -1057,7 +1055,7 @@ static int zynqmp_dp_aux_init(struct zynqmp_dp *dp) dp->aux.name = "ZynqMP DP AUX"; dp->aux.dev = dp->dev; - dp->aux.drm_dev = dp->drm; + dp->aux.drm_dev = dp->bridge.dev; dp->aux.transfer = zynqmp_dp_aux_transfer; return drm_dp_aux_register(&dp->aux); @@ -1283,14 +1281,35 @@ static int zynqmp_dp_bridge_attach(struct drm_bridge *bridge, struct zynqmp_dp *dp = bridge_to_dp(bridge); int ret; + /* Initialize and register the AUX adapter. */ + ret = zynqmp_dp_aux_init(dp); + if (ret) { + dev_err(dp->dev, "failed to initialize DP aux\n"); + return ret; + } + if (dp->next_bridge) { ret = drm_bridge_attach(bridge->encoder, dp->next_bridge, bridge, flags); if (ret < 0) - return ret; + goto error; } + /* Now that initialisation is complete, enable interrupts. */ + zynqmp_dp_write(dp, ZYNQMP_DP_INT_EN, ZYNQMP_DP_INT_ALL); + return 0; + +error: + zynqmp_dp_aux_cleanup(dp); + return ret; +} + +static void zynqmp_dp_bridge_detach(struct drm_bridge *bridge) +{ + struct zynqmp_dp *dp = bridge_to_dp(bridge); + + zynqmp_dp_aux_cleanup(dp); } static int zynqmp_dp_bridge_mode_valid(struct drm_bridge *bridge, @@ -1495,6 +1514,7 @@ static struct edid *zynqmp_dp_bridge_get_edid(struct drm_bridge *bridge, static const struct drm_bridge_funcs zynqmp_dp_bridge_funcs = { .attach = zynqmp_dp_bridge_attach, + .detach = zynqmp_dp_bridge_detach, .mode_valid = zynqmp_dp_bridge_mode_valid, .atomic_enable = zynqmp_dp_bridge_atomic_enable, .atomic_disable = zynqmp_dp_bridge_atomic_disable, @@ -1594,7 +1614,6 @@ int zynqmp_dp_drm_init(struct zynqmp_dpsub *dpsub) { struct zynqmp_dp *dp = dpsub->dp; struct drm_bridge *bridge = &dp->bridge; - int ret; dp->config.misc0 &= ~ZYNQMP_DP_MAIN_STREAM_MISC0_SYNC_LOCK; zynqmp_dp_set_format(dp, NULL, ZYNQMP_DPSUB_FORMAT_RGB, 8); @@ -1606,16 +1625,6 @@ int zynqmp_dp_drm_init(struct zynqmp_dpsub *dpsub) bridge->type = DRM_MODE_CONNECTOR_DisplayPort; dpsub->bridge = bridge; - /* Initialize and register the AUX adapter. */ - ret = zynqmp_dp_aux_init(dp); - if (ret) { - dev_err(dp->dev, "failed to initialize DP aux\n"); - return ret; - } - - /* Now that initialisation is complete, enable interrupts. */ - zynqmp_dp_write(dp, ZYNQMP_DP_INT_EN, ZYNQMP_DP_INT_ALL); - return 0; } @@ -1633,7 +1642,6 @@ int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm) dp->dev = &pdev->dev; dp->dpsub = dpsub; dp->status = connector_status_disconnected; - dp->drm = drm; INIT_DELAYED_WORK(&dp->hpd_work, zynqmp_dp_hpd_work_func); @@ -1719,7 +1727,6 @@ void zynqmp_dp_remove(struct zynqmp_dpsub *dpsub) disable_irq(dp->irq); cancel_delayed_work_sync(&dp->hpd_work); - zynqmp_dp_aux_cleanup(dp); zynqmp_dp_write(dp, ZYNQMP_DP_TRANSMITTER_ENABLE, 0); zynqmp_dp_write(dp, ZYNQMP_DP_INT_DS, 0xffffffff); -- cgit From 5889ee59031b75a5048870f0644419719a1d108d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Aug 2021 14:29:52 +0300 Subject: drm: xlnx: zynqmp_dpsub: Move DP bridge init to zynqmp_dp_probe() There's no need to delay bridge initialization, move it to zynqmp_dp_probe() and drop the zynqmp_dp_drm_init() function. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/xlnx/zynqmp_dp.c | 30 ++++++++++++------------------ drivers/gpu/drm/xlnx/zynqmp_dp.h | 1 - drivers/gpu/drm/xlnx/zynqmp_kms.c | 6 +----- 3 files changed, 13 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c index 544b062ce723..0c7add926da3 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c @@ -1610,27 +1610,10 @@ handled: * Initialization & Cleanup */ -int zynqmp_dp_drm_init(struct zynqmp_dpsub *dpsub) -{ - struct zynqmp_dp *dp = dpsub->dp; - struct drm_bridge *bridge = &dp->bridge; - - dp->config.misc0 &= ~ZYNQMP_DP_MAIN_STREAM_MISC0_SYNC_LOCK; - zynqmp_dp_set_format(dp, NULL, ZYNQMP_DPSUB_FORMAT_RGB, 8); - - /* Initialize the bridge. */ - bridge->funcs = &zynqmp_dp_bridge_funcs; - bridge->ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID - | DRM_BRIDGE_OP_HPD; - bridge->type = DRM_MODE_CONNECTOR_DisplayPort; - dpsub->bridge = bridge; - - return 0; -} - int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm) { struct platform_device *pdev = to_platform_device(dpsub->dev); + struct drm_bridge *bridge; struct zynqmp_dp *dp; struct resource *res; int ret; @@ -1673,6 +1656,14 @@ int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm) if (ret) goto err_reset; + /* Initialize the bridge. */ + bridge = &dp->bridge; + bridge->funcs = &zynqmp_dp_bridge_funcs; + bridge->ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID + | DRM_BRIDGE_OP_HPD; + bridge->type = DRM_MODE_CONNECTOR_DisplayPort; + dpsub->bridge = bridge; + /* * Acquire the next bridge in the chain. Ignore errors caused by port@5 * not being connected for backward-compatibility with older DTs. @@ -1683,6 +1674,9 @@ int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm) goto err_reset; /* Initialize the hardware. */ + dp->config.misc0 &= ~ZYNQMP_DP_MAIN_STREAM_MISC0_SYNC_LOCK; + zynqmp_dp_set_format(dp, NULL, ZYNQMP_DPSUB_FORMAT_RGB, 8); + zynqmp_dp_write(dp, ZYNQMP_DP_TX_PHY_POWER_DOWN, ZYNQMP_DP_TX_PHY_POWER_DOWN_ALL); zynqmp_dp_set(dp, ZYNQMP_DP_PHY_RESET, ZYNQMP_DP_PHY_RESET_ALL_RESET); diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.h b/drivers/gpu/drm/xlnx/zynqmp_dp.h index 4507740093f6..736d810fa16f 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dp.h +++ b/drivers/gpu/drm/xlnx/zynqmp_dp.h @@ -20,7 +20,6 @@ struct zynqmp_dpsub; void zynqmp_dp_enable_vblank(struct zynqmp_dp *dp); void zynqmp_dp_disable_vblank(struct zynqmp_dp *dp); -int zynqmp_dp_drm_init(struct zynqmp_dpsub *dpsub); int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm); void zynqmp_dp_remove(struct zynqmp_dpsub *dpsub); diff --git a/drivers/gpu/drm/xlnx/zynqmp_kms.c b/drivers/gpu/drm/xlnx/zynqmp_kms.c index a2ad4c9167ab..3b89097a2c6e 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_kms.c +++ b/drivers/gpu/drm/xlnx/zynqmp_kms.c @@ -348,7 +348,7 @@ int zynqmp_dpsub_kms_init(struct zynqmp_dpsub *dpsub) struct drm_connector *connector; int ret; - /* Create the planes and the CRTC, and initialize the DP encoder. */ + /* Create the planes and the CRTC. */ ret = zynqmp_dpsub_create_planes(dpsub); if (ret) return ret; @@ -359,10 +359,6 @@ int zynqmp_dpsub_kms_init(struct zynqmp_dpsub *dpsub) zynqmp_dpsub_map_crtc_to_plane(dpsub); - ret = zynqmp_dp_drm_init(dpsub); - if (ret) - return ret; - /* Create the encoder and attach the bridge. */ encoder->possible_crtcs |= drm_crtc_mask(&dpsub->crtc); drm_simple_encoder_init(&dpsub->drm, encoder, DRM_MODE_ENCODER_NONE); -- cgit From 6ca91bb43a63ad036a05491ad662aa18feb0e4ce Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Aug 2021 14:29:52 +0300 Subject: drm: xlnx: zynqmp_dpsub: Manage DP and DISP allocations manually The zynqmp_disp and zynqmp_dp structures are allocated with drmm_kzalloc(). While this simplifies management of memory, it requires a DRM device, which will not be available at probe time when the DP bridge will be used standalone, with a DRM device in the PL. To prepare for this, switch to manual allocation for zynqmp_disp and zynqmp_dp. The cleanup still uses the DRM managed infrastructure, but one level up, at the top level. This will be addressed separately. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/xlnx/zynqmp_disp.c | 34 ++++++++++++++++++++++------------ drivers/gpu/drm/xlnx/zynqmp_disp.h | 3 +-- drivers/gpu/drm/xlnx/zynqmp_dp.c | 30 ++++++++++++++++++------------ drivers/gpu/drm/xlnx/zynqmp_dp.h | 3 +-- drivers/gpu/drm/xlnx/zynqmp_dpsub.c | 17 +++++++++++++++-- 5 files changed, 57 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c b/drivers/gpu/drm/xlnx/zynqmp_disp.c index e1d6bb43d5f1..e9d4b891fac9 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_disp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include @@ -22,6 +21,7 @@ #include #include #include +#include #include "zynqmp_disp.h" #include "zynqmp_disp_regs.h" @@ -1225,7 +1225,7 @@ int zynqmp_disp_setup_clock(struct zynqmp_disp *disp, * Initialization & Cleanup */ -int zynqmp_disp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm) +int zynqmp_disp_probe(struct zynqmp_dpsub *dpsub) { struct platform_device *pdev = to_platform_device(dpsub->dev); struct zynqmp_disp *disp; @@ -1233,38 +1233,48 @@ int zynqmp_disp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm) struct resource *res; int ret; - disp = drmm_kzalloc(drm, sizeof(*disp), GFP_KERNEL); + disp = kzalloc(sizeof(*disp), GFP_KERNEL); if (!disp) return -ENOMEM; disp->dev = &pdev->dev; disp->dpsub = dpsub; - dpsub->disp = disp; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "blend"); disp->blend.base = devm_ioremap_resource(disp->dev, res); - if (IS_ERR(disp->blend.base)) - return PTR_ERR(disp->blend.base); + if (IS_ERR(disp->blend.base)) { + ret = PTR_ERR(disp->blend.base); + goto error; + } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "av_buf"); disp->avbuf.base = devm_ioremap_resource(disp->dev, res); - if (IS_ERR(disp->avbuf.base)) - return PTR_ERR(disp->avbuf.base); + if (IS_ERR(disp->avbuf.base)) { + ret = PTR_ERR(disp->avbuf.base); + goto error; + } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "aud"); disp->audio.base = devm_ioremap_resource(disp->dev, res); - if (IS_ERR(disp->audio.base)) - return PTR_ERR(disp->audio.base); + if (IS_ERR(disp->audio.base)) { + ret = PTR_ERR(disp->audio.base); + goto error; + } ret = zynqmp_disp_create_layers(disp); if (ret) - return ret; + goto error; layer = &disp->layers[ZYNQMP_DPSUB_LAYER_VID]; dpsub->dma_align = 1 << layer->dmas[0].chan->device->copy_align; + dpsub->disp = disp; + return 0; + +error: + kfree(disp); + return ret; } void zynqmp_disp_remove(struct zynqmp_dpsub *dpsub) diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.h b/drivers/gpu/drm/xlnx/zynqmp_disp.h index 663f7d67c78f..9b8b202224d9 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_disp.h +++ b/drivers/gpu/drm/xlnx/zynqmp_disp.h @@ -25,7 +25,6 @@ #define ZYNQMP_DISP_MAX_DMA_BIT 44 struct device; -struct drm_device; struct drm_format_info; struct drm_plane_state; struct platform_device; @@ -60,7 +59,7 @@ void zynqmp_disp_layer_set_format(struct zynqmp_disp_layer *layer, int zynqmp_disp_layer_update(struct zynqmp_disp_layer *layer, struct drm_plane_state *state); -int zynqmp_disp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm); +int zynqmp_disp_probe(struct zynqmp_dpsub *dpsub); void zynqmp_disp_remove(struct zynqmp_dpsub *dpsub); #endif /* _ZYNQMP_DISP_H_ */ diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c index 0c7add926da3..001bc24f92bd 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include @@ -27,6 +26,7 @@ #include #include #include +#include #include "zynqmp_disp.h" #include "zynqmp_dp.h" @@ -1610,7 +1610,7 @@ handled: * Initialization & Cleanup */ -int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm) +int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub) { struct platform_device *pdev = to_platform_device(dpsub->dev); struct drm_bridge *bridge; @@ -1618,7 +1618,7 @@ int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm) struct resource *res; int ret; - dp = drmm_kzalloc(drm, sizeof(*dp), GFP_KERNEL); + dp = kzalloc(sizeof(*dp), GFP_KERNEL); if (!dp) return -ENOMEM; @@ -1628,29 +1628,32 @@ int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm) INIT_DELAYED_WORK(&dp->hpd_work, zynqmp_dp_hpd_work_func); - dpsub->dp = dp; - /* Acquire all resources (IOMEM, IRQ and PHYs). */ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dp"); dp->iomem = devm_ioremap_resource(dp->dev, res); - if (IS_ERR(dp->iomem)) - return PTR_ERR(dp->iomem); + if (IS_ERR(dp->iomem)) { + ret = PTR_ERR(dp->iomem); + goto err_free; + } dp->irq = platform_get_irq(pdev, 0); - if (dp->irq < 0) - return dp->irq; + if (dp->irq < 0) { + ret = dp->irq; + goto err_free; + } dp->reset = devm_reset_control_get(dp->dev, NULL); if (IS_ERR(dp->reset)) { if (PTR_ERR(dp->reset) != -EPROBE_DEFER) dev_err(dp->dev, "failed to get reset: %ld\n", PTR_ERR(dp->reset)); - return PTR_ERR(dp->reset); + ret = PTR_ERR(dp->reset); + goto err_free; } ret = zynqmp_dp_reset(dp, false); if (ret < 0) - return ret; + goto err_free; ret = zynqmp_dp_phy_probe(dp); if (ret) @@ -1700,6 +1703,8 @@ int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm) if (ret < 0) goto err_phy_exit; + dpsub->dp = dp; + dev_dbg(dp->dev, "ZynqMP DisplayPort Tx probed with %u lanes\n", dp->num_lanes); @@ -1709,7 +1714,8 @@ err_phy_exit: zynqmp_dp_phy_exit(dp); err_reset: zynqmp_dp_reset(dp, true); - +err_free: + kfree(dp); return ret; } diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.h b/drivers/gpu/drm/xlnx/zynqmp_dp.h index 736d810fa16f..f077d7fbd0ad 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dp.h +++ b/drivers/gpu/drm/xlnx/zynqmp_dp.h @@ -12,7 +12,6 @@ #ifndef _ZYNQMP_DP_H_ #define _ZYNQMP_DP_H_ -struct drm_device; struct platform_device; struct zynqmp_dp; struct zynqmp_dpsub; @@ -20,7 +19,7 @@ struct zynqmp_dpsub; void zynqmp_dp_enable_vblank(struct zynqmp_dp *dp); void zynqmp_dp_disable_vblank(struct zynqmp_dp *dp); -int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm); +int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub); void zynqmp_dp_remove(struct zynqmp_dpsub *dpsub); #endif /* _ZYNQMP_DP_H_ */ diff --git a/drivers/gpu/drm/xlnx/zynqmp_dpsub.c b/drivers/gpu/drm/xlnx/zynqmp_dpsub.c index 5d61f6c7aee5..6a6fba28fd6f 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dpsub.c +++ b/drivers/gpu/drm/xlnx/zynqmp_dpsub.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -247,6 +248,14 @@ static int zynqmp_dpsub_init_clocks(struct zynqmp_dpsub *dpsub) return 0; } +static void zynqmp_dpsub_release(struct drm_device *drm, void *res) +{ + struct zynqmp_dpsub *dpsub = res; + + kfree(dpsub->disp); + kfree(dpsub->dp); +} + static int zynqmp_dpsub_probe(struct platform_device *pdev) { struct zynqmp_dpsub *dpsub; @@ -258,6 +267,10 @@ static int zynqmp_dpsub_probe(struct platform_device *pdev) if (IS_ERR(dpsub)) return PTR_ERR(dpsub); + ret = drmm_add_action(&dpsub->drm, zynqmp_dpsub_release, dpsub); + if (ret < 0) + return ret; + dpsub->dev = &pdev->dev; platform_set_drvdata(pdev, dpsub); @@ -276,11 +289,11 @@ static int zynqmp_dpsub_probe(struct platform_device *pdev) * DP should be probed first so that the zynqmp_disp can set the output * format accordingly. */ - ret = zynqmp_dp_probe(dpsub, &dpsub->drm); + ret = zynqmp_dp_probe(dpsub); if (ret) goto err_pm; - ret = zynqmp_disp_probe(dpsub, &dpsub->drm); + ret = zynqmp_disp_probe(dpsub); if (ret) goto err_dp; -- cgit From 074ef0ce9f8300697e6dc1f423124cc2e73d1eb5 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Aug 2021 14:29:52 +0300 Subject: drm: xlnx: zynqmp_dpsub: Move all DRM init and cleanup to zynqmp_kms.c Continue the isolation of DRM/KMS code by moving all DRM init and cleanup from zynqmp_dpsub.c to zynqmp_kms.c. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/xlnx/zynqmp_dpsub.c | 117 +--------------------------------- drivers/gpu/drm/xlnx/zynqmp_dpsub.h | 5 -- drivers/gpu/drm/xlnx/zynqmp_kms.c | 123 +++++++++++++++++++++++++++++++++++- drivers/gpu/drm/xlnx/zynqmp_kms.h | 5 +- 4 files changed, 127 insertions(+), 123 deletions(-) diff --git a/drivers/gpu/drm/xlnx/zynqmp_dpsub.c b/drivers/gpu/drm/xlnx/zynqmp_dpsub.c index 6a6fba28fd6f..946f58124e6f 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dpsub.c +++ b/drivers/gpu/drm/xlnx/zynqmp_dpsub.c @@ -18,126 +18,16 @@ #include #include -#include -#include #include -#include -#include -#include -#include #include -#include +#include #include -#include -#include #include "zynqmp_disp.h" #include "zynqmp_dp.h" #include "zynqmp_dpsub.h" #include "zynqmp_kms.h" -/* ----------------------------------------------------------------------------- - * Dumb Buffer & Framebuffer Allocation - */ - -static int zynqmp_dpsub_dumb_create(struct drm_file *file_priv, - struct drm_device *drm, - struct drm_mode_create_dumb *args) -{ - struct zynqmp_dpsub *dpsub = to_zynqmp_dpsub(drm); - unsigned int pitch = DIV_ROUND_UP(args->width * args->bpp, 8); - - /* Enforce the alignment constraints of the DMA engine. */ - args->pitch = ALIGN(pitch, dpsub->dma_align); - - return drm_gem_dma_dumb_create_internal(file_priv, drm, args); -} - -static struct drm_framebuffer * -zynqmp_dpsub_fb_create(struct drm_device *drm, struct drm_file *file_priv, - const struct drm_mode_fb_cmd2 *mode_cmd) -{ - struct zynqmp_dpsub *dpsub = to_zynqmp_dpsub(drm); - struct drm_mode_fb_cmd2 cmd = *mode_cmd; - unsigned int i; - - /* Enforce the alignment constraints of the DMA engine. */ - for (i = 0; i < ARRAY_SIZE(cmd.pitches); ++i) - cmd.pitches[i] = ALIGN(cmd.pitches[i], dpsub->dma_align); - - return drm_gem_fb_create(drm, file_priv, &cmd); -} - -static const struct drm_mode_config_funcs zynqmp_dpsub_mode_config_funcs = { - .fb_create = zynqmp_dpsub_fb_create, - .atomic_check = drm_atomic_helper_check, - .atomic_commit = drm_atomic_helper_commit, -}; - -/* ----------------------------------------------------------------------------- - * DRM/KMS Driver - */ - -DEFINE_DRM_GEM_DMA_FOPS(zynqmp_dpsub_drm_fops); - -static const struct drm_driver zynqmp_dpsub_drm_driver = { - .driver_features = DRIVER_MODESET | DRIVER_GEM | - DRIVER_ATOMIC, - - DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE(zynqmp_dpsub_dumb_create), - - .fops = &zynqmp_dpsub_drm_fops, - - .name = "zynqmp-dpsub", - .desc = "Xilinx DisplayPort Subsystem Driver", - .date = "20130509", - .major = 1, - .minor = 0, -}; - -static int zynqmp_dpsub_drm_init(struct zynqmp_dpsub *dpsub) -{ - struct drm_device *drm = &dpsub->drm; - int ret; - - /* Initialize mode config, vblank and the KMS poll helper. */ - ret = drmm_mode_config_init(drm); - if (ret < 0) - return ret; - - drm->mode_config.funcs = &zynqmp_dpsub_mode_config_funcs; - drm->mode_config.min_width = 0; - drm->mode_config.min_height = 0; - drm->mode_config.max_width = ZYNQMP_DISP_MAX_WIDTH; - drm->mode_config.max_height = ZYNQMP_DISP_MAX_HEIGHT; - - ret = drm_vblank_init(drm, 1); - if (ret) - return ret; - - drm_kms_helper_poll_init(drm); - - ret = zynqmp_dpsub_kms_init(dpsub); - if (ret < 0) - goto err_poll_fini; - - /* Reset all components and register the DRM device. */ - drm_mode_config_reset(drm); - - ret = drm_dev_register(drm, 0); - if (ret < 0) - goto err_poll_fini; - - /* Initialize fbdev generic emulation. */ - drm_fbdev_generic_setup(drm, 24); - - return 0; - -err_poll_fini: - drm_kms_helper_poll_fini(drm); - return ret; -} - /* ----------------------------------------------------------------------------- * Power Management */ @@ -320,11 +210,8 @@ err_mem: static int zynqmp_dpsub_remove(struct platform_device *pdev) { struct zynqmp_dpsub *dpsub = platform_get_drvdata(pdev); - struct drm_device *drm = &dpsub->drm; - drm_dev_unregister(drm); - drm_atomic_helper_shutdown(drm); - drm_kms_helper_poll_fini(drm); + zynqmp_dpsub_drm_cleanup(dpsub); zynqmp_disp_remove(dpsub); zynqmp_dp_remove(dpsub); diff --git a/drivers/gpu/drm/xlnx/zynqmp_dpsub.h b/drivers/gpu/drm/xlnx/zynqmp_dpsub.h index bad9148d2d3e..012dd05cf7bb 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dpsub.h +++ b/drivers/gpu/drm/xlnx/zynqmp_dpsub.h @@ -72,11 +72,6 @@ struct zynqmp_dpsub { unsigned int dma_align; }; -static inline struct zynqmp_dpsub *to_zynqmp_dpsub(struct drm_device *drm) -{ - return container_of(drm, struct zynqmp_dpsub, drm); -} - bool zynqmp_dpsub_audio_enabled(struct zynqmp_dpsub *dpsub); unsigned int zynqmp_dpsub_get_audio_clk_rate(struct zynqmp_dpsub *dpsub); diff --git a/drivers/gpu/drm/xlnx/zynqmp_kms.c b/drivers/gpu/drm/xlnx/zynqmp_kms.c index 3b89097a2c6e..7e59f306d689 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_kms.c +++ b/drivers/gpu/drm/xlnx/zynqmp_kms.c @@ -16,12 +16,19 @@ #include #include #include +#include +#include #include +#include #include #include +#include +#include #include +#include #include #include +#include #include #include @@ -35,6 +42,11 @@ #include "zynqmp_dpsub.h" #include "zynqmp_kms.h" +static inline struct zynqmp_dpsub *to_zynqmp_dpsub(struct drm_device *drm) +{ + return container_of(drm, struct zynqmp_dpsub, drm); +} + /* ----------------------------------------------------------------------------- * DRM Planes */ @@ -339,10 +351,65 @@ void zynqmp_dpsub_handle_vblank(struct zynqmp_dpsub *dpsub) } /* ----------------------------------------------------------------------------- - * Initialization + * Dumb Buffer & Framebuffer Allocation */ -int zynqmp_dpsub_kms_init(struct zynqmp_dpsub *dpsub) +static int zynqmp_dpsub_dumb_create(struct drm_file *file_priv, + struct drm_device *drm, + struct drm_mode_create_dumb *args) +{ + struct zynqmp_dpsub *dpsub = to_zynqmp_dpsub(drm); + unsigned int pitch = DIV_ROUND_UP(args->width * args->bpp, 8); + + /* Enforce the alignment constraints of the DMA engine. */ + args->pitch = ALIGN(pitch, dpsub->dma_align); + + return drm_gem_dma_dumb_create_internal(file_priv, drm, args); +} + +static struct drm_framebuffer * +zynqmp_dpsub_fb_create(struct drm_device *drm, struct drm_file *file_priv, + const struct drm_mode_fb_cmd2 *mode_cmd) +{ + struct zynqmp_dpsub *dpsub = to_zynqmp_dpsub(drm); + struct drm_mode_fb_cmd2 cmd = *mode_cmd; + unsigned int i; + + /* Enforce the alignment constraints of the DMA engine. */ + for (i = 0; i < ARRAY_SIZE(cmd.pitches); ++i) + cmd.pitches[i] = ALIGN(cmd.pitches[i], dpsub->dma_align); + + return drm_gem_fb_create(drm, file_priv, &cmd); +} + +static const struct drm_mode_config_funcs zynqmp_dpsub_mode_config_funcs = { + .fb_create = zynqmp_dpsub_fb_create, + .atomic_check = drm_atomic_helper_check, + .atomic_commit = drm_atomic_helper_commit, +}; + +/* ----------------------------------------------------------------------------- + * DRM/KMS Driver + */ + +DEFINE_DRM_GEM_DMA_FOPS(zynqmp_dpsub_drm_fops); + +const struct drm_driver zynqmp_dpsub_drm_driver = { + .driver_features = DRIVER_MODESET | DRIVER_GEM | + DRIVER_ATOMIC, + + DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE(zynqmp_dpsub_dumb_create), + + .fops = &zynqmp_dpsub_drm_fops, + + .name = "zynqmp-dpsub", + .desc = "Xilinx DisplayPort Subsystem Driver", + .date = "20130509", + .major = 1, + .minor = 0, +}; + +static int zynqmp_dpsub_kms_init(struct zynqmp_dpsub *dpsub) { struct drm_encoder *encoder = &dpsub->encoder; struct drm_connector *connector; @@ -385,3 +452,55 @@ int zynqmp_dpsub_kms_init(struct zynqmp_dpsub *dpsub) return 0; } + +int zynqmp_dpsub_drm_init(struct zynqmp_dpsub *dpsub) +{ + struct drm_device *drm = &dpsub->drm; + int ret; + + /* Initialize mode config, vblank and the KMS poll helper. */ + ret = drmm_mode_config_init(drm); + if (ret < 0) + return ret; + + drm->mode_config.funcs = &zynqmp_dpsub_mode_config_funcs; + drm->mode_config.min_width = 0; + drm->mode_config.min_height = 0; + drm->mode_config.max_width = ZYNQMP_DISP_MAX_WIDTH; + drm->mode_config.max_height = ZYNQMP_DISP_MAX_HEIGHT; + + ret = drm_vblank_init(drm, 1); + if (ret) + return ret; + + drm_kms_helper_poll_init(drm); + + ret = zynqmp_dpsub_kms_init(dpsub); + if (ret < 0) + goto err_poll_fini; + + /* Reset all components and register the DRM device. */ + drm_mode_config_reset(drm); + + ret = drm_dev_register(drm, 0); + if (ret < 0) + goto err_poll_fini; + + /* Initialize fbdev generic emulation. */ + drm_fbdev_generic_setup(drm, 24); + + return 0; + +err_poll_fini: + drm_kms_helper_poll_fini(drm); + return ret; +} + +void zynqmp_dpsub_drm_cleanup(struct zynqmp_dpsub *dpsub) +{ + struct drm_device *drm = &dpsub->drm; + + drm_dev_unregister(drm); + drm_atomic_helper_shutdown(drm); + drm_kms_helper_poll_fini(drm); +} diff --git a/drivers/gpu/drm/xlnx/zynqmp_kms.h b/drivers/gpu/drm/xlnx/zynqmp_kms.h index a8934b1abb05..8074148fd429 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_kms.h +++ b/drivers/gpu/drm/xlnx/zynqmp_kms.h @@ -14,8 +14,11 @@ struct zynqmp_dpsub; +extern const struct drm_driver zynqmp_dpsub_drm_driver; + void zynqmp_dpsub_handle_vblank(struct zynqmp_dpsub *dpsub); -int zynqmp_dpsub_kms_init(struct zynqmp_dpsub *dpsub); +int zynqmp_dpsub_drm_init(struct zynqmp_dpsub *dpsub); +void zynqmp_dpsub_drm_cleanup(struct zynqmp_dpsub *dpsub); #endif /* _ZYNQMP_KMS_H_ */ -- cgit From d189835fffed7fed4aec15a41eaa27190ad4e04d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Aug 2021 14:29:52 +0300 Subject: drm: xlnx: zynqmp_dpsub: Decouple DRM device from zynqmp_dpsub To complete the decoupling of the DRM device from the zynqmp_dpsub, group all DRM-related structures in a zynqmp_dpsub_drm structure and allocate it separately from the zynqmp_dpsub. The DRM managed allocation of the drm_device now doesn't cover the zynqmp_dpsub anymore, so we need to register a cleanup action to release the zynqmp_dpsub when the drm_device is released. The will allow usage of the DisplayPort encoder as a standalone bridge, without registering a DRM device in this driver. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/xlnx/zynqmp_dpsub.c | 41 +++++++++++++---------- drivers/gpu/drm/xlnx/zynqmp_dpsub.h | 18 +++------- drivers/gpu/drm/xlnx/zynqmp_kms.c | 66 ++++++++++++++++++++++++++----------- drivers/gpu/drm/xlnx/zynqmp_kms.h | 24 +++++++++++++- 4 files changed, 99 insertions(+), 50 deletions(-) diff --git a/drivers/gpu/drm/xlnx/zynqmp_dpsub.c b/drivers/gpu/drm/xlnx/zynqmp_dpsub.c index 946f58124e6f..86faa6edda4b 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dpsub.c +++ b/drivers/gpu/drm/xlnx/zynqmp_dpsub.c @@ -18,8 +18,6 @@ #include #include -#include -#include #include #include @@ -36,14 +34,20 @@ static int __maybe_unused zynqmp_dpsub_suspend(struct device *dev) { struct zynqmp_dpsub *dpsub = dev_get_drvdata(dev); - return drm_mode_config_helper_suspend(&dpsub->drm); + if (!dpsub->drm) + return 0; + + return drm_mode_config_helper_suspend(&dpsub->drm->dev); } static int __maybe_unused zynqmp_dpsub_resume(struct device *dev) { struct zynqmp_dpsub *dpsub = dev_get_drvdata(dev); - return drm_mode_config_helper_resume(&dpsub->drm); + if (!dpsub->drm) + return 0; + + return drm_mode_config_helper_resume(&dpsub->drm->dev); } static const struct dev_pm_ops zynqmp_dpsub_pm_ops = { @@ -138,12 +142,11 @@ static int zynqmp_dpsub_init_clocks(struct zynqmp_dpsub *dpsub) return 0; } -static void zynqmp_dpsub_release(struct drm_device *drm, void *res) +void zynqmp_dpsub_release(struct zynqmp_dpsub *dpsub) { - struct zynqmp_dpsub *dpsub = res; - kfree(dpsub->disp); kfree(dpsub->dp); + kfree(dpsub); } static int zynqmp_dpsub_probe(struct platform_device *pdev) @@ -152,14 +155,9 @@ static int zynqmp_dpsub_probe(struct platform_device *pdev) int ret; /* Allocate private data. */ - dpsub = devm_drm_dev_alloc(&pdev->dev, &zynqmp_dpsub_drm_driver, - struct zynqmp_dpsub, drm); - if (IS_ERR(dpsub)) - return PTR_ERR(dpsub); - - ret = drmm_add_action(&dpsub->drm, zynqmp_dpsub_release, dpsub); - if (ret < 0) - return ret; + dpsub = kzalloc(sizeof(*dpsub), GFP_KERNEL); + if (!dpsub) + return -ENOMEM; dpsub->dev = &pdev->dev; platform_set_drvdata(pdev, dpsub); @@ -204,6 +202,8 @@ err_pm: clk_disable_unprepare(dpsub->apb_clk); err_mem: of_reserved_mem_device_release(&pdev->dev); + if (!dpsub->drm) + zynqmp_dpsub_release(dpsub); return ret; } @@ -211,7 +211,8 @@ static int zynqmp_dpsub_remove(struct platform_device *pdev) { struct zynqmp_dpsub *dpsub = platform_get_drvdata(pdev); - zynqmp_dpsub_drm_cleanup(dpsub); + if (dpsub->drm) + zynqmp_dpsub_drm_cleanup(dpsub); zynqmp_disp_remove(dpsub); zynqmp_dp_remove(dpsub); @@ -220,6 +221,9 @@ static int zynqmp_dpsub_remove(struct platform_device *pdev) clk_disable_unprepare(dpsub->apb_clk); of_reserved_mem_device_release(&pdev->dev); + if (!dpsub->drm) + zynqmp_dpsub_release(dpsub); + return 0; } @@ -227,7 +231,10 @@ static void zynqmp_dpsub_shutdown(struct platform_device *pdev) { struct zynqmp_dpsub *dpsub = platform_get_drvdata(pdev); - drm_atomic_helper_shutdown(&dpsub->drm); + if (!dpsub->drm) + return; + + drm_atomic_helper_shutdown(&dpsub->drm->dev); } static const struct of_device_id zynqmp_dpsub_of_match[] = { diff --git a/drivers/gpu/drm/xlnx/zynqmp_dpsub.h b/drivers/gpu/drm/xlnx/zynqmp_dpsub.h index 012dd05cf7bb..6c6029ad9bc5 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dpsub.h +++ b/drivers/gpu/drm/xlnx/zynqmp_dpsub.h @@ -12,17 +12,13 @@ #ifndef _ZYNQMP_DPSUB_H_ #define _ZYNQMP_DPSUB_H_ -#include -#include -#include - struct clk; struct device; struct drm_bridge; -struct drm_device; struct zynqmp_disp; struct zynqmp_disp_layer; struct zynqmp_dp; +struct zynqmp_dpsub_drm; #define ZYNQMP_DPSUB_NUM_LAYERS 2 @@ -35,23 +31,19 @@ enum zynqmp_dpsub_format { /** * struct zynqmp_dpsub - ZynqMP DisplayPort Subsystem - * @drm: The DRM/KMS device * @dev: The physical device * @apb_clk: The APB clock * @vid_clk: Video clock * @vid_clk_from_ps: True of the video clock comes from PS, false from PL * @aud_clk: Audio clock * @aud_clk_from_ps: True of the audio clock comes from PS, false from PL - * @planes: The DRM planes - * @crtc: The DRM CRTC - * @encoder: The dummy DRM encoder + * @drm: The DRM/KMS device data * @bridge: The DP encoder bridge * @disp: The display controller * @dp: The DisplayPort controller * @dma_align: DMA alignment constraint (must be a power of 2) */ struct zynqmp_dpsub { - struct drm_device drm; struct device *dev; struct clk *apb_clk; @@ -60,9 +52,7 @@ struct zynqmp_dpsub { struct clk *aud_clk; bool aud_clk_from_ps; - struct drm_plane planes[ZYNQMP_DPSUB_NUM_LAYERS]; - struct drm_crtc crtc; - struct drm_encoder encoder; + struct zynqmp_dpsub_drm *drm; struct drm_bridge *bridge; struct zynqmp_disp *disp; @@ -75,4 +65,6 @@ struct zynqmp_dpsub { bool zynqmp_dpsub_audio_enabled(struct zynqmp_dpsub *dpsub); unsigned int zynqmp_dpsub_get_audio_clk_rate(struct zynqmp_dpsub *dpsub); +void zynqmp_dpsub_release(struct zynqmp_dpsub *dpsub); + #endif /* _ZYNQMP_DPSUB_H_ */ diff --git a/drivers/gpu/drm/xlnx/zynqmp_kms.c b/drivers/gpu/drm/xlnx/zynqmp_kms.c index 7e59f306d689..1ac81807f4fd 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_kms.c +++ b/drivers/gpu/drm/xlnx/zynqmp_kms.c @@ -44,7 +44,7 @@ static inline struct zynqmp_dpsub *to_zynqmp_dpsub(struct drm_device *drm) { - return container_of(drm, struct zynqmp_dpsub, drm); + return container_of(drm, struct zynqmp_dpsub_drm, dev)->dpsub; } /* ----------------------------------------------------------------------------- @@ -146,9 +146,9 @@ static int zynqmp_dpsub_create_planes(struct zynqmp_dpsub *dpsub) unsigned int i; int ret; - for (i = 0; i < ARRAY_SIZE(dpsub->planes); i++) { + for (i = 0; i < ARRAY_SIZE(dpsub->drm->planes); i++) { struct zynqmp_disp_layer *layer = dpsub->layers[i]; - struct drm_plane *plane = &dpsub->planes[i]; + struct drm_plane *plane = &dpsub->drm->planes[i]; enum drm_plane_type type; unsigned int num_formats; u32 *formats; @@ -160,7 +160,7 @@ static int zynqmp_dpsub_create_planes(struct zynqmp_dpsub *dpsub) /* Graphics layer is primary, and video layer is overlay. */ type = i == ZYNQMP_DPSUB_LAYER_VID ? DRM_PLANE_TYPE_OVERLAY : DRM_PLANE_TYPE_PRIMARY; - ret = drm_universal_plane_init(&dpsub->drm, plane, 0, + ret = drm_universal_plane_init(&dpsub->drm->dev, plane, 0, &zynqmp_dpsub_plane_funcs, formats, num_formats, NULL, type, NULL); @@ -184,7 +184,7 @@ static int zynqmp_dpsub_create_planes(struct zynqmp_dpsub *dpsub) static inline struct zynqmp_dpsub *crtc_to_dpsub(struct drm_crtc *crtc) { - return container_of(crtc, struct zynqmp_dpsub, crtc); + return container_of(crtc, struct zynqmp_dpsub_drm, crtc)->dpsub; } static void zynqmp_dpsub_crtc_atomic_enable(struct drm_crtc *crtc, @@ -312,11 +312,11 @@ static const struct drm_crtc_funcs zynqmp_dpsub_crtc_funcs = { static int zynqmp_dpsub_create_crtc(struct zynqmp_dpsub *dpsub) { - struct drm_plane *plane = &dpsub->planes[ZYNQMP_DPSUB_LAYER_GFX]; - struct drm_crtc *crtc = &dpsub->crtc; + struct drm_plane *plane = &dpsub->drm->planes[ZYNQMP_DPSUB_LAYER_GFX]; + struct drm_crtc *crtc = &dpsub->drm->crtc; int ret; - ret = drm_crtc_init_with_planes(&dpsub->drm, crtc, plane, + ret = drm_crtc_init_with_planes(&dpsub->drm->dev, crtc, plane, NULL, &zynqmp_dpsub_crtc_funcs, NULL); if (ret < 0) return ret; @@ -331,11 +331,11 @@ static int zynqmp_dpsub_create_crtc(struct zynqmp_dpsub *dpsub) static void zynqmp_dpsub_map_crtc_to_plane(struct zynqmp_dpsub *dpsub) { - u32 possible_crtcs = drm_crtc_mask(&dpsub->crtc); + u32 possible_crtcs = drm_crtc_mask(&dpsub->drm->crtc); unsigned int i; - for (i = 0; i < ARRAY_SIZE(dpsub->planes); i++) - dpsub->planes[i].possible_crtcs = possible_crtcs; + for (i = 0; i < ARRAY_SIZE(dpsub->drm->planes); i++) + dpsub->drm->planes[i].possible_crtcs = possible_crtcs; } /** @@ -347,7 +347,7 @@ static void zynqmp_dpsub_map_crtc_to_plane(struct zynqmp_dpsub *dpsub) */ void zynqmp_dpsub_handle_vblank(struct zynqmp_dpsub *dpsub) { - drm_crtc_handle_vblank(&dpsub->crtc); + drm_crtc_handle_vblank(&dpsub->drm->crtc); } /* ----------------------------------------------------------------------------- @@ -394,7 +394,7 @@ static const struct drm_mode_config_funcs zynqmp_dpsub_mode_config_funcs = { DEFINE_DRM_GEM_DMA_FOPS(zynqmp_dpsub_drm_fops); -const struct drm_driver zynqmp_dpsub_drm_driver = { +static const struct drm_driver zynqmp_dpsub_drm_driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC, @@ -411,7 +411,7 @@ const struct drm_driver zynqmp_dpsub_drm_driver = { static int zynqmp_dpsub_kms_init(struct zynqmp_dpsub *dpsub) { - struct drm_encoder *encoder = &dpsub->encoder; + struct drm_encoder *encoder = &dpsub->drm->encoder; struct drm_connector *connector; int ret; @@ -427,8 +427,8 @@ static int zynqmp_dpsub_kms_init(struct zynqmp_dpsub *dpsub) zynqmp_dpsub_map_crtc_to_plane(dpsub); /* Create the encoder and attach the bridge. */ - encoder->possible_crtcs |= drm_crtc_mask(&dpsub->crtc); - drm_simple_encoder_init(&dpsub->drm, encoder, DRM_MODE_ENCODER_NONE); + encoder->possible_crtcs |= drm_crtc_mask(&dpsub->drm->crtc); + drm_simple_encoder_init(&dpsub->drm->dev, encoder, DRM_MODE_ENCODER_NONE); ret = drm_bridge_attach(encoder, dpsub->bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR); @@ -438,7 +438,7 @@ static int zynqmp_dpsub_kms_init(struct zynqmp_dpsub *dpsub) } /* Create the connector for the chain of bridges. */ - connector = drm_bridge_connector_init(&dpsub->drm, encoder); + connector = drm_bridge_connector_init(&dpsub->drm->dev, encoder); if (IS_ERR(connector)) { dev_err(dpsub->dev, "failed to created connector\n"); return PTR_ERR(connector); @@ -453,11 +453,39 @@ static int zynqmp_dpsub_kms_init(struct zynqmp_dpsub *dpsub) return 0; } +static void zynqmp_dpsub_drm_release(struct drm_device *drm, void *res) +{ + struct zynqmp_dpsub_drm *dpdrm = res; + + zynqmp_dpsub_release(dpdrm->dpsub); +} + int zynqmp_dpsub_drm_init(struct zynqmp_dpsub *dpsub) { - struct drm_device *drm = &dpsub->drm; + struct zynqmp_dpsub_drm *dpdrm; + struct drm_device *drm; int ret; + /* + * Allocate the drm_device and immediately add a cleanup action to + * release the zynqmp_dpsub instance. If any of those operations fail, + * dpsub->drm will remain NULL, which tells the caller that it must + * cleanup manually. + */ + dpdrm = devm_drm_dev_alloc(dpsub->dev, &zynqmp_dpsub_drm_driver, + struct zynqmp_dpsub_drm, dev); + if (IS_ERR(dpdrm)) + return PTR_ERR(dpdrm); + + dpdrm->dpsub = dpsub; + drm = &dpdrm->dev; + + ret = drmm_add_action(drm, zynqmp_dpsub_drm_release, dpdrm); + if (ret < 0) + return ret; + + dpsub->drm = dpdrm; + /* Initialize mode config, vblank and the KMS poll helper. */ ret = drmm_mode_config_init(drm); if (ret < 0) @@ -498,7 +526,7 @@ err_poll_fini: void zynqmp_dpsub_drm_cleanup(struct zynqmp_dpsub *dpsub) { - struct drm_device *drm = &dpsub->drm; + struct drm_device *drm = &dpsub->drm->dev; drm_dev_unregister(drm); drm_atomic_helper_shutdown(drm); diff --git a/drivers/gpu/drm/xlnx/zynqmp_kms.h b/drivers/gpu/drm/xlnx/zynqmp_kms.h index 8074148fd429..b5cb27159162 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_kms.h +++ b/drivers/gpu/drm/xlnx/zynqmp_kms.h @@ -12,9 +12,31 @@ #ifndef _ZYNQMP_KMS_H_ #define _ZYNQMP_KMS_H_ +#include +#include +#include +#include + +#include "zynqmp_dpsub.h" + struct zynqmp_dpsub; -extern const struct drm_driver zynqmp_dpsub_drm_driver; +/** + * struct zynqmp_dpsub - ZynqMP DisplayPort Subsystem DRM/KMS data + * @dpsub: Backpointer to the DisplayPort subsystem + * @drm: The DRM/KMS device + * @planes: The DRM planes + * @crtc: The DRM CRTC + * @encoder: The dummy DRM encoder + */ +struct zynqmp_dpsub_drm { + struct zynqmp_dpsub *dpsub; + + struct drm_device dev; + struct drm_plane planes[ZYNQMP_DPSUB_NUM_LAYERS]; + struct drm_crtc crtc; + struct drm_encoder encoder; +}; void zynqmp_dpsub_handle_vblank(struct zynqmp_dpsub *dpsub); -- cgit From 4ce6ecd499749177b361d164849bd34924b7b3b7 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Aug 2021 14:29:52 +0300 Subject: drm: xlnx: zynqmp_dpsub: Rename zynqmp_dpsub_handle_vblank with DRM prefix The better convey its purpose, rename the zynqmp_dpsub_handle_vblank() function that belongs to the DRM layer to zynqmp_dpsub_drm_handle_vblank(). Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/xlnx/zynqmp_dp.c | 2 +- drivers/gpu/drm/xlnx/zynqmp_kms.c | 4 ++-- drivers/gpu/drm/xlnx/zynqmp_kms.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c index 001bc24f92bd..5424f955be28 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c @@ -1581,7 +1581,7 @@ static irqreturn_t zynqmp_dp_irq_handler(int irq, void *data) zynqmp_dp_write(dp, ZYNQMP_DP_INT_STATUS, status); if (status & ZYNQMP_DP_INT_VBLANK_START) - zynqmp_dpsub_handle_vblank(dp->dpsub); + zynqmp_dpsub_drm_handle_vblank(dp->dpsub); if (status & ZYNQMP_DP_INT_HPD_EVENT) schedule_delayed_work(&dp->hpd_work, 0); diff --git a/drivers/gpu/drm/xlnx/zynqmp_kms.c b/drivers/gpu/drm/xlnx/zynqmp_kms.c index 1ac81807f4fd..ff53a5ae8103 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_kms.c +++ b/drivers/gpu/drm/xlnx/zynqmp_kms.c @@ -339,13 +339,13 @@ static void zynqmp_dpsub_map_crtc_to_plane(struct zynqmp_dpsub *dpsub) } /** - * zynqmp_dpsub_handle_vblank - Handle the vblank event + * zynqmp_dpsub_drm_handle_vblank - Handle the vblank event * @dpsub: DisplayPort subsystem * * This function handles the vblank interrupt, and sends an event to * CRTC object. This will be called by the DP vblank interrupt handler. */ -void zynqmp_dpsub_handle_vblank(struct zynqmp_dpsub *dpsub) +void zynqmp_dpsub_drm_handle_vblank(struct zynqmp_dpsub *dpsub) { drm_crtc_handle_vblank(&dpsub->drm->crtc); } diff --git a/drivers/gpu/drm/xlnx/zynqmp_kms.h b/drivers/gpu/drm/xlnx/zynqmp_kms.h index b5cb27159162..01be96b00e3f 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_kms.h +++ b/drivers/gpu/drm/xlnx/zynqmp_kms.h @@ -38,7 +38,7 @@ struct zynqmp_dpsub_drm { struct drm_encoder encoder; }; -void zynqmp_dpsub_handle_vblank(struct zynqmp_dpsub *dpsub); +void zynqmp_dpsub_drm_handle_vblank(struct zynqmp_dpsub *dpsub); int zynqmp_dpsub_drm_init(struct zynqmp_dpsub *dpsub); void zynqmp_dpsub_drm_cleanup(struct zynqmp_dpsub *dpsub); -- cgit From 52c2cf1471b35eda9a29c8dfdee5c687909e126a Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Aug 2021 14:29:52 +0300 Subject: drm: xlnx: zynqmp_dpsub: Parse DT to find connected ports To prepare for live video input support, parse the device tree to find the connected ports. Warn about unsupported configurations, and error out when invalid. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/xlnx/zynqmp_dpsub.c | 54 +++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/xlnx/zynqmp_dpsub.h | 13 +++++++++ 2 files changed, 67 insertions(+) diff --git a/drivers/gpu/drm/xlnx/zynqmp_dpsub.c b/drivers/gpu/drm/xlnx/zynqmp_dpsub.c index 86faa6edda4b..6627a1ec7791 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dpsub.c +++ b/drivers/gpu/drm/xlnx/zynqmp_dpsub.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -142,6 +143,55 @@ static int zynqmp_dpsub_init_clocks(struct zynqmp_dpsub *dpsub) return 0; } +static int zynqmp_dpsub_parse_dt(struct zynqmp_dpsub *dpsub) +{ + struct device_node *np; + unsigned int i; + + /* + * For backward compatibility with old device trees that don't contain + * ports, consider that only the DP output port is connected if no + * ports child no exists. + */ + np = of_get_child_by_name(dpsub->dev->of_node, "ports"); + of_node_put(np); + if (!np) { + dev_warn(dpsub->dev, "missing ports, update DT bindings\n"); + dpsub->connected_ports = BIT(ZYNQMP_DPSUB_PORT_OUT_DP); + return 0; + } + + /* Check which ports are connected. */ + for (i = 0; i < ZYNQMP_DPSUB_NUM_PORTS; ++i) { + struct device_node *np; + + np = of_graph_get_remote_node(dpsub->dev->of_node, i, -1); + if (np) { + dpsub->connected_ports |= BIT(i); + of_node_put(np); + } + } + + /* Sanity checks. */ + if ((dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_VIDEO)) || + (dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_GFX))) + dev_warn(dpsub->dev, "live video unsupported, ignoring\n"); + + if (dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_AUDIO)) + dev_warn(dpsub->dev, "live audio unsupported, ignoring\n"); + + if ((dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_OUT_VIDEO)) || + (dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_OUT_AUDIO))) + dev_warn(dpsub->dev, "output to PL unsupported, ignoring\n"); + + if (!(dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_OUT_DP))) { + dev_err(dpsub->dev, "DP output port not connected\n"); + return -EINVAL; + } + + return 0; +} + void zynqmp_dpsub_release(struct zynqmp_dpsub *dpsub) { kfree(dpsub->disp); @@ -171,6 +221,10 @@ static int zynqmp_dpsub_probe(struct platform_device *pdev) if (ret < 0) goto err_mem; + ret = zynqmp_dpsub_parse_dt(dpsub); + if (ret < 0) + goto err_mem; + pm_runtime_enable(&pdev->dev); /* diff --git a/drivers/gpu/drm/xlnx/zynqmp_dpsub.h b/drivers/gpu/drm/xlnx/zynqmp_dpsub.h index 6c6029ad9bc5..6ded6e45ac0a 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dpsub.h +++ b/drivers/gpu/drm/xlnx/zynqmp_dpsub.h @@ -22,6 +22,16 @@ struct zynqmp_dpsub_drm; #define ZYNQMP_DPSUB_NUM_LAYERS 2 +enum zynqmp_dpsub_port { + ZYNQMP_DPSUB_PORT_LIVE_VIDEO, + ZYNQMP_DPSUB_PORT_LIVE_GFX, + ZYNQMP_DPSUB_PORT_LIVE_AUDIO, + ZYNQMP_DPSUB_PORT_OUT_VIDEO, + ZYNQMP_DPSUB_PORT_OUT_AUDIO, + ZYNQMP_DPSUB_PORT_OUT_DP, + ZYNQMP_DPSUB_NUM_PORTS, +}; + enum zynqmp_dpsub_format { ZYNQMP_DPSUB_FORMAT_RGB, ZYNQMP_DPSUB_FORMAT_YCRCB444, @@ -37,6 +47,7 @@ enum zynqmp_dpsub_format { * @vid_clk_from_ps: True of the video clock comes from PS, false from PL * @aud_clk: Audio clock * @aud_clk_from_ps: True of the audio clock comes from PS, false from PL + * @connected_ports: Bitmask of connected ports in the device tree * @drm: The DRM/KMS device data * @bridge: The DP encoder bridge * @disp: The display controller @@ -52,6 +63,8 @@ struct zynqmp_dpsub { struct clk *aud_clk; bool aud_clk_from_ps; + unsigned int connected_ports; + struct zynqmp_dpsub_drm *drm; struct drm_bridge *bridge; -- cgit From 3662bbfca5d2b83c5d549f237a8d87f69aefa46c Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Aug 2021 14:29:52 +0300 Subject: drm: xlnx: zynqmp_dpsub: Allow configuration of layer mode Add a mode parameter to the zynqmp_disp_layer_enable() to set the layer mode, to prepare for live mode support. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/xlnx/zynqmp_disp.c | 30 +++++++++--------------------- drivers/gpu/drm/xlnx/zynqmp_disp.h | 13 ++++++++++++- drivers/gpu/drm/xlnx/zynqmp_kms.c | 2 +- 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c b/drivers/gpu/drm/xlnx/zynqmp_disp.c index e9d4b891fac9..e572cbb5f293 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_disp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c @@ -78,16 +78,6 @@ struct zynqmp_disp_format { const u32 *sf; }; -/** - * enum zynqmp_disp_layer_mode - Layer mode - * @ZYNQMP_DISP_LAYER_NONLIVE: non-live (memory) mode - * @ZYNQMP_DISP_LAYER_LIVE: live (stream) mode - */ -enum zynqmp_disp_layer_mode { - ZYNQMP_DISP_LAYER_NONLIVE, - ZYNQMP_DISP_LAYER_LIVE -}; - /** * struct zynqmp_disp_layer_dma - DMA channel for one data plane of a layer * @chan: DMA channel @@ -131,7 +121,7 @@ struct zynqmp_disp_layer { const struct zynqmp_disp_format *disp_fmt; const struct drm_format_info *drm_fmt; - enum zynqmp_disp_layer_mode mode; + enum zynqmp_dpsub_layer_mode mode; }; /** @@ -519,27 +509,25 @@ static void zynqmp_disp_avbuf_disable_audio(struct zynqmp_disp *disp) * zynqmp_disp_avbuf_enable_video - Enable a video layer * @disp: Display controller * @layer: The layer - * @mode: Operating mode of layer * * Enable the video/graphics buffer for @layer. */ static void zynqmp_disp_avbuf_enable_video(struct zynqmp_disp *disp, - struct zynqmp_disp_layer *layer, - enum zynqmp_disp_layer_mode mode) + struct zynqmp_disp_layer *layer) { u32 val; val = zynqmp_disp_avbuf_read(disp, ZYNQMP_DISP_AV_BUF_OUTPUT); if (zynqmp_disp_layer_is_video(layer)) { val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_MASK; - if (mode == ZYNQMP_DISP_LAYER_NONLIVE) + if (layer->mode == ZYNQMP_DPSUB_LAYER_NONLIVE) val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_MEM; else val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_LIVE; } else { val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_MASK; val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_MEM; - if (mode == ZYNQMP_DISP_LAYER_NONLIVE) + if (layer->mode == ZYNQMP_DPSUB_LAYER_NONLIVE) val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_MEM; else val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_LIVE; @@ -914,17 +902,17 @@ u32 *zynqmp_disp_layer_drm_formats(struct zynqmp_disp_layer *layer, /** * zynqmp_disp_layer_enable - Enable a layer * @layer: The layer + * @mode: Operating mode of layer * * Enable the @layer in the audio/video buffer manager and the blender. DMA * channels are started separately by zynqmp_disp_layer_update(). */ -void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer) +void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer, + enum zynqmp_dpsub_layer_mode mode) { - zynqmp_disp_avbuf_enable_video(layer->disp, layer, - ZYNQMP_DISP_LAYER_NONLIVE); + layer->mode = mode; + zynqmp_disp_avbuf_enable_video(layer->disp, layer); zynqmp_disp_blend_layer_enable(layer->disp, layer); - - layer->mode = ZYNQMP_DISP_LAYER_NONLIVE; } /** diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.h b/drivers/gpu/drm/xlnx/zynqmp_disp.h index 9b8b202224d9..123cffac08be 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_disp.h +++ b/drivers/gpu/drm/xlnx/zynqmp_disp.h @@ -42,6 +42,16 @@ enum zynqmp_dpsub_layer_id { ZYNQMP_DPSUB_LAYER_GFX, }; +/** + * enum zynqmp_dpsub_layer_mode - Layer mode + * @ZYNQMP_DPSUB_LAYER_NONLIVE: non-live (memory) mode + * @ZYNQMP_DPSUB_LAYER_LIVE: live (stream) mode + */ +enum zynqmp_dpsub_layer_mode { + ZYNQMP_DPSUB_LAYER_NONLIVE, + ZYNQMP_DPSUB_LAYER_LIVE, +}; + void zynqmp_disp_enable(struct zynqmp_disp *disp); void zynqmp_disp_disable(struct zynqmp_disp *disp); int zynqmp_disp_setup_clock(struct zynqmp_disp *disp, @@ -52,7 +62,8 @@ void zynqmp_disp_blend_set_global_alpha(struct zynqmp_disp *disp, u32 *zynqmp_disp_layer_drm_formats(struct zynqmp_disp_layer *layer, unsigned int *num_formats); -void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer); +void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer, + enum zynqmp_dpsub_layer_mode mode); void zynqmp_disp_layer_disable(struct zynqmp_disp_layer *layer); void zynqmp_disp_layer_set_format(struct zynqmp_disp_layer *layer, const struct drm_format_info *info); diff --git a/drivers/gpu/drm/xlnx/zynqmp_kms.c b/drivers/gpu/drm/xlnx/zynqmp_kms.c index ff53a5ae8103..1847792cf13d 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_kms.c +++ b/drivers/gpu/drm/xlnx/zynqmp_kms.c @@ -123,7 +123,7 @@ static void zynqmp_dpsub_plane_atomic_update(struct drm_plane *plane, /* Enable or re-enable the plane if the format has changed. */ if (format_changed) - zynqmp_disp_layer_enable(layer); + zynqmp_disp_layer_enable(layer, ZYNQMP_DPSUB_LAYER_NONLIVE); } static const struct drm_plane_helper_funcs zynqmp_dpsub_plane_helper_funcs = { -- cgit From 51ae3bd4f0577d250c2b95f58fa93e7937136498 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Aug 2021 14:29:52 +0300 Subject: drm: xlnx: zynqmp_dpsub: Support operation without DMA engine To prepare for usage of the DPSUB as a DisplayPort bridge without creating a DRM device, make initialization and usage of the DMA engine optional. The flag that controls this feature is currently hardcoded to operating with the DMA engine, this will be made dynamic based on the device tree configuration in a subsequent change. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/xlnx/zynqmp_disp.c | 26 ++++++++++++++++++++------ drivers/gpu/drm/xlnx/zynqmp_dpsub.c | 3 +++ drivers/gpu/drm/xlnx/zynqmp_dpsub.h | 3 +++ 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c b/drivers/gpu/drm/xlnx/zynqmp_disp.c index e572cbb5f293..3b87eebddc97 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_disp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c @@ -926,8 +926,10 @@ void zynqmp_disp_layer_disable(struct zynqmp_disp_layer *layer) { unsigned int i; - for (i = 0; i < layer->drm_fmt->num_planes; i++) - dmaengine_terminate_sync(layer->dmas[i].chan); + if (layer->disp->dpsub->dma_enabled) { + for (i = 0; i < layer->drm_fmt->num_planes; i++) + dmaengine_terminate_sync(layer->dmas[i].chan); + } zynqmp_disp_avbuf_disable_video(layer->disp, layer); zynqmp_disp_blend_layer_disable(layer->disp, layer); @@ -950,6 +952,9 @@ void zynqmp_disp_layer_set_format(struct zynqmp_disp_layer *layer, zynqmp_disp_avbuf_set_format(layer->disp, layer, layer->disp_fmt); + if (!layer->disp->dpsub->dma_enabled) + return; + /* * Set pconfig for each DMA channel to indicate they're part of a * video group. @@ -985,6 +990,9 @@ int zynqmp_disp_layer_update(struct zynqmp_disp_layer *layer, const struct drm_format_info *info = layer->drm_fmt; unsigned int i; + if (!layer->disp->dpsub->dma_enabled) + return 0; + for (i = 0; i < info->num_planes; i++) { unsigned int width = state->crtc_w / (i ? info->hsub : 1); unsigned int height = state->crtc_h / (i ? info->vsub : 1); @@ -1032,7 +1040,7 @@ static void zynqmp_disp_layer_release_dma(struct zynqmp_disp *disp, { unsigned int i; - if (!layer->info) + if (!layer->info || !disp->dpsub->dma_enabled) return; for (i = 0; i < layer->info->num_channels; i++) { @@ -1075,6 +1083,9 @@ static int zynqmp_disp_layer_request_dma(struct zynqmp_disp *disp, unsigned int i; int ret; + if (!disp->dpsub->dma_enabled) + return 0; + for (i = 0; i < layer->info->num_channels; i++) { struct zynqmp_disp_layer_dma *dma = &layer->dmas[i]; char dma_channel_name[16]; @@ -1217,7 +1228,6 @@ int zynqmp_disp_probe(struct zynqmp_dpsub *dpsub) { struct platform_device *pdev = to_platform_device(dpsub->dev); struct zynqmp_disp *disp; - struct zynqmp_disp_layer *layer; struct resource *res; int ret; @@ -1253,8 +1263,12 @@ int zynqmp_disp_probe(struct zynqmp_dpsub *dpsub) if (ret) goto error; - layer = &disp->layers[ZYNQMP_DPSUB_LAYER_VID]; - dpsub->dma_align = 1 << layer->dmas[0].chan->device->copy_align; + if (disp->dpsub->dma_enabled) { + struct zynqmp_disp_layer *layer; + + layer = &disp->layers[ZYNQMP_DPSUB_LAYER_VID]; + dpsub->dma_align = 1 << layer->dmas[0].chan->device->copy_align; + } dpsub->disp = disp; diff --git a/drivers/gpu/drm/xlnx/zynqmp_dpsub.c b/drivers/gpu/drm/xlnx/zynqmp_dpsub.c index 6627a1ec7791..6e4cd4479de1 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dpsub.c +++ b/drivers/gpu/drm/xlnx/zynqmp_dpsub.c @@ -158,6 +158,7 @@ static int zynqmp_dpsub_parse_dt(struct zynqmp_dpsub *dpsub) if (!np) { dev_warn(dpsub->dev, "missing ports, update DT bindings\n"); dpsub->connected_ports = BIT(ZYNQMP_DPSUB_PORT_OUT_DP); + dpsub->dma_enabled = true; return 0; } @@ -177,6 +178,8 @@ static int zynqmp_dpsub_parse_dt(struct zynqmp_dpsub *dpsub) (dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_GFX))) dev_warn(dpsub->dev, "live video unsupported, ignoring\n"); + dpsub->dma_enabled = true; + if (dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_AUDIO)) dev_warn(dpsub->dev, "live audio unsupported, ignoring\n"); diff --git a/drivers/gpu/drm/xlnx/zynqmp_dpsub.h b/drivers/gpu/drm/xlnx/zynqmp_dpsub.h index 6ded6e45ac0a..09ea01878f2a 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dpsub.h +++ b/drivers/gpu/drm/xlnx/zynqmp_dpsub.h @@ -48,6 +48,8 @@ enum zynqmp_dpsub_format { * @aud_clk: Audio clock * @aud_clk_from_ps: True of the audio clock comes from PS, false from PL * @connected_ports: Bitmask of connected ports in the device tree + * @dma_enabled: True if the DMA interface is enabled, false if the DPSUB is + * driven by the live input * @drm: The DRM/KMS device data * @bridge: The DP encoder bridge * @disp: The display controller @@ -64,6 +66,7 @@ struct zynqmp_dpsub { bool aud_clk_from_ps; unsigned int connected_ports; + bool dma_enabled; struct zynqmp_dpsub_drm *drm; struct drm_bridge *bridge; -- cgit From 56167161239472c35e902d40a13d1c6b2ff5e7c7 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Aug 2021 14:29:52 +0300 Subject: drm: xlnx: zynqmp_dpsub: Add support for live video input Add partial live video support, with a single video input that bypasses blending. Skip registration of the DRM device in that case, but register the DRM bridge instead. The DRM device will be created by the driver for the display controller in the PL. Full live video mode with concurrent usage of the video and gfx inputs, and blending in the DPSUB video pipeline, is currently unsupported. Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/xlnx/zynqmp_dp.c | 55 +++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/xlnx/zynqmp_dpsub.c | 32 ++++++++++++++++----- 2 files changed, 80 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c index 5424f955be28..7c9ae167eac7 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -1271,6 +1272,55 @@ static void zynqmp_dp_encoder_mode_set_stream(struct zynqmp_dp *dp, zynqmp_dp_write(dp, ZYNQMP_DP_USER_DATA_COUNT_PER_LANE, reg); } +/* ----------------------------------------------------------------------------- + * DISP Configuration + */ + +static void zynqmp_dp_disp_enable(struct zynqmp_dp *dp, + struct drm_bridge_state *old_bridge_state) +{ + enum zynqmp_dpsub_layer_id layer_id; + struct zynqmp_disp_layer *layer; + const struct drm_format_info *info; + + if (dp->dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_VIDEO)) + layer_id = ZYNQMP_DPSUB_LAYER_VID; + else if (dp->dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_GFX)) + layer_id = ZYNQMP_DPSUB_LAYER_GFX; + else + return; + + layer = dp->dpsub->layers[layer_id]; + + /* TODO: Make the format configurable. */ + info = drm_format_info(DRM_FORMAT_YUV422); + zynqmp_disp_layer_set_format(layer, info); + zynqmp_disp_layer_enable(layer, ZYNQMP_DPSUB_LAYER_LIVE); + + if (layer_id == ZYNQMP_DPSUB_LAYER_GFX) + zynqmp_disp_blend_set_global_alpha(dp->dpsub->disp, true, 255); + else + zynqmp_disp_blend_set_global_alpha(dp->dpsub->disp, false, 0); + + zynqmp_disp_enable(dp->dpsub->disp); +} + +static void zynqmp_dp_disp_disable(struct zynqmp_dp *dp, + struct drm_bridge_state *old_bridge_state) +{ + struct zynqmp_disp_layer *layer; + + if (dp->dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_VIDEO)) + layer = dp->dpsub->layers[ZYNQMP_DPSUB_LAYER_VID]; + else if (dp->dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_GFX)) + layer = dp->dpsub->layers[ZYNQMP_DPSUB_LAYER_GFX]; + else + return; + + zynqmp_disp_disable(dp->dpsub->disp); + zynqmp_disp_layer_disable(layer); +} + /* ----------------------------------------------------------------------------- * DRM Bridge */ @@ -1355,6 +1405,8 @@ static void zynqmp_dp_bridge_atomic_enable(struct drm_bridge *bridge, pm_runtime_get_sync(dp->dev); + zynqmp_dp_disp_enable(dp, old_bridge_state); + /* * Retrieve the CRTC mode and adjusted mode. This requires a little * dance to go from the bridge to the encoder, to the connector and to @@ -1428,6 +1480,9 @@ static void zynqmp_dp_bridge_atomic_disable(struct drm_bridge *bridge, ZYNQMP_DP_TX_PHY_POWER_DOWN_ALL); if (zynqmp_dpsub_audio_enabled(dp->dpsub)) zynqmp_dp_write(dp, ZYNQMP_DP_TX_AUDIO_CONTROL, 0); + + zynqmp_dp_disp_disable(dp, old_bridge_state); + pm_runtime_put_sync(dp->dev); } diff --git a/drivers/gpu/drm/xlnx/zynqmp_dpsub.c b/drivers/gpu/drm/xlnx/zynqmp_dpsub.c index 6e4cd4479de1..bab862484d42 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dpsub.c +++ b/drivers/gpu/drm/xlnx/zynqmp_dpsub.c @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -174,11 +175,22 @@ static int zynqmp_dpsub_parse_dt(struct zynqmp_dpsub *dpsub) } /* Sanity checks. */ - if ((dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_VIDEO)) || - (dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_GFX))) - dev_warn(dpsub->dev, "live video unsupported, ignoring\n"); + if ((dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_VIDEO)) && + (dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_GFX))) { + dev_err(dpsub->dev, "only one live video input is supported\n"); + return -EINVAL; + } - dpsub->dma_enabled = true; + if ((dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_VIDEO)) || + (dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_GFX))) { + if (dpsub->vid_clk_from_ps) { + dev_err(dpsub->dev, + "live video input requires PL clock\n"); + return -EINVAL; + } + } else { + dpsub->dma_enabled = true; + } if (dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_AUDIO)) dev_warn(dpsub->dev, "live audio unsupported, ignoring\n"); @@ -242,9 +254,13 @@ static int zynqmp_dpsub_probe(struct platform_device *pdev) if (ret) goto err_dp; - ret = zynqmp_dpsub_drm_init(dpsub); - if (ret) - goto err_disp; + if (dpsub->dma_enabled) { + ret = zynqmp_dpsub_drm_init(dpsub); + if (ret) + goto err_disp; + } else { + drm_bridge_add(dpsub->bridge); + } dev_info(&pdev->dev, "ZynqMP DisplayPort Subsystem driver probed"); @@ -270,6 +286,8 @@ static int zynqmp_dpsub_remove(struct platform_device *pdev) if (dpsub->drm) zynqmp_dpsub_drm_cleanup(dpsub); + else + drm_bridge_remove(dpsub->bridge); zynqmp_disp_remove(dpsub); zynqmp_dp_remove(dpsub); -- cgit From 7c99616e3fe7f35fe25bf6f5797267da29b4751e Mon Sep 17 00:00:00 2001 From: Zack Rusin Date: Tue, 18 Oct 2022 22:43:50 -0400 Subject: drm: Remove drm_mode_config::fb_base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The fb_base in struct drm_mode_config has been unused for a long time. Some drivers set it and some don't leading to a very confusing state where the variable can't be relied upon, because there's no indication as to which driver sets it and which doesn't. The only usage of fb_base is internal to two drivers so instead of trying to force it into all the drivers to get it into a coherent state completely remove it. Signed-off-by: Zack Rusin Reviewed-by: Laurent Pinchart Reviewed-by: Thomas Zimmermann Acked-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20221019024401.394617-1-zack@kde.org --- drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c | 2 -- drivers/gpu/drm/amd/amdgpu/dce_v10_0.c | 2 -- drivers/gpu/drm/amd/amdgpu/dce_v11_0.c | 2 -- drivers/gpu/drm/amd/amdgpu/dce_v6_0.c | 1 - drivers/gpu/drm/amd/amdgpu/dce_v8_0.c | 2 -- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 -- drivers/gpu/drm/ast/ast_mode.c | 2 -- drivers/gpu/drm/gma500/framebuffer.c | 6 +++--- drivers/gpu/drm/gma500/psb_drv.h | 1 + drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c | 16 +++------------- drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h | 3 --- drivers/gpu/drm/mgag200/mgag200_mode.c | 1 - drivers/gpu/drm/msm/msm_fbdev.c | 2 -- drivers/gpu/drm/nouveau/nouveau_display.c | 1 - drivers/gpu/drm/nouveau/nv04_fbcon.c | 6 ++++-- drivers/gpu/drm/omapdrm/omap_fbdev.c | 2 -- drivers/gpu/drm/qxl/qxl_display.c | 2 -- drivers/gpu/drm/radeon/radeon_display.c | 2 -- drivers/gpu/drm/radeon/radeon_fb.c | 2 +- drivers/gpu/drm/tegra/fb.c | 1 - drivers/gpu/drm/tiny/bochs.c | 1 - include/drm/drm_mode_config.h | 2 -- 22 files changed, 12 insertions(+), 49 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c index f4b5301ea2a0..09dec2561adf 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c @@ -498,8 +498,6 @@ static int amdgpu_vkms_sw_init(void *handle) adev_to_drm(adev)->mode_config.preferred_depth = 24; adev_to_drm(adev)->mode_config.prefer_shadow = 1; - adev_to_drm(adev)->mode_config.fb_base = adev->gmc.aper_base; - r = amdgpu_display_modeset_create_props(adev); if (r) return r; diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c index 288fce7dc0ed..05051d5d2ec3 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c @@ -2800,8 +2800,6 @@ static int dce_v10_0_sw_init(void *handle) adev_to_drm(adev)->mode_config.fb_modifiers_not_supported = true; - adev_to_drm(adev)->mode_config.fb_base = adev->gmc.aper_base; - r = amdgpu_display_modeset_create_props(adev); if (r) return r; diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c index cbe5250b31cb..c928bc9eb202 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c @@ -2918,8 +2918,6 @@ static int dce_v11_0_sw_init(void *handle) adev_to_drm(adev)->mode_config.fb_modifiers_not_supported = true; - adev_to_drm(adev)->mode_config.fb_base = adev->gmc.aper_base; - r = amdgpu_display_modeset_create_props(adev); if (r) return r; diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c index b1c44fab074f..62315fd5a05f 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c @@ -2675,7 +2675,6 @@ static int dce_v6_0_sw_init(void *handle) adev_to_drm(adev)->mode_config.preferred_depth = 24; adev_to_drm(adev)->mode_config.prefer_shadow = 1; adev_to_drm(adev)->mode_config.fb_modifiers_not_supported = true; - adev_to_drm(adev)->mode_config.fb_base = adev->gmc.aper_base; r = amdgpu_display_modeset_create_props(adev); if (r) diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c index a22b45c92792..87d5e4c21cb3 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c @@ -2701,8 +2701,6 @@ static int dce_v8_0_sw_init(void *handle) adev_to_drm(adev)->mode_config.fb_modifiers_not_supported = true; - adev_to_drm(adev)->mode_config.fb_base = adev->gmc.aper_base; - r = amdgpu_display_modeset_create_props(adev); if (r) return r; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index c053cb79cd06..0db2a88cd4d7 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -3816,8 +3816,6 @@ static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev) /* indicates support for immediate flip */ adev_to_drm(adev)->mode_config.async_page_flip = true; - adev_to_drm(adev)->mode_config.fb_base = adev->gmc.aper_base; - state = kzalloc(sizeof(*state), GFP_KERNEL); if (!state) return -ENOMEM; diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index 4355754d69b5..c7443317c747 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -1767,7 +1767,6 @@ static const struct drm_mode_config_funcs ast_mode_config_funcs = { int ast_mode_config_init(struct ast_private *ast) { struct drm_device *dev = &ast->base; - struct pci_dev *pdev = to_pci_dev(dev->dev); int ret; ret = drmm_mode_config_init(dev); @@ -1778,7 +1777,6 @@ int ast_mode_config_init(struct ast_private *ast) dev->mode_config.min_width = 0; dev->mode_config.min_height = 0; dev->mode_config.preferred_depth = 24; - dev->mode_config.fb_base = pci_resource_start(pdev, 0); if (ast->chip == AST2100 || ast->chip == AST2200 || diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c index aa3ecf771fd3..5f502a0048ab 100644 --- a/drivers/gpu/drm/gma500/framebuffer.c +++ b/drivers/gpu/drm/gma500/framebuffer.c @@ -286,7 +286,7 @@ static int psbfb_create(struct drm_fb_helper *fb_helper, info->fbops = &psbfb_unaccel_ops; - info->fix.smem_start = dev->mode_config.fb_base; + info->fix.smem_start = dev_priv->fb_base; info->fix.smem_len = size; info->fix.ywrapstep = 0; info->fix.ypanstep = 0; @@ -296,7 +296,7 @@ static int psbfb_create(struct drm_fb_helper *fb_helper, info->screen_size = size; if (dev_priv->gtt.stolen_size) { - info->apertures->ranges[0].base = dev->mode_config.fb_base; + info->apertures->ranges[0].base = dev_priv->fb_base; info->apertures->ranges[0].size = dev_priv->gtt.stolen_size; } @@ -527,7 +527,7 @@ void psb_modeset_init(struct drm_device *dev) /* set memory base */ /* Oaktrail and Poulsbo should use BAR 2*/ - pci_read_config_dword(pdev, PSB_BSM, (u32 *)&(dev->mode_config.fb_base)); + pci_read_config_dword(pdev, PSB_BSM, (u32 *)&(dev_priv->fb_base)); /* num pipes is 2 for PSB but 1 for Mrst */ for (i = 0; i < dev_priv->num_pipe; i++) diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h index ae544b69fc47..a5df6d2f2cab 100644 --- a/drivers/gpu/drm/gma500/psb_drv.h +++ b/drivers/gpu/drm/gma500/psb_drv.h @@ -523,6 +523,7 @@ struct drm_psb_private { uint32_t blc_adj2; struct drm_fb_helper *fb_helper; + resource_size_t fb_base; bool dsr_enable; u32 dsr_fb_update; diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c index fe4269c5aa0a..5a2e1cac06b2 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c @@ -105,7 +105,6 @@ static int hibmc_kms_init(struct hibmc_drm_private *priv) dev->mode_config.max_width = 1920; dev->mode_config.max_height = 1200; - dev->mode_config.fb_base = priv->fb_base; dev->mode_config.preferred_depth = 32; dev->mode_config.prefer_shadow = 1; @@ -212,7 +211,7 @@ static int hibmc_hw_map(struct hibmc_drm_private *priv) { struct drm_device *dev = &priv->dev; struct pci_dev *pdev = to_pci_dev(dev->dev); - resource_size_t addr, size, ioaddr, iosize; + resource_size_t ioaddr, iosize; ioaddr = pci_resource_start(pdev, 1); iosize = pci_resource_len(pdev, 1); @@ -222,16 +221,6 @@ static int hibmc_hw_map(struct hibmc_drm_private *priv) return -ENOMEM; } - addr = pci_resource_start(pdev, 0); - size = pci_resource_len(pdev, 0); - priv->fb_map = devm_ioremap(dev->dev, addr, size); - if (!priv->fb_map) { - drm_err(dev, "Cannot map framebuffer\n"); - return -ENOMEM; - } - priv->fb_base = addr; - priv->fb_size = size; - return 0; } @@ -271,7 +260,8 @@ static int hibmc_load(struct drm_device *dev) if (ret) goto err; - ret = drmm_vram_helper_init(dev, pci_resource_start(pdev, 0), priv->fb_size); + ret = drmm_vram_helper_init(dev, pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); if (ret) { drm_err(dev, "Error initializing VRAM MM; %d\n", ret); goto err; diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h index 7d263f4d7078..4a0cd22c10e2 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h @@ -32,9 +32,6 @@ struct hibmc_connector { struct hibmc_drm_private { /* hw */ void __iomem *mmio; - void __iomem *fb_map; - resource_size_t fb_base; - resource_size_t fb_size; /* drm */ struct drm_device dev; diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 758629da95d9..0a5aaf78172a 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -824,7 +824,6 @@ int mgag200_mode_config_init(struct mga_device *mdev, resource_size_t vram_avail dev->mode_config.max_width = MGAG200_MAX_FB_WIDTH; dev->mode_config.max_height = MGAG200_MAX_FB_HEIGHT; dev->mode_config.preferred_depth = 24; - dev->mode_config.fb_base = mdev->vram_res->start; dev->mode_config.funcs = &mgag200_mode_config_funcs; dev->mode_config.helper_private = &mgag200_mode_config_helper_funcs; diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c index 46168eccfac4..b373e3000320 100644 --- a/drivers/gpu/drm/msm/msm_fbdev.c +++ b/drivers/gpu/drm/msm/msm_fbdev.c @@ -109,8 +109,6 @@ static int msm_fbdev_create(struct drm_fb_helper *helper, drm_fb_helper_fill_info(fbi, helper, sizes); - dev->mode_config.fb_base = paddr; - fbi->screen_base = msm_gem_get_vaddr(bo); if (IS_ERR(fbi->screen_base)) { ret = PTR_ERR(fbi->screen_base); diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index a2f5df568ca5..928fdfa8e8e5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -672,7 +672,6 @@ nouveau_display_create(struct drm_device *dev) drm_mode_create_dvi_i_properties(dev); dev->mode_config.funcs = &nouveau_mode_config_funcs; - dev->mode_config.fb_base = device->func->resource_addr(device, 1); dev->mode_config.min_width = 0; dev->mode_config.min_height = 0; diff --git a/drivers/gpu/drm/nouveau/nv04_fbcon.c b/drivers/gpu/drm/nouveau/nv04_fbcon.c index 92f3fb6765ab..c30b8dacd86b 100644 --- a/drivers/gpu/drm/nouveau/nv04_fbcon.c +++ b/drivers/gpu/drm/nouveau/nv04_fbcon.c @@ -137,6 +137,8 @@ nv04_fbcon_accel_init(struct fb_info *info) struct nouveau_channel *chan = drm->channel; struct nvif_device *device = &drm->client.device; struct nvif_push *push = chan->chan.push; + struct nvkm_device *nvkm_device = nvxx_device(&drm->client.device); + resource_size_t fb_base = nvkm_device->func->resource_addr(nvkm_device, 1); int surface_fmt, pattern_fmt, rect_fmt; int ret; @@ -210,8 +212,8 @@ nv04_fbcon_accel_init(struct fb_info *info) 0x0188, chan->vram.handle); PUSH_NVSQ(push, NV042, 0x0300, surface_fmt, 0x0304, info->fix.line_length | (info->fix.line_length << 16), - 0x0308, info->fix.smem_start - dev->mode_config.fb_base, - 0x030c, info->fix.smem_start - dev->mode_config.fb_base); + 0x0308, info->fix.smem_start - fb_base, + 0x030c, info->fix.smem_start - fb_base); PUSH_NVSQ(push, NV043, 0x0000, nfbdev->rop.handle); PUSH_NVSQ(push, NV043, 0x0300, 0x55); diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c index 40706c5aad7b..ed67dd25794c 100644 --- a/drivers/gpu/drm/omapdrm/omap_fbdev.c +++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c @@ -177,8 +177,6 @@ static int omap_fbdev_create(struct drm_fb_helper *helper, drm_fb_helper_fill_info(fbi, helper, sizes); - dev->mode_config.fb_base = dma_addr; - fbi->screen_buffer = omap_gem_vaddr(fbdev->bo); fbi->screen_size = fbdev->bo->size; fbi->fix.smem_start = dma_addr; diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index a152a7c6db21..6492a70e3c39 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c @@ -1261,8 +1261,6 @@ int qxl_modeset_init(struct qxl_device *qdev) qdev->ddev.mode_config.max_width = 8192; qdev->ddev.mode_config.max_height = 8192; - qdev->ddev.mode_config.fb_base = qdev->vram_base; - drm_mode_create_suggested_offset_properties(&qdev->ddev); qxl_mode_create_hotplug_mode_update_property(qdev); diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index ca5598ae8bfc..9bed1a6cb163 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -1604,8 +1604,6 @@ int radeon_modeset_init(struct radeon_device *rdev) rdev->ddev->mode_config.fb_modifiers_not_supported = true; - rdev->ddev->mode_config.fb_base = rdev->mc.aper_base; - ret = radeon_modeset_create_props(rdev); if (ret) { return ret; diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index 6ccea51d4072..cc6754d88b81 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -276,7 +276,7 @@ static int radeonfb_create(struct drm_fb_helper *helper, drm_fb_helper_fill_info(info, &rfbdev->helper, sizes); /* setup aperture base/size for vesafb takeover */ - info->apertures->ranges[0].base = rdev->ddev->mode_config.fb_base; + info->apertures->ranges[0].base = rdev->mc.aper_base; info->apertures->ranges[0].size = rdev->mc.aper_size; /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c index 9291209154a7..bce71c0ccc9e 100644 --- a/drivers/gpu/drm/tegra/fb.c +++ b/drivers/gpu/drm/tegra/fb.c @@ -280,7 +280,6 @@ static int tegra_fbdev_probe(struct drm_fb_helper *helper, } } - drm->mode_config.fb_base = (resource_size_t)bo->iova; info->screen_base = (void __iomem *)bo->vaddr + offset; info->screen_size = size; info->fix.smem_start = (unsigned long)(bo->iova + offset); diff --git a/drivers/gpu/drm/tiny/bochs.c b/drivers/gpu/drm/tiny/bochs.c index a51262289aef..04682f831544 100644 --- a/drivers/gpu/drm/tiny/bochs.c +++ b/drivers/gpu/drm/tiny/bochs.c @@ -543,7 +543,6 @@ static int bochs_kms_init(struct bochs_device *bochs) bochs->dev->mode_config.max_width = 8192; bochs->dev->mode_config.max_height = 8192; - bochs->dev->mode_config.fb_base = bochs->fb_base; bochs->dev->mode_config.preferred_depth = 24; bochs->dev->mode_config.prefer_shadow = 0; bochs->dev->mode_config.prefer_shadow_fbdev = 1; diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h index 6b5e01295348..5362702fffe1 100644 --- a/include/drm/drm_mode_config.h +++ b/include/drm/drm_mode_config.h @@ -345,7 +345,6 @@ struct drm_mode_config_funcs { * @max_width: maximum fb pixel width on this device * @max_height: maximum fb pixel height on this device * @funcs: core driver provided mode setting functions - * @fb_base: base address of the framebuffer * @poll_enabled: track polling support for this device * @poll_running: track polling status for this device * @delayed_event: track delayed poll uevent deliver for this device @@ -542,7 +541,6 @@ struct drm_mode_config { int min_width, min_height; int max_width, max_height; const struct drm_mode_config_funcs *funcs; - resource_size_t fb_base; /* output poll support */ bool poll_enabled; -- cgit From d74c1b461f3d02fe1c3816dec7642caba2581c35 Mon Sep 17 00:00:00 2001 From: Michał Winiarski Date: Thu, 20 Oct 2022 10:21:34 +0200 Subject: drm/plane_helper: Print actual/expected values on failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently the values are printed with debug log level. Adjust the log level and link the output with the test by using kunit_err. Example output: foo: dst: 20x20+10+10, expected: 10x10+0+0 foo: EXPECTATION FAILED at drivers/gpu/drm/tests/drm_plane_helper_test.c:85 Signed-off-by: Michał Winiarski Reviewed-by: Maíra Canal Signed-off-by: Maíra Canal Link: https://patchwork.freedesktop.org/patch/msgid/20221020082135.779872-1-michal.winiarski@intel.com --- drivers/gpu/drm/tests/drm_plane_helper_test.c | 78 +++++++++++++++------------ 1 file changed, 44 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/tests/drm_plane_helper_test.c b/drivers/gpu/drm/tests/drm_plane_helper_test.c index ec71af791f1f..4963f0c960d8 100644 --- a/drivers/gpu/drm/tests/drm_plane_helper_test.c +++ b/drivers/gpu/drm/tests/drm_plane_helper_test.c @@ -10,6 +10,7 @@ #include #include #include +#include static void set_src(struct drm_plane_state *plane_state, unsigned int src_x, unsigned int src_y, @@ -21,26 +22,32 @@ static void set_src(struct drm_plane_state *plane_state, plane_state->src_h = src_h; } -static bool check_src_eq(struct drm_plane_state *plane_state, +static bool check_src_eq(struct kunit *test, struct drm_plane_state *plane_state, unsigned int src_x, unsigned int src_y, unsigned int src_w, unsigned int src_h) { + struct drm_rect expected = DRM_RECT_INIT(src_x, src_y, src_w, src_h); + if (plane_state->src.x1 < 0) { - pr_err("src x coordinate %x should never be below 0.\n", plane_state->src.x1); - drm_rect_debug_print("src: ", &plane_state->src, true); + kunit_err(test, + "src x coordinate %x should never be below 0, src: " DRM_RECT_FP_FMT, + plane_state->src.x1, DRM_RECT_FP_ARG(&plane_state->src)); return false; } if (plane_state->src.y1 < 0) { - pr_err("src y coordinate %x should never be below 0.\n", plane_state->src.y1); - drm_rect_debug_print("src: ", &plane_state->src, true); + kunit_err(test, + "src y coordinate %x should never be below 0, src: " DRM_RECT_FP_FMT, + plane_state->src.y1, DRM_RECT_FP_ARG(&plane_state->src)); return false; } - if (plane_state->src.x1 != src_x || - plane_state->src.y1 != src_y || - drm_rect_width(&plane_state->src) != src_w || - drm_rect_height(&plane_state->src) != src_h) { - drm_rect_debug_print("src: ", &plane_state->src, true); + if (plane_state->src.x1 != expected.x1 || + plane_state->src.y1 != expected.y1 || + drm_rect_width(&plane_state->src) != drm_rect_width(&expected) || + drm_rect_height(&plane_state->src) != drm_rect_height(&expected)) { + kunit_err(test, "src: " DRM_RECT_FP_FMT ", expected: " DRM_RECT_FP_FMT, + DRM_RECT_FP_ARG(&plane_state->src), DRM_RECT_FP_ARG(&expected)); + return false; } @@ -57,15 +64,18 @@ static void set_crtc(struct drm_plane_state *plane_state, plane_state->crtc_h = crtc_h; } -static bool check_crtc_eq(struct drm_plane_state *plane_state, +static bool check_crtc_eq(struct kunit *test, struct drm_plane_state *plane_state, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h) { - if (plane_state->dst.x1 != crtc_x || - plane_state->dst.y1 != crtc_y || - drm_rect_width(&plane_state->dst) != crtc_w || - drm_rect_height(&plane_state->dst) != crtc_h) { - drm_rect_debug_print("dst: ", &plane_state->dst, false); + struct drm_rect expected = DRM_RECT_INIT(crtc_x, crtc_y, crtc_w, crtc_h); + + if (plane_state->dst.x1 != expected.x1 || + plane_state->dst.y1 != expected.y1 || + drm_rect_width(&plane_state->dst) != drm_rect_width(&expected) || + drm_rect_height(&plane_state->dst) != drm_rect_height(&expected)) { + kunit_err(test, "dst: " DRM_RECT_FMT ", expected: " DRM_RECT_FMT, + DRM_RECT_ARG(&plane_state->dst), DRM_RECT_ARG(&expected)); return false; } @@ -109,8 +119,8 @@ static void drm_test_check_plane_state(struct kunit *test) false, false); KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Simple clipping check should pass\n"); KUNIT_EXPECT_TRUE(test, plane_state.visible); - KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0, 0, 1024 << 16, 768 << 16)); - KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 0, 0, 1024, 768)); + KUNIT_EXPECT_TRUE(test, check_src_eq(test, &plane_state, 0, 0, 1024 << 16, 768 << 16)); + KUNIT_EXPECT_TRUE(test, check_crtc_eq(test, &plane_state, 0, 0, 1024, 768)); /* Rotated clipping + reflection, no scaling. */ plane_state.rotation = DRM_MODE_ROTATE_90 | DRM_MODE_REFLECT_X; @@ -120,8 +130,8 @@ static void drm_test_check_plane_state(struct kunit *test) false, false); KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Rotated clipping check should pass\n"); KUNIT_EXPECT_TRUE(test, plane_state.visible); - KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0, 0, 768 << 16, 1024 << 16)); - KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 0, 0, 1024, 768)); + KUNIT_EXPECT_TRUE(test, check_src_eq(test, &plane_state, 0, 0, 768 << 16, 1024 << 16)); + KUNIT_EXPECT_TRUE(test, check_crtc_eq(test, &plane_state, 0, 0, 1024, 768)); plane_state.rotation = DRM_MODE_ROTATE_0; /* Check whether positioning works correctly. */ @@ -140,8 +150,8 @@ static void drm_test_check_plane_state(struct kunit *test) true, false); KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Simple positioning should work\n"); KUNIT_EXPECT_TRUE(test, plane_state.visible); - KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0, 0, 1023 << 16, 767 << 16)); - KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 0, 0, 1023, 767)); + KUNIT_EXPECT_TRUE(test, check_src_eq(test, &plane_state, 0, 0, 1023 << 16, 767 << 16)); + KUNIT_EXPECT_TRUE(test, check_crtc_eq(test, &plane_state, 0, 0, 1023, 767)); /* Simple scaling tests. */ set_src(&plane_state, 0, 0, 512 << 16, 384 << 16); @@ -157,8 +167,8 @@ static void drm_test_check_plane_state(struct kunit *test) false, false); KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Upscaling exactly 2x should work\n"); KUNIT_EXPECT_TRUE(test, plane_state.visible); - KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0, 0, 512 << 16, 384 << 16)); - KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 0, 0, 1024, 768)); + KUNIT_EXPECT_TRUE(test, check_src_eq(test, &plane_state, 0, 0, 512 << 16, 384 << 16)); + KUNIT_EXPECT_TRUE(test, check_crtc_eq(test, &plane_state, 0, 0, 1024, 768)); set_src(&plane_state, 0, 0, 2048 << 16, 1536 << 16); ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, @@ -170,8 +180,8 @@ static void drm_test_check_plane_state(struct kunit *test) 0x20000, false, false); KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Should succeed with exact scaling limit\n"); KUNIT_EXPECT_TRUE(test, plane_state.visible); - KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0, 0, 2048 << 16, 1536 << 16)); - KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 0, 0, 1024, 768)); + KUNIT_EXPECT_TRUE(test, check_src_eq(test, &plane_state, 0, 0, 2048 << 16, 1536 << 16)); + KUNIT_EXPECT_TRUE(test, check_crtc_eq(test, &plane_state, 0, 0, 1024, 768)); /* Testing rounding errors. */ set_src(&plane_state, 0, 0, 0x40001, 0x40001); @@ -182,8 +192,8 @@ static void drm_test_check_plane_state(struct kunit *test) true, false); KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Should succeed by clipping to exact multiple"); KUNIT_EXPECT_TRUE(test, plane_state.visible); - KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0, 0, 2 << 16, 2 << 16)); - KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 1022, 766, 2, 2)); + KUNIT_EXPECT_TRUE(test, check_src_eq(test, &plane_state, 0, 0, 2 << 16, 2 << 16)); + KUNIT_EXPECT_TRUE(test, check_crtc_eq(test, &plane_state, 1022, 766, 2, 2)); set_src(&plane_state, 0x20001, 0x20001, 0x4040001, 0x3040001); set_crtc(&plane_state, -2, -2, 1028, 772); @@ -193,9 +203,9 @@ static void drm_test_check_plane_state(struct kunit *test) false, false); KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Should succeed by clipping to exact multiple"); KUNIT_EXPECT_TRUE(test, plane_state.visible); - KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0x40002, 0x40002, + KUNIT_EXPECT_TRUE(test, check_src_eq(test, &plane_state, 0x40002, 0x40002, 1024 << 16, 768 << 16)); - KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 0, 0, 1024, 768)); + KUNIT_EXPECT_TRUE(test, check_crtc_eq(test, &plane_state, 0, 0, 1024, 768)); set_src(&plane_state, 0, 0, 0x3ffff, 0x3ffff); set_crtc(&plane_state, 1022, 766, 4, 4); @@ -206,8 +216,8 @@ static void drm_test_check_plane_state(struct kunit *test) KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Should succeed by clipping to exact multiple"); KUNIT_EXPECT_TRUE(test, plane_state.visible); /* Should not be rounded to 0x20001, which would be upscaling. */ - KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0, 0, 2 << 16, 2 << 16)); - KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 1022, 766, 2, 2)); + KUNIT_EXPECT_TRUE(test, check_src_eq(test, &plane_state, 0, 0, 2 << 16, 2 << 16)); + KUNIT_EXPECT_TRUE(test, check_crtc_eq(test, &plane_state, 1022, 766, 2, 2)); set_src(&plane_state, 0x1ffff, 0x1ffff, 0x403ffff, 0x303ffff); set_crtc(&plane_state, -2, -2, 1028, 772); @@ -217,9 +227,9 @@ static void drm_test_check_plane_state(struct kunit *test) false, false); KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Should succeed by clipping to exact multiple"); KUNIT_EXPECT_TRUE(test, plane_state.visible); - KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0x3fffe, 0x3fffe, + KUNIT_EXPECT_TRUE(test, check_src_eq(test, &plane_state, 0x3fffe, 0x3fffe, 1024 << 16, 768 << 16)); - KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 0, 0, 1024, 768)); + KUNIT_EXPECT_TRUE(test, check_crtc_eq(test, &plane_state, 0, 0, 1024, 768)); } static struct kunit_case drm_plane_helper_test[] = { -- cgit From e9f696f88b8de4cfea8e284be91fa3ea2a631731 Mon Sep 17 00:00:00 2001 From: Michał Winiarski Date: Thu, 20 Oct 2022 10:21:35 +0200 Subject: drm/plane_helper: Split into parameterized test cases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The test was constructed as a single function (test case) which checks multiple conditions, calling the function that is tested multiple times with different arguments. This usually means that it can be easily converted into multiple test cases. Split igt_check_plane_state into two parameterized test cases, drm_check_plane_state and drm_check_invalid_plane_state. Passing output: ============================================================ ============== drm_plane_helper (2 subtests) =============== ================== drm_check_plane_state =================== [PASSED] clipping_simple [PASSED] clipping_rotate_reflect [PASSED] positioning_simple [PASSED] upscaling [PASSED] downscaling [PASSED] rounding1 [PASSED] rounding2 [PASSED] rounding3 [PASSED] rounding4 ============== [PASSED] drm_check_plane_state ============== ============== drm_check_invalid_plane_state =============== [PASSED] positioning_invalid [PASSED] upscaling_invalid [PASSED] downscaling_invalid ========== [PASSED] drm_check_invalid_plane_state ========== ================ [PASSED] drm_plane_helper ================= ============================================================ Testing complete. Ran 12 tests: passed: 12 v2: Add missing EXPECT/ASSERT (Maíra) v3: Use single EXPECT insted of condition + KUNIT_FAILURE (Maíra) v4: Rebase after "drm_test" rename Signed-off-by: Michał Winiarski Reviewed-by: Maíra Canal Signed-off-by: Maíra Canal Link: https://patchwork.freedesktop.org/patch/msgid/20221020082135.779872-2-michal.winiarski@intel.com --- drivers/gpu/drm/tests/drm_plane_helper_test.c | 467 +++++++++++++++----------- 1 file changed, 269 insertions(+), 198 deletions(-) diff --git a/drivers/gpu/drm/tests/drm_plane_helper_test.c b/drivers/gpu/drm/tests/drm_plane_helper_test.c index 4963f0c960d8..0f392146b233 100644 --- a/drivers/gpu/drm/tests/drm_plane_helper_test.c +++ b/drivers/gpu/drm/tests/drm_plane_helper_test.c @@ -12,233 +12,304 @@ #include #include -static void set_src(struct drm_plane_state *plane_state, - unsigned int src_x, unsigned int src_y, - unsigned int src_w, unsigned int src_h) +static const struct drm_crtc_state crtc_state = { + .crtc = ZERO_SIZE_PTR, + .enable = true, + .active = true, + .mode = { + DRM_MODE("1024x768", 0, 65000, 1024, 1048, + 1184, 1344, 0, 768, 771, 777, 806, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) + }, +}; + +struct drm_check_plane_state_test { + const char *name; + const char *msg; + struct { + unsigned int x; + unsigned int y; + unsigned int w; + unsigned int h; + } src, src_expected; + struct { + int x; + int y; + unsigned int w; + unsigned int h; + } crtc, crtc_expected; + unsigned int rotation; + int min_scale; + int max_scale; + bool can_position; +}; + +static int drm_plane_helper_init(struct kunit *test) { - plane_state->src_x = src_x; - plane_state->src_y = src_y; - plane_state->src_w = src_w; - plane_state->src_h = src_h; + const struct drm_check_plane_state_test *params = test->param_value; + struct drm_plane *plane; + struct drm_framebuffer *fb; + struct drm_plane_state *mock; + + plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, plane); + + fb = kunit_kzalloc(test, sizeof(*fb), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, fb); + fb->width = 2048; + fb->height = 2048; + + mock = kunit_kzalloc(test, sizeof(*mock), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, mock); + mock->plane = plane; + mock->crtc = ZERO_SIZE_PTR; + mock->fb = fb; + mock->rotation = params->rotation; + mock->src_x = params->src.x; + mock->src_y = params->src.y; + mock->src_w = params->src.w; + mock->src_h = params->src.h; + mock->crtc_x = params->crtc.x; + mock->crtc_y = params->crtc.y; + mock->crtc_w = params->crtc.w; + mock->crtc_h = params->crtc.h; + + test->priv = mock; + + return 0; } -static bool check_src_eq(struct kunit *test, struct drm_plane_state *plane_state, +static void check_src_eq(struct kunit *test, struct drm_plane_state *plane_state, unsigned int src_x, unsigned int src_y, unsigned int src_w, unsigned int src_h) { struct drm_rect expected = DRM_RECT_INIT(src_x, src_y, src_w, src_h); - if (plane_state->src.x1 < 0) { - kunit_err(test, - "src x coordinate %x should never be below 0, src: " DRM_RECT_FP_FMT, - plane_state->src.x1, DRM_RECT_FP_ARG(&plane_state->src)); - return false; - } - if (plane_state->src.y1 < 0) { - kunit_err(test, - "src y coordinate %x should never be below 0, src: " DRM_RECT_FP_FMT, - plane_state->src.y1, DRM_RECT_FP_ARG(&plane_state->src)); - return false; - } - - if (plane_state->src.x1 != expected.x1 || - plane_state->src.y1 != expected.y1 || - drm_rect_width(&plane_state->src) != drm_rect_width(&expected) || - drm_rect_height(&plane_state->src) != drm_rect_height(&expected)) { - kunit_err(test, "src: " DRM_RECT_FP_FMT ", expected: " DRM_RECT_FP_FMT, - DRM_RECT_FP_ARG(&plane_state->src), DRM_RECT_FP_ARG(&expected)); - - return false; - } - - return true; -} + KUNIT_ASSERT_GE_MSG(test, plane_state->src.x1, 0, + "src x coordinate %x should never be below 0, src: " DRM_RECT_FP_FMT, + plane_state->src.x1, DRM_RECT_FP_ARG(&plane_state->src)); -static void set_crtc(struct drm_plane_state *plane_state, - int crtc_x, int crtc_y, - unsigned int crtc_w, unsigned int crtc_h) -{ - plane_state->crtc_x = crtc_x; - plane_state->crtc_y = crtc_y; - plane_state->crtc_w = crtc_w; - plane_state->crtc_h = crtc_h; + KUNIT_ASSERT_GE_MSG(test, plane_state->src.y1, 0, + "src y coordinate %x should never be below 0, src: " DRM_RECT_FP_FMT, + plane_state->src.y1, DRM_RECT_FP_ARG(&plane_state->src)); + + KUNIT_EXPECT_TRUE_MSG(test, drm_rect_equals(&plane_state->src, &expected), + "dst: " DRM_RECT_FP_FMT ", expected: " DRM_RECT_FP_FMT, + DRM_RECT_FP_ARG(&plane_state->src), DRM_RECT_FP_ARG(&expected)); } -static bool check_crtc_eq(struct kunit *test, struct drm_plane_state *plane_state, +static void check_crtc_eq(struct kunit *test, struct drm_plane_state *plane_state, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h) { struct drm_rect expected = DRM_RECT_INIT(crtc_x, crtc_y, crtc_w, crtc_h); - if (plane_state->dst.x1 != expected.x1 || - plane_state->dst.y1 != expected.y1 || - drm_rect_width(&plane_state->dst) != drm_rect_width(&expected) || - drm_rect_height(&plane_state->dst) != drm_rect_height(&expected)) { - kunit_err(test, "dst: " DRM_RECT_FMT ", expected: " DRM_RECT_FMT, - DRM_RECT_ARG(&plane_state->dst), DRM_RECT_ARG(&expected)); + KUNIT_EXPECT_TRUE_MSG(test, drm_rect_equals(&plane_state->dst, &expected), + "dst: " DRM_RECT_FMT ", expected: " DRM_RECT_FMT, + DRM_RECT_ARG(&plane_state->dst), DRM_RECT_ARG(&expected)); +} + +static void drm_test_check_plane_state(struct kunit *test) +{ + const struct drm_check_plane_state_test *params = test->param_value; + struct drm_plane_state *plane_state = test->priv; - return false; - } + KUNIT_ASSERT_EQ_MSG(test, + drm_atomic_helper_check_plane_state(plane_state, &crtc_state, + params->min_scale, + params->max_scale, + params->can_position, false), + 0, params->msg); + KUNIT_EXPECT_TRUE(test, plane_state->visible); + check_src_eq(test, plane_state, params->src_expected.x, params->src_expected.y, + params->src_expected.w, params->src_expected.h); + check_crtc_eq(test, plane_state, params->crtc_expected.x, params->crtc_expected.y, + params->crtc_expected.w, params->crtc_expected.h); +} - return true; +static void drm_check_plane_state_desc(const struct drm_check_plane_state_test *t, + char *desc) +{ + sprintf(desc, "%s", t->name); } -static void drm_test_check_plane_state(struct kunit *test) +static const struct drm_check_plane_state_test drm_check_plane_state_tests[] = { + { + .name = "clipping_simple", + .msg = "Simple clipping check should pass", + .src = { 0, 0, + 2048 << 16, + 2048 << 16 }, + .crtc = { 0, 0, 2048, 2048 }, + .rotation = DRM_MODE_ROTATE_0, + .min_scale = DRM_PLANE_NO_SCALING, + .max_scale = DRM_PLANE_NO_SCALING, + .can_position = false, + .src_expected = { 0, 0, 1024 << 16, 768 << 16 }, + .crtc_expected = { 0, 0, 1024, 768 }, + }, + { + .name = "clipping_rotate_reflect", + .msg = "Rotated clipping check should pass", + .src = { 0, 0, + 2048 << 16, + 2048 << 16 }, + .crtc = { 0, 0, 2048, 2048 }, + .rotation = DRM_MODE_ROTATE_90 | DRM_MODE_REFLECT_X, + .min_scale = DRM_PLANE_NO_SCALING, + .max_scale = DRM_PLANE_NO_SCALING, + .can_position = false, + .src_expected = { 0, 0, 768 << 16, 1024 << 16 }, + .crtc_expected = { 0, 0, 1024, 768 }, + }, + { + .name = "positioning_simple", + .msg = "Simple positioning should work", + .src = { 0, 0, 1023 << 16, 767 << 16 }, + .crtc = { 0, 0, 1023, 767 }, + .rotation = DRM_MODE_ROTATE_0, + .min_scale = DRM_PLANE_NO_SCALING, + .max_scale = DRM_PLANE_NO_SCALING, + .can_position = true, + .src_expected = { 0, 0, 1023 << 16, 767 << 16 }, + .crtc_expected = { 0, 0, 1023, 767 }, + }, + { + .name = "upscaling", + .msg = "Upscaling exactly 2x should work", + .src = { 0, 0, 512 << 16, 384 << 16 }, + .crtc = { 0, 0, 1024, 768 }, + .rotation = DRM_MODE_ROTATE_0, + .min_scale = 0x8000, + .max_scale = DRM_PLANE_NO_SCALING, + .can_position = false, + .src_expected = { 0, 0, 512 << 16, 384 << 16 }, + .crtc_expected = { 0, 0, 1024, 768 }, + }, + { + .name = "downscaling", + .msg = "Should succeed with exact scaling limit", + .src = { 0, 0, 2048 << 16, 1536 << 16 }, + .crtc = { 0, 0, 1024, 768 }, + .rotation = DRM_MODE_ROTATE_0, + .min_scale = DRM_PLANE_NO_SCALING, + .max_scale = 0x20000, + .can_position = false, + .src_expected = { 0, 0, 2048 << 16, 1536 << 16 }, + .crtc_expected = { 0, 0, 1024, 768 }, + }, + { + .name = "rounding1", + .msg = "Should succeed by clipping to exact multiple", + .src = { 0, 0, 0x40001, 0x40001 }, + .crtc = { 1022, 766, 4, 4 }, + .rotation = DRM_MODE_ROTATE_0, + .min_scale = DRM_PLANE_NO_SCALING, + .max_scale = 0x10001, + .can_position = true, + .src_expected = { 0, 0, 2 << 16, 2 << 16 }, + .crtc_expected = { 1022, 766, 2, 2 }, + }, + { + .name = "rounding2", + .msg = "Should succeed by clipping to exact multiple", + .src = { 0x20001, 0x20001, 0x4040001, 0x3040001 }, + .crtc = { -2, -2, 1028, 772 }, + .rotation = DRM_MODE_ROTATE_0, + .min_scale = DRM_PLANE_NO_SCALING, + .max_scale = 0x10001, + .can_position = false, + .src_expected = { 0x40002, 0x40002, 1024 << 16, 768 << 16 }, + .crtc_expected = { 0, 0, 1024, 768 }, + }, + { + .name = "rounding3", + .msg = "Should succeed by clipping to exact multiple", + .src = { 0, 0, 0x3ffff, 0x3ffff }, + .crtc = { 1022, 766, 4, 4 }, + .rotation = DRM_MODE_ROTATE_0, + .min_scale = 0xffff, + .max_scale = DRM_PLANE_NO_SCALING, + .can_position = true, + /* Should not be rounded to 0x20001, which would be upscaling. */ + .src_expected = { 0, 0, 2 << 16, 2 << 16 }, + .crtc_expected = { 1022, 766, 2, 2 }, + }, + { + .name = "rounding4", + .msg = "Should succeed by clipping to exact multiple", + .src = { 0x1ffff, 0x1ffff, 0x403ffff, 0x303ffff }, + .crtc = { -2, -2, 1028, 772 }, + .rotation = DRM_MODE_ROTATE_0, + .min_scale = 0xffff, + .max_scale = DRM_PLANE_NO_SCALING, + .can_position = false, + .src_expected = { 0x3fffe, 0x3fffe, 1024 << 16, 768 << 16 }, + .crtc_expected = { 0, 0, 1024, 768 }, + }, +}; + +KUNIT_ARRAY_PARAM(drm_check_plane_state, drm_check_plane_state_tests, drm_check_plane_state_desc); + +static void drm_test_check_invalid_plane_state(struct kunit *test) { - int ret; - - static const struct drm_crtc_state crtc_state = { - .crtc = ZERO_SIZE_PTR, - .enable = true, - .active = true, - .mode = { - DRM_MODE("1024x768", 0, 65000, 1024, 1048, 1184, 1344, 0, 768, 771, - 777, 806, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) - }, - }; - static struct drm_plane plane = { - .dev = NULL - }; - static struct drm_framebuffer fb = { - .width = 2048, - .height = 2048 - }; - static struct drm_plane_state plane_state = { - .plane = &plane, - .crtc = ZERO_SIZE_PTR, - .fb = &fb, - .rotation = DRM_MODE_ROTATE_0 - }; - - /* Simple clipping, no scaling. */ - set_src(&plane_state, 0, 0, fb.width << 16, fb.height << 16); - set_crtc(&plane_state, 0, 0, fb.width, fb.height); - ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, - DRM_PLANE_NO_SCALING, - DRM_PLANE_NO_SCALING, - false, false); - KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Simple clipping check should pass\n"); - KUNIT_EXPECT_TRUE(test, plane_state.visible); - KUNIT_EXPECT_TRUE(test, check_src_eq(test, &plane_state, 0, 0, 1024 << 16, 768 << 16)); - KUNIT_EXPECT_TRUE(test, check_crtc_eq(test, &plane_state, 0, 0, 1024, 768)); - - /* Rotated clipping + reflection, no scaling. */ - plane_state.rotation = DRM_MODE_ROTATE_90 | DRM_MODE_REFLECT_X; - ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, - DRM_PLANE_NO_SCALING, - DRM_PLANE_NO_SCALING, - false, false); - KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Rotated clipping check should pass\n"); - KUNIT_EXPECT_TRUE(test, plane_state.visible); - KUNIT_EXPECT_TRUE(test, check_src_eq(test, &plane_state, 0, 0, 768 << 16, 1024 << 16)); - KUNIT_EXPECT_TRUE(test, check_crtc_eq(test, &plane_state, 0, 0, 1024, 768)); - plane_state.rotation = DRM_MODE_ROTATE_0; - - /* Check whether positioning works correctly. */ - set_src(&plane_state, 0, 0, 1023 << 16, 767 << 16); - set_crtc(&plane_state, 0, 0, 1023, 767); - ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, - DRM_PLANE_NO_SCALING, - DRM_PLANE_NO_SCALING, - false, false); - KUNIT_EXPECT_TRUE_MSG(test, ret, - "Should not be able to position on the crtc with can_position=false\n"); - - ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, - DRM_PLANE_NO_SCALING, - DRM_PLANE_NO_SCALING, - true, false); - KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Simple positioning should work\n"); - KUNIT_EXPECT_TRUE(test, plane_state.visible); - KUNIT_EXPECT_TRUE(test, check_src_eq(test, &plane_state, 0, 0, 1023 << 16, 767 << 16)); - KUNIT_EXPECT_TRUE(test, check_crtc_eq(test, &plane_state, 0, 0, 1023, 767)); - - /* Simple scaling tests. */ - set_src(&plane_state, 0, 0, 512 << 16, 384 << 16); - set_crtc(&plane_state, 0, 0, 1024, 768); - ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, - 0x8001, - DRM_PLANE_NO_SCALING, - false, false); - KUNIT_EXPECT_TRUE_MSG(test, ret, "Upscaling out of range should fail.\n"); - ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, - 0x8000, - DRM_PLANE_NO_SCALING, - false, false); - KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Upscaling exactly 2x should work\n"); - KUNIT_EXPECT_TRUE(test, plane_state.visible); - KUNIT_EXPECT_TRUE(test, check_src_eq(test, &plane_state, 0, 0, 512 << 16, 384 << 16)); - KUNIT_EXPECT_TRUE(test, check_crtc_eq(test, &plane_state, 0, 0, 1024, 768)); - - set_src(&plane_state, 0, 0, 2048 << 16, 1536 << 16); - ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, - DRM_PLANE_NO_SCALING, - 0x1ffff, false, false); - KUNIT_EXPECT_TRUE_MSG(test, ret, "Downscaling out of range should fail.\n"); - ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, - DRM_PLANE_NO_SCALING, - 0x20000, false, false); - KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Should succeed with exact scaling limit\n"); - KUNIT_EXPECT_TRUE(test, plane_state.visible); - KUNIT_EXPECT_TRUE(test, check_src_eq(test, &plane_state, 0, 0, 2048 << 16, 1536 << 16)); - KUNIT_EXPECT_TRUE(test, check_crtc_eq(test, &plane_state, 0, 0, 1024, 768)); - - /* Testing rounding errors. */ - set_src(&plane_state, 0, 0, 0x40001, 0x40001); - set_crtc(&plane_state, 1022, 766, 4, 4); - ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, - DRM_PLANE_NO_SCALING, - 0x10001, - true, false); - KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Should succeed by clipping to exact multiple"); - KUNIT_EXPECT_TRUE(test, plane_state.visible); - KUNIT_EXPECT_TRUE(test, check_src_eq(test, &plane_state, 0, 0, 2 << 16, 2 << 16)); - KUNIT_EXPECT_TRUE(test, check_crtc_eq(test, &plane_state, 1022, 766, 2, 2)); - - set_src(&plane_state, 0x20001, 0x20001, 0x4040001, 0x3040001); - set_crtc(&plane_state, -2, -2, 1028, 772); - ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, - DRM_PLANE_NO_SCALING, - 0x10001, - false, false); - KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Should succeed by clipping to exact multiple"); - KUNIT_EXPECT_TRUE(test, plane_state.visible); - KUNIT_EXPECT_TRUE(test, check_src_eq(test, &plane_state, 0x40002, 0x40002, - 1024 << 16, 768 << 16)); - KUNIT_EXPECT_TRUE(test, check_crtc_eq(test, &plane_state, 0, 0, 1024, 768)); - - set_src(&plane_state, 0, 0, 0x3ffff, 0x3ffff); - set_crtc(&plane_state, 1022, 766, 4, 4); - ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, - 0xffff, - DRM_PLANE_NO_SCALING, - true, false); - KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Should succeed by clipping to exact multiple"); - KUNIT_EXPECT_TRUE(test, plane_state.visible); - /* Should not be rounded to 0x20001, which would be upscaling. */ - KUNIT_EXPECT_TRUE(test, check_src_eq(test, &plane_state, 0, 0, 2 << 16, 2 << 16)); - KUNIT_EXPECT_TRUE(test, check_crtc_eq(test, &plane_state, 1022, 766, 2, 2)); - - set_src(&plane_state, 0x1ffff, 0x1ffff, 0x403ffff, 0x303ffff); - set_crtc(&plane_state, -2, -2, 1028, 772); - ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, - 0xffff, - DRM_PLANE_NO_SCALING, - false, false); - KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Should succeed by clipping to exact multiple"); - KUNIT_EXPECT_TRUE(test, plane_state.visible); - KUNIT_EXPECT_TRUE(test, check_src_eq(test, &plane_state, 0x3fffe, 0x3fffe, - 1024 << 16, 768 << 16)); - KUNIT_EXPECT_TRUE(test, check_crtc_eq(test, &plane_state, 0, 0, 1024, 768)); + const struct drm_check_plane_state_test *params = test->param_value; + struct drm_plane_state *plane_state = test->priv; + + KUNIT_ASSERT_LT_MSG(test, + drm_atomic_helper_check_plane_state(plane_state, &crtc_state, + params->min_scale, + params->max_scale, + params->can_position, false), + 0, params->msg); } +static const struct drm_check_plane_state_test drm_check_invalid_plane_state_tests[] = { + { + .name = "positioning_invalid", + .msg = "Should not be able to position on the crtc with can_position=false", + .src = { 0, 0, 1023 << 16, 767 << 16 }, + .crtc = { 0, 0, 1023, 767 }, + .rotation = DRM_MODE_ROTATE_0, + .min_scale = DRM_PLANE_NO_SCALING, + .max_scale = DRM_PLANE_NO_SCALING, + .can_position = false, + }, + { + .name = "upscaling_invalid", + .msg = "Upscaling out of range should fail", + .src = { 0, 0, 512 << 16, 384 << 16 }, + .crtc = { 0, 0, 1024, 768 }, + .rotation = DRM_MODE_ROTATE_0, + .min_scale = 0x8001, + .max_scale = DRM_PLANE_NO_SCALING, + .can_position = false, + }, + { + .name = "downscaling_invalid", + .msg = "Downscaling out of range should fail", + .src = { 0, 0, 2048 << 16, 1536 << 16 }, + .crtc = { 0, 0, 1024, 768 }, + .rotation = DRM_MODE_ROTATE_0, + .min_scale = DRM_PLANE_NO_SCALING, + .max_scale = 0x1ffff, + .can_position = false, + }, +}; + +KUNIT_ARRAY_PARAM(drm_check_invalid_plane_state, drm_check_invalid_plane_state_tests, + drm_check_plane_state_desc); + static struct kunit_case drm_plane_helper_test[] = { - KUNIT_CASE(drm_test_check_plane_state), + KUNIT_CASE_PARAM(drm_test_check_plane_state, drm_check_plane_state_gen_params), + KUNIT_CASE_PARAM(drm_test_check_invalid_plane_state, + drm_check_invalid_plane_state_gen_params), {} }; static struct kunit_suite drm_plane_helper_test_suite = { .name = "drm_plane_helper", + .init = drm_plane_helper_init, .test_cases = drm_plane_helper_test, }; -- cgit From 47e1a59e60c688c5f95b67277202f05b7e84c189 Mon Sep 17 00:00:00 2001 From: Ankit Nautiyal Date: Tue, 11 Oct 2022 12:04:40 +0530 Subject: drm/i915/dp: Reset frl trained flag before restarting FRL training MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For cases where DP has HDMI2.1 sink and FRL Link issues are detected, reset the flag to state FRL trained status before restarting FRL training. Fixes: 9488a030ac91 ("drm/i915: Add support for enabling link status and recovery") Cc: Swati Sharma Cc: Ankit Nautiyal Cc: Uma Shankar (v2) Cc: Jani Nikula Signed-off-by: Ankit Nautiyal Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221011063447.904649-2-ankit.k.nautiyal@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index a060903891b2..1858dd7856b2 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -3961,6 +3961,8 @@ intel_dp_handle_hdmi_link_status_change(struct intel_dp *intel_dp) drm_dp_pcon_hdmi_frl_link_error_count(&intel_dp->aux, &intel_dp->attached_connector->base); + intel_dp->frl.is_trained = false; + /* Restart FRL training or fall back to TMDS mode */ intel_dp_check_frl_training(intel_dp); } -- cgit From 1e3d21a5b3a4e7af3ed5fa3772c221cb8c284df5 Mon Sep 17 00:00:00 2001 From: Ankit Nautiyal Date: Tue, 11 Oct 2022 12:04:41 +0530 Subject: drm/i915/dp: Remove whitespace at the end of function. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove extraline left after intel_dp_configure_protocol_converter. Signed-off-by: Ankit Nautiyal Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221011063447.904649-3-ankit.k.nautiyal@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 1858dd7856b2..7400d6b4c587 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -2690,7 +2690,6 @@ void intel_dp_configure_protocol_converter(struct intel_dp *intel_dp, str_enable_disable(tmp)); } - bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp) { u8 dprx = 0; -- cgit From 5bfcff516c89c57be6cd90af1d64529a51228ac1 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 5 Oct 2022 18:41:57 +0300 Subject: drm/i915: Extract intel_mmio_bar() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have the same code to determine the MMIO BAR in two places. Collect it to a single place. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221005154159.18750-1-ville.syrjala@linux.intel.com Reviewed-by: Matthew Auld --- drivers/gpu/drm/i915/gt/intel_gt.c | 2 +- drivers/gpu/drm/i915/i915_pci.c | 4 +--- drivers/gpu/drm/i915/intel_pci_config.h | 8 ++++++++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c b/drivers/gpu/drm/i915/gt/intel_gt.c index 27dbb9e4bd6c..2e796ffad911 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt.c +++ b/drivers/gpu/drm/i915/gt/intel_gt.c @@ -880,7 +880,7 @@ int intel_gt_probe_all(struct drm_i915_private *i915) unsigned int i; int ret; - mmio_bar = GRAPHICS_VER(i915) == 2 ? GEN2_GTTMMADR_BAR : GTTMMADR_BAR; + mmio_bar = intel_mmio_bar(GRAPHICS_VER(i915)); phys_addr = pci_resource_start(pdev, mmio_bar); /* diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c index 4757ad0173da..53c6b7cf7879 100644 --- a/drivers/gpu/drm/i915/i915_pci.c +++ b/drivers/gpu/drm/i915/i915_pci.c @@ -1295,9 +1295,7 @@ bool i915_pci_resource_valid(struct pci_dev *pdev, int bar) static bool intel_mmio_bar_valid(struct pci_dev *pdev, struct intel_device_info *intel_info) { - int gttmmaddr_bar = intel_info->__runtime.graphics.ip.ver == 2 ? GEN2_GTTMMADR_BAR : GTTMMADR_BAR; - - return i915_pci_resource_valid(pdev, gttmmaddr_bar); + return i915_pci_resource_valid(pdev, intel_mmio_bar(intel_info->__runtime.graphics.ip.ver)); } static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) diff --git a/drivers/gpu/drm/i915/intel_pci_config.h b/drivers/gpu/drm/i915/intel_pci_config.h index 4977a524ce6f..305f137d2ebd 100644 --- a/drivers/gpu/drm/i915/intel_pci_config.h +++ b/drivers/gpu/drm/i915/intel_pci_config.h @@ -13,6 +13,14 @@ #define GTT_APERTURE_BAR GFXMEM_BAR #define GEN12_LMEM_BAR GFXMEM_BAR +static inline int intel_mmio_bar(int graphics_ver) +{ + switch (graphics_ver) { + case 2: return GEN2_GTTMMADR_BAR; + default: return GTTMMADR_BAR; + } +} + /* BSM in include/drm/i915_drm.h */ #define MCHBAR_I915 0x44 -- cgit From 0492a34c832473190ff9bf65fd080b7fcb9a0af2 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 5 Oct 2022 22:56:46 +0300 Subject: drm/i915: Name our BARs based on the spec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We use all kinds of weird names for our base address registers. Take the names from the spec and stick to them to avoid confusing everyone. The only exceptions are IOBAR and LMEMBAR since naming them IOBAR_BAR and LMEMBAR_BAR looks too funny, and yet I think that adding the _BAR to GTTMMADR & co. (which don't have one in the spec name) does make it more clear what they are. And IOBAR vs. GTTMMADR_BAR also looks a bit too inconsistent for my taste. v2: Fix gvt build v3: Add GEN2_IO_BAR for completeness Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221005195646.17201-1-ville.syrjala@linux.intel.com Acked-by: Matthew Auld --- drivers/gpu/drm/i915/display/intel_lpe_audio.c | 4 ++-- drivers/gpu/drm/i915/gt/intel_ggtt.c | 12 ++++++------ drivers/gpu/drm/i915/gvt/cfg_space.c | 4 ++-- drivers/gpu/drm/i915/intel_pci_config.h | 24 +++++++++++++++++------- 4 files changed, 27 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_lpe_audio.c b/drivers/gpu/drm/i915/display/intel_lpe_audio.c index dca6003ccac8..389ccdc46a1e 100644 --- a/drivers/gpu/drm/i915/display/intel_lpe_audio.c +++ b/drivers/gpu/drm/i915/display/intel_lpe_audio.c @@ -101,9 +101,9 @@ lpe_audio_platdev_create(struct drm_i915_private *dev_priv) rsc[0].flags = IORESOURCE_IRQ; rsc[0].name = "hdmi-lpe-audio-irq"; - rsc[1].start = pci_resource_start(pdev, GTTMMADR_BAR) + + rsc[1].start = pci_resource_start(pdev, GEN4_GTTMMADR_BAR) + I915_HDMI_LPE_AUDIO_BASE; - rsc[1].end = pci_resource_start(pdev, GTTMMADR_BAR) + + rsc[1].end = pci_resource_start(pdev, GEN4_GTTMMADR_BAR) + I915_HDMI_LPE_AUDIO_BASE + I915_HDMI_LPE_AUDIO_SIZE - 1; rsc[1].flags = IORESOURCE_MEM; rsc[1].name = "hdmi-lpe-audio-mmio"; diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt.c b/drivers/gpu/drm/i915/gt/intel_ggtt.c index 6b58c95ad6a0..619a073a06ff 100644 --- a/drivers/gpu/drm/i915/gt/intel_ggtt.c +++ b/drivers/gpu/drm/i915/gt/intel_ggtt.c @@ -871,8 +871,8 @@ static int ggtt_probe_common(struct i915_ggtt *ggtt, u64 size) u32 pte_flags; int ret; - GEM_WARN_ON(pci_resource_len(pdev, GTTMMADR_BAR) != gen6_gttmmadr_size(i915)); - phys_addr = pci_resource_start(pdev, GTTMMADR_BAR) + gen6_gttadr_offset(i915); + GEM_WARN_ON(pci_resource_len(pdev, GEN4_GTTMMADR_BAR) != gen6_gttmmadr_size(i915)); + phys_addr = pci_resource_start(pdev, GEN4_GTTMMADR_BAR) + gen6_gttadr_offset(i915); /* * On BXT+/ICL+ writes larger than 64 bit to the GTT pagetable range @@ -932,10 +932,10 @@ static int gen8_gmch_probe(struct i915_ggtt *ggtt) u16 snb_gmch_ctl; if (!HAS_LMEM(i915) && !HAS_BAR2_SMEM_STOLEN(i915)) { - if (!i915_pci_resource_valid(pdev, GTT_APERTURE_BAR)) + if (!i915_pci_resource_valid(pdev, GEN4_GMADR_BAR)) return -ENXIO; - ggtt->gmadr = pci_resource(pdev, GTT_APERTURE_BAR); + ggtt->gmadr = pci_resource(pdev, GEN4_GMADR_BAR); ggtt->mappable_end = resource_size(&ggtt->gmadr); } @@ -1089,10 +1089,10 @@ static int gen6_gmch_probe(struct i915_ggtt *ggtt) unsigned int size; u16 snb_gmch_ctl; - if (!i915_pci_resource_valid(pdev, GTT_APERTURE_BAR)) + if (!i915_pci_resource_valid(pdev, GEN4_GMADR_BAR)) return -ENXIO; - ggtt->gmadr = pci_resource(pdev, GTT_APERTURE_BAR); + ggtt->gmadr = pci_resource(pdev, GEN4_GMADR_BAR); ggtt->mappable_end = resource_size(&ggtt->gmadr); /* diff --git a/drivers/gpu/drm/i915/gvt/cfg_space.c b/drivers/gpu/drm/i915/gvt/cfg_space.c index eef3bba8a41b..357c5b65e097 100644 --- a/drivers/gpu/drm/i915/gvt/cfg_space.c +++ b/drivers/gpu/drm/i915/gvt/cfg_space.c @@ -354,9 +354,9 @@ void intel_vgpu_init_cfg_space(struct intel_vgpu *vgpu, memset(vgpu_cfg_space(vgpu) + INTEL_GVT_PCI_OPREGION, 0, 4); vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_GTTMMIO].size = - pci_resource_len(pdev, GTTMMADR_BAR); + pci_resource_len(pdev, GEN4_GTTMMADR_BAR); vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_APERTURE].size = - pci_resource_len(pdev, GTT_APERTURE_BAR); + pci_resource_len(pdev, GEN4_GMADR_BAR); memset(vgpu_cfg_space(vgpu) + PCI_ROM_ADDRESS, 0, 4); diff --git a/drivers/gpu/drm/i915/intel_pci_config.h b/drivers/gpu/drm/i915/intel_pci_config.h index 305f137d2ebd..23b8e519f333 100644 --- a/drivers/gpu/drm/i915/intel_pci_config.h +++ b/drivers/gpu/drm/i915/intel_pci_config.h @@ -7,17 +7,27 @@ #define __INTEL_PCI_CONFIG_H__ /* PCI BARs */ -#define GTTMMADR_BAR 0 -#define GEN2_GTTMMADR_BAR 1 -#define GFXMEM_BAR 2 -#define GTT_APERTURE_BAR GFXMEM_BAR -#define GEN12_LMEM_BAR GFXMEM_BAR +#define GEN2_GMADR_BAR 0 +#define GEN2_MMADR_BAR 1 /* MMIO+GTT, despite the name */ +#define GEN2_IO_BAR 2 /* 85x/865 */ + +#define GEN3_MMADR_BAR 0 /* MMIO only */ +#define GEN3_IO_BAR 1 +#define GEN3_GMADR_BAR 2 +#define GEN3_GTTADR_BAR 3 /* GTT only */ + +#define GEN4_GTTMMADR_BAR 0 /* MMIO+GTT */ +#define GEN4_GMADR_BAR 2 +#define GEN4_IO_BAR 4 + +#define GEN12_LMEM_BAR 2 static inline int intel_mmio_bar(int graphics_ver) { switch (graphics_ver) { - case 2: return GEN2_GTTMMADR_BAR; - default: return GTTMMADR_BAR; + case 2: return GEN2_MMADR_BAR; + case 3: return GEN3_MMADR_BAR; + default: return GEN4_GTTMMADR_BAR; } } -- cgit From 03eababbf383e6340ef900c91315c97bd9cdd0b7 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 5 Oct 2022 18:41:59 +0300 Subject: drm/i915: s/HAS_BAR2_SMEM_STOLEN/HAS_LMEMBAR_SMEM_STOLEN/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The fact that LMEMBAR is BAR2 should be of no real interest to anyone. So use the name of the BAR rather than its index. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221005154159.18750-3-ville.syrjala@linux.intel.com Acked-by: Matthew Auld --- drivers/gpu/drm/i915/gem/i915_gem_stolen.c | 14 +++++++------- drivers/gpu/drm/i915/gt/intel_ggtt.c | 2 +- drivers/gpu/drm/i915/i915_drv.h | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c index 1e00cf4d3ace..0c70711818ed 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c @@ -79,7 +79,7 @@ void i915_gem_stolen_remove_node(struct drm_i915_private *i915, static bool valid_stolen_size(struct drm_i915_private *i915, struct resource *dsm) { - return (dsm->start != 0 || HAS_BAR2_SMEM_STOLEN(i915)) && dsm->end > dsm->start; + return (dsm->start != 0 || HAS_LMEMBAR_SMEM_STOLEN(i915)) && dsm->end > dsm->start; } static int adjust_stolen(struct drm_i915_private *i915, @@ -151,9 +151,9 @@ static int request_smem_stolen(struct drm_i915_private *i915, * address range since it's local to the gpu. * * Starting MTL, in IGFX devices the stolen memory is exposed via - * BAR2 and shall be considered similar to stolen lmem. + * LMEMBAR and shall be considered similar to stolen lmem. */ - if (HAS_LMEM(i915) || HAS_BAR2_SMEM_STOLEN(i915)) + if (HAS_LMEM(i915) || HAS_LMEMBAR_SMEM_STOLEN(i915)) return 0; /* @@ -406,7 +406,7 @@ static void icl_get_stolen_reserved(struct drm_i915_private *i915, MISSING_CASE(reg_val & GEN8_STOLEN_RESERVED_SIZE_MASK); } - if (HAS_BAR2_SMEM_STOLEN(i915)) + if (HAS_LMEMBAR_SMEM_STOLEN(i915)) /* the base is initialized to stolen top so subtract size to get base */ *base -= *size; else @@ -881,7 +881,7 @@ i915_gem_stolen_lmem_setup(struct drm_i915_private *i915, u16 type, if (!i915_pci_resource_valid(pdev, GEN12_LMEM_BAR)) return ERR_PTR(-ENXIO); - if (HAS_BAR2_SMEM_STOLEN(i915) || IS_DG1(i915)) { + if (HAS_LMEMBAR_SMEM_STOLEN(i915) || IS_DG1(i915)) { lmem_size = pci_resource_len(pdev, GEN12_LMEM_BAR); } else { resource_size_t lmem_range; @@ -891,7 +891,7 @@ i915_gem_stolen_lmem_setup(struct drm_i915_private *i915, u16 type, lmem_size *= SZ_1G; } - if (HAS_BAR2_SMEM_STOLEN(i915)) { + if (HAS_LMEMBAR_SMEM_STOLEN(i915)) { /* * MTL dsm size is in GGC register. * Also MTL uses offset to DSMBASE in ptes, so i915 @@ -917,7 +917,7 @@ i915_gem_stolen_lmem_setup(struct drm_i915_private *i915, u16 type, } io_size = dsm_size; - if (HAS_BAR2_SMEM_STOLEN(i915)) { + if (HAS_LMEMBAR_SMEM_STOLEN(i915)) { io_start = pci_resource_start(pdev, GEN12_LMEM_BAR) + SZ_8M; } else if (pci_resource_len(pdev, GEN12_LMEM_BAR) < lmem_size) { io_start = 0; diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt.c b/drivers/gpu/drm/i915/gt/intel_ggtt.c index 619a073a06ff..2518cebbf931 100644 --- a/drivers/gpu/drm/i915/gt/intel_ggtt.c +++ b/drivers/gpu/drm/i915/gt/intel_ggtt.c @@ -931,7 +931,7 @@ static int gen8_gmch_probe(struct i915_ggtt *ggtt) unsigned int size; u16 snb_gmch_ctl; - if (!HAS_LMEM(i915) && !HAS_BAR2_SMEM_STOLEN(i915)) { + if (!HAS_LMEM(i915) && !HAS_LMEMBAR_SMEM_STOLEN(i915)) { if (!i915_pci_resource_valid(pdev, GEN4_GMADR_BAR)) return -ENXIO; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 74a1a646878b..28ee5ac166db 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -970,8 +970,8 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915, #define HAS_ONE_EU_PER_FUSE_BIT(i915) (INTEL_INFO(i915)->has_one_eu_per_fuse_bit) -#define HAS_BAR2_SMEM_STOLEN(i915) (!HAS_LMEM(i915) && \ - GRAPHICS_VER_FULL(i915) >= IP_VER(12, 70)) +#define HAS_LMEMBAR_SMEM_STOLEN(i915) (!HAS_LMEM(i915) && \ + GRAPHICS_VER_FULL(i915) >= IP_VER(12, 70)) /* intel_device_info.c */ static inline struct intel_device_info * -- cgit From 6407cf533217e09dfd895e64984c3f1ee3802373 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Thu, 20 Oct 2022 14:08:41 +0100 Subject: drm/i915/selftests: Stop using kthread_stop() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since a7c01fa93aeb ("signal: break out of wait loops on kthread_stop()") kthread_stop() started asserting a pending signal which wreaks havoc with a few of our selftests. Mainly because they are not fully expecting to handle signals, but also cutting the intended test runtimes short due signal_pending() now returning true (via __igt_timeout), which therefore breaks both the patterns of: kthread_run() ..sleep for igt_timeout_ms to allow test to exercise stuff.. kthread_stop() And check for errors recorded in the thread. And also: Main thread | Test thread ---------------+------------------------------ kthread_run() | kthread_stop() | do stuff until __igt_timeout | -- exits early due signal -- Where this kthread_stop() was assume would have a "join" semantics, which it would have had if not the new signal assertion issue. To recap, threads are now likely to catch a previously impossible ERESTARTSYS or EINTR, marking the test as failed, or have a pointlessly short run time. To work around this start using kthread_work(er) API which provides an explicit way of waiting for threads to exit. And for cases where parent controls the test duration we add explicit signaling which threads will now use instead of relying on kthread_should_stop(). Signed-off-by: Tvrtko Ursulin Cc: Ville Syrjälä Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221020130841.3845791-1-tvrtko.ursulin@linux.intel.com --- .../gpu/drm/i915/gem/selftests/i915_gem_context.c | 118 +++++----- drivers/gpu/drm/i915/gt/selftest_execlists.c | 48 ++-- drivers/gpu/drm/i915/gt/selftest_hangcheck.c | 51 +++-- drivers/gpu/drm/i915/selftests/i915_request.c | 252 +++++++++++++-------- 4 files changed, 281 insertions(+), 188 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c index c6ad67b90e8a..d8864444432b 100644 --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c @@ -179,97 +179,108 @@ out_file: } struct parallel_switch { - struct task_struct *tsk; + struct kthread_worker *worker; + struct kthread_work work; struct intel_context *ce[2]; + int result; }; -static int __live_parallel_switch1(void *data) +static void __live_parallel_switch1(struct kthread_work *work) { - struct parallel_switch *arg = data; + struct parallel_switch *arg = + container_of(work, typeof(*arg), work); IGT_TIMEOUT(end_time); unsigned long count; count = 0; + arg->result = 0; do { struct i915_request *rq = NULL; - int err, n; + int n; - err = 0; - for (n = 0; !err && n < ARRAY_SIZE(arg->ce); n++) { + for (n = 0; !arg->result && n < ARRAY_SIZE(arg->ce); n++) { struct i915_request *prev = rq; rq = i915_request_create(arg->ce[n]); if (IS_ERR(rq)) { i915_request_put(prev); - return PTR_ERR(rq); + arg->result = PTR_ERR(rq); + break; } i915_request_get(rq); if (prev) { - err = i915_request_await_dma_fence(rq, &prev->fence); + arg->result = + i915_request_await_dma_fence(rq, + &prev->fence); i915_request_put(prev); } i915_request_add(rq); } + + if (IS_ERR_OR_NULL(rq)) + break; + if (i915_request_wait(rq, 0, HZ) < 0) - err = -ETIME; + arg->result = -ETIME; + i915_request_put(rq); - if (err) - return err; count++; - } while (!__igt_timeout(end_time, NULL)); + } while (!arg->result && !__igt_timeout(end_time, NULL)); - pr_info("%s: %lu switches (sync)\n", arg->ce[0]->engine->name, count); - return 0; + pr_info("%s: %lu switches (sync) <%d>\n", + arg->ce[0]->engine->name, count, arg->result); } -static int __live_parallel_switchN(void *data) +static void __live_parallel_switchN(struct kthread_work *work) { - struct parallel_switch *arg = data; + struct parallel_switch *arg = + container_of(work, typeof(*arg), work); struct i915_request *rq = NULL; IGT_TIMEOUT(end_time); unsigned long count; int n; count = 0; + arg->result = 0; do { - for (n = 0; n < ARRAY_SIZE(arg->ce); n++) { + for (n = 0; !arg->result && n < ARRAY_SIZE(arg->ce); n++) { struct i915_request *prev = rq; - int err = 0; rq = i915_request_create(arg->ce[n]); if (IS_ERR(rq)) { i915_request_put(prev); - return PTR_ERR(rq); + arg->result = PTR_ERR(rq); + break; } i915_request_get(rq); if (prev) { - err = i915_request_await_dma_fence(rq, &prev->fence); + arg->result = + i915_request_await_dma_fence(rq, + &prev->fence); i915_request_put(prev); } i915_request_add(rq); - if (err) { - i915_request_put(rq); - return err; - } } count++; - } while (!__igt_timeout(end_time, NULL)); - i915_request_put(rq); + } while (!arg->result && !__igt_timeout(end_time, NULL)); - pr_info("%s: %lu switches (many)\n", arg->ce[0]->engine->name, count); - return 0; + if (!IS_ERR_OR_NULL(rq)) + i915_request_put(rq); + + pr_info("%s: %lu switches (many) <%d>\n", + arg->ce[0]->engine->name, count, arg->result); } static int live_parallel_switch(void *arg) { struct drm_i915_private *i915 = arg; - static int (* const func[])(void *arg) = { + static void (* const func[])(struct kthread_work *) = { __live_parallel_switch1, __live_parallel_switchN, NULL, @@ -277,7 +288,7 @@ static int live_parallel_switch(void *arg) struct parallel_switch *data = NULL; struct i915_gem_engines *engines; struct i915_gem_engines_iter it; - int (* const *fn)(void *arg); + void (* const *fn)(struct kthread_work *); struct i915_gem_context *ctx; struct intel_context *ce; struct file *file; @@ -348,9 +359,22 @@ static int live_parallel_switch(void *arg) } } + for (n = 0; n < count; n++) { + struct kthread_worker *worker; + + if (!data[n].ce[0]) + continue; + + worker = kthread_create_worker(0, "igt/parallel:%s", + data[n].ce[0]->engine->name); + if (IS_ERR(worker)) + goto out; + + data[n].worker = worker; + } + for (fn = func; !err && *fn; fn++) { struct igt_live_test t; - int n; err = igt_live_test_begin(&t, i915, __func__, ""); if (err) @@ -360,30 +384,17 @@ static int live_parallel_switch(void *arg) if (!data[n].ce[0]) continue; - data[n].tsk = kthread_run(*fn, &data[n], - "igt/parallel:%s", - data[n].ce[0]->engine->name); - if (IS_ERR(data[n].tsk)) { - err = PTR_ERR(data[n].tsk); - break; - } - get_task_struct(data[n].tsk); + data[n].result = 0; + kthread_init_work(&data[n].work, *fn); + kthread_queue_work(data[n].worker, &data[n].work); } - yield(); /* start all threads before we kthread_stop() */ - for (n = 0; n < count; n++) { - int status; - - if (IS_ERR_OR_NULL(data[n].tsk)) - continue; - - status = kthread_stop(data[n].tsk); - if (status && !err) - err = status; - - put_task_struct(data[n].tsk); - data[n].tsk = NULL; + if (data[n].ce[0]) { + kthread_flush_work(&data[n].work); + if (data[n].result && !err) + err = data[n].result; + } } if (igt_live_test_end(&t)) @@ -399,6 +410,9 @@ out: intel_context_unpin(data[n].ce[m]); intel_context_put(data[n].ce[m]); } + + if (data[n].worker) + kthread_destroy_worker(data[n].worker); } kfree(data); out_file: diff --git a/drivers/gpu/drm/i915/gt/selftest_execlists.c b/drivers/gpu/drm/i915/gt/selftest_execlists.c index 56b7d5b5fea0..2c7c053a8808 100644 --- a/drivers/gpu/drm/i915/gt/selftest_execlists.c +++ b/drivers/gpu/drm/i915/gt/selftest_execlists.c @@ -3473,12 +3473,14 @@ static int random_priority(struct rnd_state *rnd) struct preempt_smoke { struct intel_gt *gt; + struct kthread_work work; struct i915_gem_context **contexts; struct intel_engine_cs *engine; struct drm_i915_gem_object *batch; unsigned int ncontext; struct rnd_state prng; unsigned long count; + int result; }; static struct i915_gem_context *smoke_context(struct preempt_smoke *smoke) @@ -3538,34 +3540,31 @@ unpin: return err; } -static int smoke_crescendo_thread(void *arg) +static void smoke_crescendo_work(struct kthread_work *work) { - struct preempt_smoke *smoke = arg; + struct preempt_smoke *smoke = container_of(work, typeof(*smoke), work); IGT_TIMEOUT(end_time); unsigned long count; count = 0; do { struct i915_gem_context *ctx = smoke_context(smoke); - int err; - err = smoke_submit(smoke, - ctx, count % I915_PRIORITY_MAX, - smoke->batch); - if (err) - return err; + smoke->result = smoke_submit(smoke, ctx, + count % I915_PRIORITY_MAX, + smoke->batch); count++; - } while (count < smoke->ncontext && !__igt_timeout(end_time, NULL)); + } while (!smoke->result && count < smoke->ncontext && + !__igt_timeout(end_time, NULL)); smoke->count = count; - return 0; } static int smoke_crescendo(struct preempt_smoke *smoke, unsigned int flags) #define BATCH BIT(0) { - struct task_struct *tsk[I915_NUM_ENGINES] = {}; + struct kthread_worker *worker[I915_NUM_ENGINES] = {}; struct preempt_smoke *arg; struct intel_engine_cs *engine; enum intel_engine_id id; @@ -3576,6 +3575,8 @@ static int smoke_crescendo(struct preempt_smoke *smoke, unsigned int flags) if (!arg) return -ENOMEM; + memset(arg, 0, I915_NUM_ENGINES * sizeof(*arg)); + for_each_engine(engine, smoke->gt, id) { arg[id] = *smoke; arg[id].engine = engine; @@ -3583,31 +3584,28 @@ static int smoke_crescendo(struct preempt_smoke *smoke, unsigned int flags) arg[id].batch = NULL; arg[id].count = 0; - tsk[id] = kthread_run(smoke_crescendo_thread, arg, - "igt/smoke:%d", id); - if (IS_ERR(tsk[id])) { - err = PTR_ERR(tsk[id]); + worker[id] = kthread_create_worker(0, "igt/smoke:%d", id); + if (IS_ERR(worker[id])) { + err = PTR_ERR(worker[id]); break; } - get_task_struct(tsk[id]); - } - yield(); /* start all threads before we kthread_stop() */ + kthread_init_work(&arg[id].work, smoke_crescendo_work); + kthread_queue_work(worker[id], &arg[id].work); + } count = 0; for_each_engine(engine, smoke->gt, id) { - int status; - - if (IS_ERR_OR_NULL(tsk[id])) + if (IS_ERR_OR_NULL(worker[id])) continue; - status = kthread_stop(tsk[id]); - if (status && !err) - err = status; + kthread_flush_work(&arg[id].work); + if (arg[id].result && !err) + err = arg[id].result; count += arg[id].count; - put_task_struct(tsk[id]); + kthread_destroy_worker(worker[id]); } pr_info("Submitted %lu crescendo:%x requests across %d engines and %d contexts\n", diff --git a/drivers/gpu/drm/i915/gt/selftest_hangcheck.c b/drivers/gpu/drm/i915/gt/selftest_hangcheck.c index 7f3bb1d34dfb..71263058a7b0 100644 --- a/drivers/gpu/drm/i915/gt/selftest_hangcheck.c +++ b/drivers/gpu/drm/i915/gt/selftest_hangcheck.c @@ -866,10 +866,13 @@ static int igt_reset_active_engine(void *arg) } struct active_engine { - struct task_struct *task; + struct kthread_worker *worker; + struct kthread_work work; struct intel_engine_cs *engine; unsigned long resets; unsigned int flags; + bool stop; + int result; }; #define TEST_ACTIVE BIT(0) @@ -900,10 +903,10 @@ static int active_request_put(struct i915_request *rq) return err; } -static int active_engine(void *data) +static void active_engine(struct kthread_work *work) { I915_RND_STATE(prng); - struct active_engine *arg = data; + struct active_engine *arg = container_of(work, typeof(*arg), work); struct intel_engine_cs *engine = arg->engine; struct i915_request *rq[8] = {}; struct intel_context *ce[ARRAY_SIZE(rq)]; @@ -913,16 +916,17 @@ static int active_engine(void *data) for (count = 0; count < ARRAY_SIZE(ce); count++) { ce[count] = intel_context_create(engine); if (IS_ERR(ce[count])) { - err = PTR_ERR(ce[count]); - pr_err("[%s] Create context #%ld failed: %d!\n", engine->name, count, err); + arg->result = PTR_ERR(ce[count]); + pr_err("[%s] Create context #%ld failed: %d!\n", + engine->name, count, arg->result); while (--count) intel_context_put(ce[count]); - return err; + return; } } count = 0; - while (!kthread_should_stop()) { + while (!READ_ONCE(arg->stop)) { unsigned int idx = count++ & (ARRAY_SIZE(rq) - 1); struct i915_request *old = rq[idx]; struct i915_request *new; @@ -967,7 +971,7 @@ static int active_engine(void *data) intel_context_put(ce[count]); } - return err; + arg->result = err; } static int __igt_reset_engines(struct intel_gt *gt, @@ -1022,7 +1026,7 @@ static int __igt_reset_engines(struct intel_gt *gt, memset(threads, 0, sizeof(*threads) * I915_NUM_ENGINES); for_each_engine(other, gt, tmp) { - struct task_struct *tsk; + struct kthread_worker *worker; threads[tmp].resets = i915_reset_engine_count(global, other); @@ -1036,19 +1040,21 @@ static int __igt_reset_engines(struct intel_gt *gt, threads[tmp].engine = other; threads[tmp].flags = flags; - tsk = kthread_run(active_engine, &threads[tmp], - "igt/%s", other->name); - if (IS_ERR(tsk)) { - err = PTR_ERR(tsk); - pr_err("[%s] Thread spawn failed: %d!\n", engine->name, err); + worker = kthread_create_worker(0, "igt/%s", + other->name); + if (IS_ERR(worker)) { + err = PTR_ERR(worker); + pr_err("[%s] Worker create failed: %d!\n", + engine->name, err); goto unwind; } - threads[tmp].task = tsk; - get_task_struct(tsk); - } + threads[tmp].worker = worker; - yield(); /* start all threads before we begin */ + kthread_init_work(&threads[tmp].work, active_engine); + kthread_queue_work(threads[tmp].worker, + &threads[tmp].work); + } st_engine_heartbeat_disable_no_pm(engine); GEM_BUG_ON(test_and_set_bit(I915_RESET_ENGINE + id, @@ -1197,17 +1203,20 @@ unwind: for_each_engine(other, gt, tmp) { int ret; - if (!threads[tmp].task) + if (!threads[tmp].worker) continue; - ret = kthread_stop(threads[tmp].task); + WRITE_ONCE(threads[tmp].stop, true); + kthread_flush_work(&threads[tmp].work); + ret = READ_ONCE(threads[tmp].result); if (ret) { pr_err("kthread for other engine %s failed, err=%d\n", other->name, ret); if (!err) err = ret; } - put_task_struct(threads[tmp].task); + + kthread_destroy_worker(threads[tmp].worker); /* GuC based resets are not logged per engine */ if (!using_guc) { diff --git a/drivers/gpu/drm/i915/selftests/i915_request.c b/drivers/gpu/drm/i915/selftests/i915_request.c index 818a4909c1f3..a46350c37e9d 100644 --- a/drivers/gpu/drm/i915/selftests/i915_request.c +++ b/drivers/gpu/drm/i915/selftests/i915_request.c @@ -299,9 +299,18 @@ __live_request_alloc(struct intel_context *ce) return intel_context_create_request(ce); } -static int __igt_breadcrumbs_smoketest(void *arg) +struct smoke_thread { + struct kthread_worker *worker; + struct kthread_work work; + struct smoketest *t; + bool stop; + int result; +}; + +static void __igt_breadcrumbs_smoketest(struct kthread_work *work) { - struct smoketest *t = arg; + struct smoke_thread *thread = container_of(work, typeof(*thread), work); + struct smoketest *t = thread->t; const unsigned int max_batch = min(t->ncontexts, t->max_batch) - 1; const unsigned int total = 4 * t->ncontexts + 1; unsigned int num_waits = 0, num_fences = 0; @@ -320,8 +329,10 @@ static int __igt_breadcrumbs_smoketest(void *arg) */ requests = kcalloc(total, sizeof(*requests), GFP_KERNEL); - if (!requests) - return -ENOMEM; + if (!requests) { + thread->result = -ENOMEM; + return; + } order = i915_random_order(total, &prng); if (!order) { @@ -329,7 +340,7 @@ static int __igt_breadcrumbs_smoketest(void *arg) goto out_requests; } - while (!kthread_should_stop()) { + while (!READ_ONCE(thread->stop)) { struct i915_sw_fence *submit, *wait; unsigned int n, count; @@ -437,7 +448,7 @@ static int __igt_breadcrumbs_smoketest(void *arg) kfree(order); out_requests: kfree(requests); - return err; + thread->result = err; } static int mock_breadcrumbs_smoketest(void *arg) @@ -450,7 +461,7 @@ static int mock_breadcrumbs_smoketest(void *arg) .request_alloc = __mock_request_alloc }; unsigned int ncpus = num_online_cpus(); - struct task_struct **threads; + struct smoke_thread *threads; unsigned int n; int ret = 0; @@ -479,28 +490,37 @@ static int mock_breadcrumbs_smoketest(void *arg) } for (n = 0; n < ncpus; n++) { - threads[n] = kthread_run(__igt_breadcrumbs_smoketest, - &t, "igt/%d", n); - if (IS_ERR(threads[n])) { - ret = PTR_ERR(threads[n]); + struct kthread_worker *worker; + + worker = kthread_create_worker(0, "igt/%d", n); + if (IS_ERR(worker)) { + ret = PTR_ERR(worker); ncpus = n; break; } - get_task_struct(threads[n]); + threads[n].worker = worker; + threads[n].t = &t; + threads[n].stop = false; + threads[n].result = 0; + + kthread_init_work(&threads[n].work, + __igt_breadcrumbs_smoketest); + kthread_queue_work(worker, &threads[n].work); } - yield(); /* start all threads before we begin */ msleep(jiffies_to_msecs(i915_selftest.timeout_jiffies)); for (n = 0; n < ncpus; n++) { int err; - err = kthread_stop(threads[n]); + WRITE_ONCE(threads[n].stop, true); + kthread_flush_work(&threads[n].work); + err = READ_ONCE(threads[n].result); if (err < 0 && !ret) ret = err; - put_task_struct(threads[n]); + kthread_destroy_worker(threads[n].worker); } pr_info("Completed %lu waits for %lu fence across %d cpus\n", atomic_long_read(&t.num_waits), @@ -1419,9 +1439,18 @@ out_free: return err; } -static int __live_parallel_engine1(void *arg) +struct parallel_thread { + struct kthread_worker *worker; + struct kthread_work work; + struct intel_engine_cs *engine; + int result; +}; + +static void __live_parallel_engine1(struct kthread_work *work) { - struct intel_engine_cs *engine = arg; + struct parallel_thread *thread = + container_of(work, typeof(*thread), work); + struct intel_engine_cs *engine = thread->engine; IGT_TIMEOUT(end_time); unsigned long count; int err = 0; @@ -1452,12 +1481,14 @@ static int __live_parallel_engine1(void *arg) intel_engine_pm_put(engine); pr_info("%s: %lu request + sync\n", engine->name, count); - return err; + thread->result = err; } -static int __live_parallel_engineN(void *arg) +static void __live_parallel_engineN(struct kthread_work *work) { - struct intel_engine_cs *engine = arg; + struct parallel_thread *thread = + container_of(work, typeof(*thread), work); + struct intel_engine_cs *engine = thread->engine; IGT_TIMEOUT(end_time); unsigned long count; int err = 0; @@ -1479,7 +1510,7 @@ static int __live_parallel_engineN(void *arg) intel_engine_pm_put(engine); pr_info("%s: %lu requests\n", engine->name, count); - return err; + thread->result = err; } static bool wake_all(struct drm_i915_private *i915) @@ -1505,9 +1536,11 @@ static int wait_for_all(struct drm_i915_private *i915) return -ETIME; } -static int __live_parallel_spin(void *arg) +static void __live_parallel_spin(struct kthread_work *work) { - struct intel_engine_cs *engine = arg; + struct parallel_thread *thread = + container_of(work, typeof(*thread), work); + struct intel_engine_cs *engine = thread->engine; struct igt_spinner spin; struct i915_request *rq; int err = 0; @@ -1520,7 +1553,8 @@ static int __live_parallel_spin(void *arg) if (igt_spinner_init(&spin, engine->gt)) { wake_all(engine->i915); - return -ENOMEM; + thread->result = -ENOMEM; + return; } intel_engine_pm_get(engine); @@ -1553,22 +1587,22 @@ static int __live_parallel_spin(void *arg) out_spin: igt_spinner_fini(&spin); - return err; + thread->result = err; } static int live_parallel_engines(void *arg) { struct drm_i915_private *i915 = arg; - static int (* const func[])(void *arg) = { + static void (* const func[])(struct kthread_work *) = { __live_parallel_engine1, __live_parallel_engineN, __live_parallel_spin, NULL, }; const unsigned int nengines = num_uabi_engines(i915); + struct parallel_thread *threads; struct intel_engine_cs *engine; - int (* const *fn)(void *arg); - struct task_struct **tsk; + void (* const *fn)(struct kthread_work *); int err = 0; /* @@ -1576,8 +1610,8 @@ static int live_parallel_engines(void *arg) * tests that we load up the system maximally. */ - tsk = kcalloc(nengines, sizeof(*tsk), GFP_KERNEL); - if (!tsk) + threads = kcalloc(nengines, sizeof(*threads), GFP_KERNEL); + if (!threads) return -ENOMEM; for (fn = func; !err && *fn; fn++) { @@ -1594,37 +1628,44 @@ static int live_parallel_engines(void *arg) idx = 0; for_each_uabi_engine(engine, i915) { - tsk[idx] = kthread_run(*fn, engine, - "igt/parallel:%s", - engine->name); - if (IS_ERR(tsk[idx])) { - err = PTR_ERR(tsk[idx]); + struct kthread_worker *worker; + + worker = kthread_create_worker(0, "igt/parallel:%s", + engine->name); + if (IS_ERR(worker)) { + err = PTR_ERR(worker); break; } - get_task_struct(tsk[idx++]); - } - yield(); /* start all threads before we kthread_stop() */ + threads[idx].worker = worker; + threads[idx].result = 0; + threads[idx].engine = engine; + + kthread_init_work(&threads[idx].work, *fn); + kthread_queue_work(worker, &threads[idx].work); + idx++; + } idx = 0; for_each_uabi_engine(engine, i915) { int status; - if (IS_ERR(tsk[idx])) + if (!threads[idx].worker) break; - status = kthread_stop(tsk[idx]); + kthread_flush_work(&threads[idx].work); + status = READ_ONCE(threads[idx].result); if (status && !err) err = status; - put_task_struct(tsk[idx++]); + kthread_destroy_worker(threads[idx++].worker); } if (igt_live_test_end(&t)) err = -EIO; } - kfree(tsk); + kfree(threads); return err; } @@ -1672,7 +1713,7 @@ static int live_breadcrumbs_smoketest(void *arg) const unsigned int ncpus = num_online_cpus(); unsigned long num_waits, num_fences; struct intel_engine_cs *engine; - struct task_struct **threads; + struct smoke_thread *threads; struct igt_live_test live; intel_wakeref_t wakeref; struct smoketest *smoke; @@ -1746,23 +1787,26 @@ static int live_breadcrumbs_smoketest(void *arg) smoke[idx].max_batch, engine->name); for (n = 0; n < ncpus; n++) { - struct task_struct *tsk; + unsigned int i = idx * ncpus + n; + struct kthread_worker *worker; - tsk = kthread_run(__igt_breadcrumbs_smoketest, - &smoke[idx], "igt/%d.%d", idx, n); - if (IS_ERR(tsk)) { - ret = PTR_ERR(tsk); + worker = kthread_create_worker(0, "igt/%d.%d", idx, n); + if (IS_ERR(worker)) { + ret = PTR_ERR(worker); goto out_flush; } - get_task_struct(tsk); - threads[idx * ncpus + n] = tsk; + threads[i].worker = worker; + threads[i].t = &smoke[idx]; + + kthread_init_work(&threads[i].work, + __igt_breadcrumbs_smoketest); + kthread_queue_work(worker, &threads[i].work); } idx++; } - yield(); /* start all threads before we begin */ msleep(jiffies_to_msecs(i915_selftest.timeout_jiffies)); out_flush: @@ -1771,17 +1815,19 @@ out_flush: num_fences = 0; for_each_uabi_engine(engine, i915) { for (n = 0; n < ncpus; n++) { - struct task_struct *tsk = threads[idx * ncpus + n]; + unsigned int i = idx * ncpus + n; int err; - if (!tsk) + if (!threads[i].worker) continue; - err = kthread_stop(tsk); + WRITE_ONCE(threads[i].stop, true); + kthread_flush_work(&threads[i].work); + err = READ_ONCE(threads[i].result); if (err < 0 && !ret) ret = err; - put_task_struct(tsk); + kthread_destroy_worker(threads[i].worker); } num_waits += atomic_long_read(&smoke[idx].num_waits); @@ -2891,9 +2937,18 @@ out: return err; } -static int p_sync0(void *arg) +struct p_thread { + struct perf_stats p; + struct kthread_worker *worker; + struct kthread_work work; + struct intel_engine_cs *engine; + int result; +}; + +static void p_sync0(struct kthread_work *work) { - struct perf_stats *p = arg; + struct p_thread *thread = container_of(work, typeof(*thread), work); + struct perf_stats *p = &thread->p; struct intel_engine_cs *engine = p->engine; struct intel_context *ce; IGT_TIMEOUT(end_time); @@ -2902,13 +2957,16 @@ static int p_sync0(void *arg) int err = 0; ce = intel_context_create(engine); - if (IS_ERR(ce)) - return PTR_ERR(ce); + if (IS_ERR(ce)) { + thread->result = PTR_ERR(ce); + return; + } err = intel_context_pin(ce); if (err) { intel_context_put(ce); - return err; + thread->result = err; + return; } if (intel_engine_supports_stats(engine)) { @@ -2958,12 +3016,13 @@ static int p_sync0(void *arg) intel_context_unpin(ce); intel_context_put(ce); - return err; + thread->result = err; } -static int p_sync1(void *arg) +static void p_sync1(struct kthread_work *work) { - struct perf_stats *p = arg; + struct p_thread *thread = container_of(work, typeof(*thread), work); + struct perf_stats *p = &thread->p; struct intel_engine_cs *engine = p->engine; struct i915_request *prev = NULL; struct intel_context *ce; @@ -2973,13 +3032,16 @@ static int p_sync1(void *arg) int err = 0; ce = intel_context_create(engine); - if (IS_ERR(ce)) - return PTR_ERR(ce); + if (IS_ERR(ce)) { + thread->result = PTR_ERR(ce); + return; + } err = intel_context_pin(ce); if (err) { intel_context_put(ce); - return err; + thread->result = err; + return; } if (intel_engine_supports_stats(engine)) { @@ -3031,12 +3093,13 @@ static int p_sync1(void *arg) intel_context_unpin(ce); intel_context_put(ce); - return err; + thread->result = err; } -static int p_many(void *arg) +static void p_many(struct kthread_work *work) { - struct perf_stats *p = arg; + struct p_thread *thread = container_of(work, typeof(*thread), work); + struct perf_stats *p = &thread->p; struct intel_engine_cs *engine = p->engine; struct intel_context *ce; IGT_TIMEOUT(end_time); @@ -3045,13 +3108,16 @@ static int p_many(void *arg) bool busy; ce = intel_context_create(engine); - if (IS_ERR(ce)) - return PTR_ERR(ce); + if (IS_ERR(ce)) { + thread->result = PTR_ERR(ce); + return; + } err = intel_context_pin(ce); if (err) { intel_context_put(ce); - return err; + thread->result = err; + return; } if (intel_engine_supports_stats(engine)) { @@ -3092,26 +3158,23 @@ static int p_many(void *arg) intel_context_unpin(ce); intel_context_put(ce); - return err; + thread->result = err; } static int perf_parallel_engines(void *arg) { struct drm_i915_private *i915 = arg; - static int (* const func[])(void *arg) = { + static void (* const func[])(struct kthread_work *) = { p_sync0, p_sync1, p_many, NULL, }; const unsigned int nengines = num_uabi_engines(i915); + void (* const *fn)(struct kthread_work *); struct intel_engine_cs *engine; - int (* const *fn)(void *arg); struct pm_qos_request qos; - struct { - struct perf_stats p; - struct task_struct *tsk; - } *engines; + struct p_thread *engines; int err = 0; engines = kcalloc(nengines, sizeof(*engines), GFP_KERNEL); @@ -3134,36 +3197,45 @@ static int perf_parallel_engines(void *arg) idx = 0; for_each_uabi_engine(engine, i915) { + struct kthread_worker *worker; + intel_engine_pm_get(engine); memset(&engines[idx].p, 0, sizeof(engines[idx].p)); - engines[idx].p.engine = engine; - engines[idx].tsk = kthread_run(*fn, &engines[idx].p, - "igt:%s", engine->name); - if (IS_ERR(engines[idx].tsk)) { - err = PTR_ERR(engines[idx].tsk); + worker = kthread_create_worker(0, "igt:%s", + engine->name); + if (IS_ERR(worker)) { + err = PTR_ERR(worker); intel_engine_pm_put(engine); break; } - get_task_struct(engines[idx++].tsk); - } + engines[idx].worker = worker; + engines[idx].result = 0; + engines[idx].p.engine = engine; + engines[idx].engine = engine; - yield(); /* start all threads before we kthread_stop() */ + kthread_init_work(&engines[idx].work, *fn); + kthread_queue_work(worker, &engines[idx].work); + idx++; + } idx = 0; for_each_uabi_engine(engine, i915) { int status; - if (IS_ERR(engines[idx].tsk)) + if (!engines[idx].worker) break; - status = kthread_stop(engines[idx].tsk); + kthread_flush_work(&engines[idx].work); + status = READ_ONCE(engines[idx].result); if (status && !err) err = status; intel_engine_pm_put(engine); - put_task_struct(engines[idx++].tsk); + + kthread_destroy_worker(engines[idx].worker); + idx++; } if (igt_live_test_end(&t)) -- cgit From 1f367ee9554af5d67c86f206e1d6889cc99f6f45 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Aug 2021 14:02:23 +0300 Subject: arm64: dts: zynqmp: Add ports for the DisplayPort subsystem The DPSUB DT bindings now specify ports to model the connections with the programmable logic and the DisplayPort output. Add them to the device tree. Signed-off-by: Laurent Pinchart Acked-by: Michal Simek --- arch/arm64/boot/dts/xilinx/zynqmp.dtsi | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi index a549265e55f6..307c76cd8544 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi +++ b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi @@ -930,6 +930,30 @@ <&zynqmp_dpdma ZYNQMP_DPDMA_VIDEO1>, <&zynqmp_dpdma ZYNQMP_DPDMA_VIDEO2>, <&zynqmp_dpdma ZYNQMP_DPDMA_GRAPHICS>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + }; + port@1 { + reg = <1>; + }; + port@2 { + reg = <2>; + }; + port@3 { + reg = <3>; + }; + port@4 { + reg = <4>; + }; + port@5 { + reg = <5>; + }; + }; }; }; }; -- cgit From ddcb8fa6514f2baf0fdb45e7ba12fbf3abb112c7 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Aug 2021 14:19:32 +0300 Subject: arm64: dts: zynqmp: zcu106a: Describe DisplayPort connector Add a device tree node to describe the DisplayPort connector, and connect it to the DPSUB output. Signed-off-by: Laurent Pinchart Acked-by: Michal Simek --- arch/arm64/boot/dts/xilinx/zynqmp-zcu106-revA.dts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu106-revA.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu106-revA.dts index e2dd72fe33ce..24a252317150 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu106-revA.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu106-revA.dts @@ -150,6 +150,18 @@ #clock-cells = <0>; clock-frequency = <114285000>; }; + + dpcon { + compatible = "dp-connector"; + label = "P11"; + type = "full-size"; + + port { + dpcon_in: endpoint { + remote-endpoint = <&dpsub_dp_out>; + }; + }; + }; }; &can1 { @@ -1015,4 +1027,12 @@ phy-names = "dp-phy0", "dp-phy1"; phys = <&psgtr 1 PHY_TYPE_DP 0 3>, <&psgtr 0 PHY_TYPE_DP 1 3>; + + ports { + port@5 { + dpsub_dp_out: endpoint { + remote-endpoint = <&dpcon_in>; + }; + }; + }; }; -- cgit From a47e8a46a7f02ab6e5b225bcaec4fd2c0bec5e6f Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Wed, 19 Oct 2022 15:24:37 -0700 Subject: drm/i915/xelpg: Fix write to MTL_MCR_SELECTOR A misplaced closing parenthesis caused the groupid/instanceid values to be considered part of the ternary operator's condition instead of being OR'd into the resulting value. Fixes: f32898c94a10 ("drm/i915/xelpg: Add multicast steering") Reported-by: kernel test robot Signed-off-by: Matt Roper Reviewed-by: Arun R Murthy Link: https://patchwork.freedesktop.org/patch/msgid/20221019222437.3035182-1-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/gt/intel_gt_mcr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_mcr.c b/drivers/gpu/drm/i915/gt/intel_gt_mcr.c index 0d2811724b00..46cf2f3d1e8e 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_mcr.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_mcr.c @@ -249,7 +249,7 @@ static u32 rw_with_mcr_steering_fw(struct intel_uncore *uncore, intel_uncore_write_fw(uncore, MTL_MCR_SELECTOR, REG_FIELD_PREP(MTL_MCR_GROUPID, group) | REG_FIELD_PREP(MTL_MCR_INSTANCEID, instance) | - (rw_flag == FW_REG_READ) ? GEN11_MCR_MULTICAST : 0); + (rw_flag == FW_REG_READ ? GEN11_MCR_MULTICAST : 0)); } else if (GRAPHICS_VER(uncore->i915) >= 11) { mcr_mask = GEN11_MCR_SLICE_MASK | GEN11_MCR_SUBSLICE_MASK; mcr_ss = GEN11_MCR_SLICE(group) | GEN11_MCR_SUBSLICE(instance); -- cgit From 5988a0acad32823743b1a078b60392047aae4118 Mon Sep 17 00:00:00 2001 From: Suraj Kandpal Date: Thu, 20 Oct 2022 16:16:35 +0530 Subject: drm/i915: Remove one use macro Remove one use macro for_each_connector_on_encoder which is only being used at intel_encoder_find_connector. Signed-off-by: Suraj Kandpal Reviewed-by: Arun R Murthy Reviewed-by: Jani Nikula Signed-off-by: Uma Shankar Link: https://patchwork.freedesktop.org/patch/msgid/20221020104635.874860-2-suraj.kandpal@intel.com --- drivers/gpu/drm/i915/display/intel_display.h | 4 ---- drivers/gpu/drm/i915/display/intel_modeset_setup.c | 16 ++++++++++++---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index dc335e03934e..918c8f432172 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -469,10 +469,6 @@ enum hpd_pin { list_for_each_entry((intel_encoder), &(dev)->mode_config.encoder_list, base.head) \ for_each_if((intel_encoder)->base.crtc == (__crtc)) -#define for_each_connector_on_encoder(dev, __encoder, intel_connector) \ - list_for_each_entry((intel_connector), &(dev)->mode_config.connector_list, base.head) \ - for_each_if((intel_connector)->base.encoder == (__encoder)) - #define for_each_old_intel_plane_in_state(__state, plane, old_plane_state, __i) \ for ((__i) = 0; \ (__i) < (__state)->base.dev->mode_config.num_total_plane && \ diff --git a/drivers/gpu/drm/i915/display/intel_modeset_setup.c b/drivers/gpu/drm/i915/display/intel_modeset_setup.c index cbfabd58b75a..5f56e0335ff0 100644 --- a/drivers/gpu/drm/i915/display/intel_modeset_setup.c +++ b/drivers/gpu/drm/i915/display/intel_modeset_setup.c @@ -205,13 +205,21 @@ static bool intel_crtc_has_encoders(struct intel_crtc *crtc) static struct intel_connector *intel_encoder_find_connector(struct intel_encoder *encoder) { - struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + struct drm_connector_list_iter conn_iter; struct intel_connector *connector; + struct intel_connector *found_connector = NULL; - for_each_connector_on_encoder(dev, &encoder->base, connector) - return connector; + drm_connector_list_iter_begin(&i915->drm, &conn_iter); + for_each_intel_connector_iter(connector, &conn_iter) { + if (&encoder->base == connector->base.encoder) { + found_connector = connector; + break; + } + } + drm_connector_list_iter_end(&conn_iter); - return NULL; + return found_connector; } static void intel_sanitize_fifo_underrun_reporting(const struct intel_crtc_state *crtc_state) -- cgit From 2bd0db4b3f0bd529f75b32538fc5a3775e3591c0 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 20 Oct 2022 12:39:38 +0300 Subject: drm/i915: Allow panel fixed modes to have differing sync polarities MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apparently some panels declare multiple modes with random sync polarities. Seems a bit weird, but looks like Windows/GOP doesn't care, so let follow suit and accept alternate fixed modes regardless of their sync polarities. v2: Don't pollute the DRM_ namespace with a define (Jani) Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/6968 Acked-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221020093938.27200-1-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_panel.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_panel.c b/drivers/gpu/drm/i915/display/intel_panel.c index 2b4b359b8342..69ce77711b7c 100644 --- a/drivers/gpu/drm/i915/display/intel_panel.c +++ b/drivers/gpu/drm/i915/display/intel_panel.c @@ -85,9 +85,10 @@ static bool is_alt_drrs_mode(const struct drm_display_mode *mode, static bool is_alt_fixed_mode(const struct drm_display_mode *mode, const struct drm_display_mode *preferred_mode) { - return drm_mode_match(mode, preferred_mode, - DRM_MODE_MATCH_FLAGS | - DRM_MODE_MATCH_3D_FLAGS) && + u32 sync_flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NHSYNC | + DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_NVSYNC; + + return (mode->flags & ~sync_flags) == (preferred_mode->flags & ~sync_flags) && mode->hdisplay == preferred_mode->hdisplay && mode->vdisplay == preferred_mode->vdisplay; } -- cgit From 4ab5953f0af77fd27895ca2e5cba7078a0f63583 Mon Sep 17 00:00:00 2001 From: Sean Hong Date: Fri, 21 Oct 2022 10:58:01 +0800 Subject: drm/panel-edp: Add INX N116BGE-EA2 (HW: C2) Add support for the INX - N116BGE-EA2 (HW: C2) panel. Signed-off-by: Sean Hong Reviewed-by: Douglas Anderson Signed-off-by: Douglas Anderson Link: https://patchwork.freedesktop.org/patch/msgid/20221021025801.2898500-1-sean.hong@quanta.corp-partner.google.com --- drivers/gpu/drm/panel/panel-edp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index 4b39d1dd9140..724b27a53299 100644 --- a/drivers/gpu/drm/panel/panel-edp.c +++ b/drivers/gpu/drm/panel/panel-edp.c @@ -1883,6 +1883,7 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a5d, &delay_200_500_e50, "NV116WHM-N45"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0ac5, &delay_200_500_e50, "NV116WHM-N4C"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1139, &delay_200_500_e80_d50, "N116BGE-EA2"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x114c, &innolux_n116bca_ea1.delay, "N116BCA-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1152, &delay_200_500_e80_d50, "N116BCN-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1154, &delay_200_500_e80_d50, "N116BCA-EA2"), -- cgit From 3facae0649648da1da6b1c36babc9b92998face0 Mon Sep 17 00:00:00 2001 From: Sean Hong Date: Fri, 21 Oct 2022 11:10:24 +0800 Subject: drm/panel-edp: Add INX N116BGE-EA2 (HW: C4) Add support for the INX - N116BGE-EA2 (HW: C4) panel. Signed-off-by: Sean Hong Reviewed-by: Douglas Anderson Signed-off-by: Douglas Anderson Link: https://patchwork.freedesktop.org/patch/msgid/20221021031024.2899082-1-sean.hong@quanta.corp-partner.google.com --- drivers/gpu/drm/panel/panel-edp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index 724b27a53299..5cb8dc2ebe18 100644 --- a/drivers/gpu/drm/panel/panel-edp.c +++ b/drivers/gpu/drm/panel/panel-edp.c @@ -1886,6 +1886,7 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('C', 'M', 'N', 0x1139, &delay_200_500_e80_d50, "N116BGE-EA2"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x114c, &innolux_n116bca_ea1.delay, "N116BCA-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1152, &delay_200_500_e80_d50, "N116BCN-EA1"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1153, &delay_200_500_e80_d50, "N116BGE-EA2"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1154, &delay_200_500_e80_d50, "N116BCA-EA2"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1247, &delay_200_500_e80_d50, "N120ACA-EA1"), -- cgit From 8a7a5b5f23377a1eb79b8cc47ba79d805767da47 Mon Sep 17 00:00:00 2001 From: Chengming Gui Date: Tue, 18 Oct 2022 17:31:38 +0800 Subject: drm/amdgpu: fix pstate setting issue [WHY] 0, original pstate X 1, ctx_A_create -> ctx_A->stable_pstate = X 2, ctx_A_set_pstate (Y) -> current pstate is Y (PEAK or STANDARD) 3, ctx_B_create -> ctx_B->stable_pstate = Y 4, ctx_A_destroy -> restore pstate to X 5, ctx_B_destroy -> restore pstate to Y Above sequence will cause final pstate is wrong (Y), should be original X. [HOW] When ctx_B create, if ctx_A touched pstate setting (not auto, stable_pstate_ctx != NULL), set ctx_B->stable_pstate the same value as ctx_A saved, if stable_pstate_ctx == NULL, fetch current pstate to fill ctx_B->stable_pstate. Signed-off-by: Chengming Gui Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c index f6d9d5da53cd..d2139ac12159 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c @@ -326,7 +326,10 @@ static int amdgpu_ctx_init(struct amdgpu_ctx_mgr *mgr, int32_t priority, if (r) return r; - ctx->stable_pstate = current_stable_pstate; + if (mgr->adev->pm.stable_pstate_ctx) + ctx->stable_pstate = mgr->adev->pm.stable_pstate_ctx->stable_pstate; + else + ctx->stable_pstate = current_stable_pstate; return 0; } -- cgit From 7e5632cdf68b2d2d53ab9d39daf6a545c2ac2045 Mon Sep 17 00:00:00 2001 From: Kenneth Feng Date: Wed, 19 Oct 2022 11:24:05 +0800 Subject: drm/amd/pm: update driver-if header for smu_v13_0_10 update driver-if header for smu_v13_0_10 and merge with smu_v13_0_0 Signed-off-by: Kenneth Feng Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- .../pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_0.h | 111 +++++++++++++++------ drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h | 2 +- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c | 6 +- 3 files changed, 84 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_0.h index 063f4a737605..b76f0f7e4299 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_0.h @@ -25,7 +25,7 @@ #define SMU13_DRIVER_IF_V13_0_0_H //Increment this version if SkuTable_t or BoardTable_t change -#define PPTABLE_VERSION 0x24 +#define PPTABLE_VERSION 0x26 #define NUM_GFXCLK_DPM_LEVELS 16 #define NUM_SOCCLK_DPM_LEVELS 8 @@ -109,6 +109,22 @@ #define FEATURE_SPARE_63_BIT 63 #define NUM_FEATURES 64 +#define ALLOWED_FEATURE_CTRL_DEFAULT 0xFFFFFFFFFFFFFFFFULL +#define ALLOWED_FEATURE_CTRL_SCPM ((1 << FEATURE_DPM_GFXCLK_BIT) | \ + (1 << FEATURE_DPM_GFX_POWER_OPTIMIZER_BIT) | \ + (1 << FEATURE_DPM_UCLK_BIT) | \ + (1 << FEATURE_DPM_FCLK_BIT) | \ + (1 << FEATURE_DPM_SOCCLK_BIT) | \ + (1 << FEATURE_DPM_MP0CLK_BIT) | \ + (1 << FEATURE_DPM_LINK_BIT) | \ + (1 << FEATURE_DPM_DCN_BIT) | \ + (1 << FEATURE_DS_GFXCLK_BIT) | \ + (1 << FEATURE_DS_SOCCLK_BIT) | \ + (1 << FEATURE_DS_FCLK_BIT) | \ + (1 << FEATURE_DS_LCLK_BIT) | \ + (1 << FEATURE_DS_DCFCLK_BIT) | \ + (1 << FEATURE_DS_UCLK_BIT)) + //For use with feature control messages typedef enum { FEATURE_PWR_ALL, @@ -133,6 +149,7 @@ typedef enum { #define DEBUG_OVERRIDE_DISABLE_DFLL 0x00000200 #define DEBUG_OVERRIDE_ENABLE_RLC_VF_BRINGUP_MODE 0x00000400 #define DEBUG_OVERRIDE_DFLL_MASTER_MODE 0x00000800 +#define DEBUG_OVERRIDE_ENABLE_PROFILING_MODE 0x00001000 // VR Mapping Bit Defines #define VR_MAPPING_VR_SELECT_MASK 0x01 @@ -262,15 +279,15 @@ typedef enum { } I2cControllerPort_e; typedef enum { - I2C_CONTROLLER_NAME_VR_GFX = 0, - I2C_CONTROLLER_NAME_VR_SOC, - I2C_CONTROLLER_NAME_VR_VMEMP, - I2C_CONTROLLER_NAME_VR_VDDIO, - I2C_CONTROLLER_NAME_LIQUID0, - I2C_CONTROLLER_NAME_LIQUID1, - I2C_CONTROLLER_NAME_PLX, - I2C_CONTROLLER_NAME_OTHER, - I2C_CONTROLLER_NAME_COUNT, + I2C_CONTROLLER_NAME_VR_GFX = 0, + I2C_CONTROLLER_NAME_VR_SOC, + I2C_CONTROLLER_NAME_VR_VMEMP, + I2C_CONTROLLER_NAME_VR_VDDIO, + I2C_CONTROLLER_NAME_LIQUID0, + I2C_CONTROLLER_NAME_LIQUID1, + I2C_CONTROLLER_NAME_PLX, + I2C_CONTROLLER_NAME_FAN_INTAKE, + I2C_CONTROLLER_NAME_COUNT, } I2cControllerName_e; typedef enum { @@ -282,16 +299,17 @@ typedef enum { I2C_CONTROLLER_THROTTLER_LIQUID0, I2C_CONTROLLER_THROTTLER_LIQUID1, I2C_CONTROLLER_THROTTLER_PLX, + I2C_CONTROLLER_THROTTLER_FAN_INTAKE, I2C_CONTROLLER_THROTTLER_INA3221, I2C_CONTROLLER_THROTTLER_COUNT, } I2cControllerThrottler_e; typedef enum { - I2C_CONTROLLER_PROTOCOL_VR_XPDE132G5, - I2C_CONTROLLER_PROTOCOL_VR_IR35217, - I2C_CONTROLLER_PROTOCOL_TMP_TMP102A, - I2C_CONTROLLER_PROTOCOL_INA3221, - I2C_CONTROLLER_PROTOCOL_COUNT, + I2C_CONTROLLER_PROTOCOL_VR_XPDE132G5, + I2C_CONTROLLER_PROTOCOL_VR_IR35217, + I2C_CONTROLLER_PROTOCOL_TMP_MAX31875, + I2C_CONTROLLER_PROTOCOL_INA3221, + I2C_CONTROLLER_PROTOCOL_COUNT, } I2cControllerProtocol_e; typedef struct { @@ -658,13 +676,20 @@ typedef struct { #define PP_NUM_OD_VF_CURVE_POINTS PP_NUM_RTAVFS_PWL_ZONES + 1 +typedef enum { + FAN_MODE_AUTO = 0, + FAN_MODE_MANUAL_LINEAR, +} FanMode_e; typedef struct { uint32_t FeatureCtrlMask; //Voltage control int16_t VoltageOffsetPerZoneBoundary[PP_NUM_OD_VF_CURVE_POINTS]; - uint16_t reserved[2]; + uint16_t VddGfxVmax; // in mV + + uint8_t IdlePwrSavingFeaturesCtrl; + uint8_t RuntimePwrSavingFeaturesCtrl; //Frequency changes int16_t GfxclkFmin; // MHz @@ -674,7 +699,7 @@ typedef struct { //PPT int16_t Ppt; // % - int16_t reserved1; + int16_t Tdc; //Fan control uint8_t FanLinearPwmPoints[NUM_OD_FAN_MAX_POINTS]; @@ -701,16 +726,19 @@ typedef struct { uint32_t FeatureCtrlMask; int16_t VoltageOffsetPerZoneBoundary; - uint16_t reserved[2]; + uint16_t VddGfxVmax; // in mV + + uint8_t IdlePwrSavingFeaturesCtrl; + uint8_t RuntimePwrSavingFeaturesCtrl; - uint16_t GfxclkFmin; // MHz - uint16_t GfxclkFmax; // MHz + int16_t GfxclkFmin; // MHz + int16_t GfxclkFmax; // MHz uint16_t UclkFmin; // MHz uint16_t UclkFmax; // MHz //PPT int16_t Ppt; // % - int16_t reserved1; + int16_t Tdc; uint8_t FanLinearPwmPoints; uint8_t FanLinearTempPoints; @@ -857,7 +885,8 @@ typedef struct { uint16_t FanStartTempMin; uint16_t FanStartTempMax; - uint32_t Spare[12]; + uint16_t PowerMinPpt0[POWER_SOURCE_COUNT]; + uint32_t Spare[11]; } MsgLimits_t; @@ -1041,7 +1070,17 @@ typedef struct { uint32_t GfxoffSpare[15]; // GFX GPO - uint32_t GfxGpoSpare[16]; + uint32_t DfllBtcMasterScalerM; + int32_t DfllBtcMasterScalerB; + uint32_t DfllBtcSlaveScalerM; + int32_t DfllBtcSlaveScalerB; + + uint32_t DfllPccAsWaitCtrl; //GDFLL_AS_WAIT_CTRL_PCC register value to be passed to RLC msg + uint32_t DfllPccAsStepCtrl; //GDFLL_AS_STEP_CTRL_PCC register value to be passed to RLC msg + + uint32_t DfllL2FrequencyBoostM; //Unitless (float) + uint32_t DfllL2FrequencyBoostB; //In MHz (integer) + uint32_t GfxGpoSpare[8]; // GFX DCS @@ -1114,12 +1153,14 @@ typedef struct { uint16_t IntakeTempHighIntakeAcousticLimit; uint16_t IntakeTempAcouticLimitReleaseRate; - uint16_t FanStalledTempLimitOffset; + int16_t FanAbnormalTempLimitOffset; uint16_t FanStalledTriggerRpm; - uint16_t FanAbnormalTriggerRpm; - uint16_t FanPadding; + uint16_t FanAbnormalTriggerRpmCoeff; + uint16_t FanAbnormalDetectionEnable; - uint32_t FanSpare[14]; + uint8_t FanIntakeSensorSupport; + uint8_t FanIntakePadding[3]; + uint32_t FanSpare[13]; // SECTION: VDD_GFX AVFS @@ -1198,8 +1239,13 @@ typedef struct { int16_t TotalBoardPowerM; int16_t TotalBoardPowerB; + //PMFW-11158 + QuadraticInt_t qFeffCoeffGameClock[POWER_SOURCE_COUNT]; + QuadraticInt_t qFeffCoeffBaseClock[POWER_SOURCE_COUNT]; + QuadraticInt_t qFeffCoeffBoostClock[POWER_SOURCE_COUNT]; + // SECTION: Sku Reserved - uint32_t Spare[61]; + uint32_t Spare[43]; // Padding for MMHUB - do not modify this uint32_t MmHubPadding[8]; @@ -1288,8 +1334,11 @@ typedef struct { uint32_t PostVoltageSetBacoDelay; // in microseconds. Amount of time FW will wait after power good is established or PSI0 command is issued uint32_t BacoEntryDelay; // in milliseconds. Amount of time FW will wait to trigger BACO entry after receiving entry notification from OS + uint8_t FuseWritePowerMuxPresent; + uint8_t FuseWritePadding[3]; + // SECTION: Board Reserved - uint32_t BoardSpare[64]; + uint32_t BoardSpare[63]; // SECTION: Structure Padding @@ -1381,7 +1430,7 @@ typedef struct { uint16_t AverageTotalBoardPower; uint16_t AvgTemperature[TEMP_COUNT]; - uint16_t TempPadding; + uint16_t AvgTemperatureFanIntake; uint8_t PcieRate ; uint8_t PcieWidth ; @@ -1550,5 +1599,7 @@ typedef struct { #define IH_INTERRUPT_CONTEXT_ID_AUDIO_D0 0x5 #define IH_INTERRUPT_CONTEXT_ID_AUDIO_D3 0x6 #define IH_INTERRUPT_CONTEXT_ID_THERMAL_THROTTLING 0x7 +#define IH_INTERRUPT_CONTEXT_ID_FAN_ABNORMAL 0x8 +#define IH_INTERRUPT_CONTEXT_ID_FAN_RECOVERY 0x9 #endif diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h index 8f72202aea8e..80fb583b18d9 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h @@ -30,7 +30,7 @@ #define SMU13_DRIVER_IF_VERSION_ALDE 0x08 #define SMU13_DRIVER_IF_VERSION_SMU_V13_0_4 0x07 #define SMU13_DRIVER_IF_VERSION_SMU_V13_0_5 0x04 -#define SMU13_DRIVER_IF_VERSION_SMU_V13_0_0 0x30 +#define SMU13_DRIVER_IF_VERSION_SMU_V13_0_0_10 0x32 #define SMU13_DRIVER_IF_VERSION_SMU_V13_0_7 0x2C #define SMU13_DRIVER_IF_VERSION_SMU_V13_0_10 0x1D diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c index c4552ade8d44..feb4d68f3fd9 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c @@ -289,7 +289,8 @@ int smu_v13_0_check_fw_version(struct smu_context *smu) smu->smc_driver_if_version = SMU13_DRIVER_IF_VERSION_ALDE; break; case IP_VERSION(13, 0, 0): - smu->smc_driver_if_version = SMU13_DRIVER_IF_VERSION_SMU_V13_0_0; + case IP_VERSION(13, 0, 10): + smu->smc_driver_if_version = SMU13_DRIVER_IF_VERSION_SMU_V13_0_0_10; break; case IP_VERSION(13, 0, 7): smu->smc_driver_if_version = SMU13_DRIVER_IF_VERSION_SMU_V13_0_7; @@ -305,9 +306,6 @@ int smu_v13_0_check_fw_version(struct smu_context *smu) case IP_VERSION(13, 0, 5): smu->smc_driver_if_version = SMU13_DRIVER_IF_VERSION_SMU_V13_0_5; break; - case IP_VERSION(13, 0, 10): - smu->smc_driver_if_version = SMU13_DRIVER_IF_VERSION_SMU_V13_0_10; - break; default: dev_err(adev->dev, "smu unsupported IP version: 0x%x.\n", adev->ip_versions[MP1_HWIP][0]); -- cgit From bb3c846ad26e1c8551f68078278cbd437a20fb64 Mon Sep 17 00:00:00 2001 From: Yiqing Yao Date: Tue, 18 Oct 2022 15:17:59 +0800 Subject: drm/amdgpu: Adjust MES polling timeout for sriov [why] MES response time in sriov may be longer than default value due to reset or init in other VF. A timeout value specific to sriov is needed. [how] When in sriov, adjust the timeout value to calculated worst case scenario. Signed-off-by: Yiqing Yao Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/mes_v11_0.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c index fef7d020bc5f..f141fadd2d86 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c @@ -98,7 +98,14 @@ static int mes_v11_0_submit_pkt_and_poll_completion(struct amdgpu_mes *mes, struct amdgpu_device *adev = mes->adev; struct amdgpu_ring *ring = &mes->ring; unsigned long flags; + signed long timeout = adev->usec_timeout; + if (amdgpu_emu_mode) { + timeout *= 100; + } else if (amdgpu_sriov_vf(adev)) { + /* Worst case in sriov where all other 15 VF timeout, each VF needs about 600ms */ + timeout = 15 * 600 * 1000; + } BUG_ON(size % 4 != 0); spin_lock_irqsave(&mes->ring_lock, flags); @@ -118,7 +125,7 @@ static int mes_v11_0_submit_pkt_and_poll_completion(struct amdgpu_mes *mes, DRM_DEBUG("MES msg=%d was emitted\n", x_pkt->header.opcode); r = amdgpu_fence_wait_polling(ring, ring->fence_drv.sync_seq, - adev->usec_timeout * (amdgpu_emu_mode ? 100 : 1)); + timeout); if (r < 1) { DRM_ERROR("MES failed to response msg=%d\n", x_pkt->header.opcode); -- cgit From 1beca7f1471e14802f7f6730ac9ac0a3de7c8f8b Mon Sep 17 00:00:00 2001 From: Alistair Popple Date: Wed, 19 Oct 2022 23:29:34 +1100 Subject: nouveau: Fix migrate_to_ram() for faulting page Commit 16ce101db85d ("mm/memory.c: fix race when faulting a device private page") changed the migrate_to_ram() callback to take a reference on the device page to ensure it can't be freed while handling the fault. Unfortunately the corresponding update to Nouveau to accommodate this change was inadvertently dropped from that patch causing GPU to CPU migration to fail so add it here. Signed-off-by: Alistair Popple Fixes: 16ce101db85d ("mm/memory.c: fix race when faulting a device private page") Cc: John Hubbard Cc: Ralph Campbell Cc: Lyude Paul Cc: Ben Skeggs Reviewed-by: Lyude Paul Signed-off-by: Lyude Paul Link: https://patchwork.freedesktop.org/patch/msgid/20221019122934.866205-1-apopple@nvidia.com --- drivers/gpu/drm/nouveau/nouveau_dmem.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/nouveau_dmem.c b/drivers/gpu/drm/nouveau/nouveau_dmem.c index 5fe209107246..20fe53815b20 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dmem.c +++ b/drivers/gpu/drm/nouveau/nouveau_dmem.c @@ -176,6 +176,7 @@ static vm_fault_t nouveau_dmem_migrate_to_ram(struct vm_fault *vmf) .src = &src, .dst = &dst, .pgmap_owner = drm->dev, + .fault_page = vmf->page, .flags = MIGRATE_VMA_SELECT_DEVICE_PRIVATE, }; -- cgit From ad50295ba8ca1f3a8d24bfa72414d8402c1992ca Mon Sep 17 00:00:00 2001 From: Zack Rusin Date: Thu, 20 Oct 2022 21:07:03 -0400 Subject: drm/nouveau: Remove unused variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Trivial removal of an unused variable. Not sure how it snuck by me and build bots in the 7c99616e3fe7. Fixes: 7c99616e3fe7 ("drm: Remove drm_mode_config::fb_base") Reported-by: Stephen Rothwell Cc: Laurent Pinchart Cc: Thomas Zimmermann Cc: Christian König Cc: Ben Skeggs Cc: Karol Herbst Cc: Lyude Paul Reviewed-by: Lyude Paul Signed-off-by: Zack Rusin Signed-off-by: Lyude Paul Link: https://patchwork.freedesktop.org/patch/msgid/20221021010703.536318-1-zack@kde.org --- drivers/gpu/drm/nouveau/nouveau_display.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 928fdfa8e8e5..2e97186090c8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -659,7 +659,6 @@ int nouveau_display_create(struct drm_device *dev) { struct nouveau_drm *drm = nouveau_drm(dev); - struct nvkm_device *device = nvxx_device(&drm->client.device); struct nouveau_display *disp; int ret; -- cgit From 16d2a3f2ad1d2b95bf9122c910c63b0efe74179d Mon Sep 17 00:00:00 2001 From: Yang Li Date: Mon, 17 Oct 2022 08:07:23 +0800 Subject: nouveau/dmem: Remove duplicated include in nouveau_dmem.c ./drivers/gpu/drm/nouveau/nouveau_dmem.c: nvif/if000c.h is included more than once. Link: https://bugzilla.openanolis.cn/show_bug.cgi?id=2404 Reported-by: Abaci Robot Signed-off-by: Yang Li Reviewed-by: Lyude Paul Signed-off-by: Lyude Paul Link: https://patchwork.freedesktop.org/patch/msgid/20221017000723.113744-1-yang.lee@linux.alibaba.com --- drivers/gpu/drm/nouveau/nouveau_dmem.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_dmem.c b/drivers/gpu/drm/nouveau/nouveau_dmem.c index 20fe53815b20..789857faa048 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dmem.c +++ b/drivers/gpu/drm/nouveau/nouveau_dmem.c @@ -33,7 +33,6 @@ #include #include #include -#include #include -- cgit From 4c35e5d1190058be31236876ae1f12681ddba137 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 20 Oct 2022 15:07:06 +0300 Subject: drm/i915: Activate DRRS after state readout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On BDW+ we have just the one set of DP M/N registers. The values we write into said registers depends on whether we want DRRS to be in high or low gear. This causes issues for the state checker which currently has to assume either set of M/N (high or low refresh rate) values may appear there. That sort of works for M/N itself, but all other values derived from the M/N (dotclock, pixel rate) are not handled correctly, leading to potential for state checker mismatches. Let's avoid all those problems by simply keeping DRRS in high gear until the state checker has done its hardware state readout. Note that hitting this issue presumable became very hard after commit 1b333c679a0f ("drm/i915: Do DRRS disable/enable during pre/post_plane_update()") since the state check would have to laze about for one full second (delay used by intel_drrs_schedule_work()) to see the low refresh rate. But it is still theoretically possible. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221020120706.25728-1-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_display.c | 43 +++++----------------------- 1 file changed, 7 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index d014d3ef35e4..92305f832ce7 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -1261,8 +1261,6 @@ static void intel_post_plane_update(struct intel_atomic_state *state, if (needs_cursorclk_wa(old_crtc_state) && !needs_cursorclk_wa(new_crtc_state)) icl_wa_cursorclkgating(dev_priv, pipe, false); - - intel_drrs_activate(new_crtc_state); } static void intel_crtc_enable_flip_done(struct intel_atomic_state *state, @@ -5646,39 +5644,6 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, PIPE_CONF_CHECK_I(name.y2); \ } while (0) -/* This is required for BDW+ where there is only one set of registers for - * switching between high and low RR. - * This macro can be used whenever a comparison has to be made between one - * hw state and multiple sw state variables. - */ -#define PIPE_CONF_CHECK_M_N_ALT(name, alt_name) do { \ - if (!intel_compare_link_m_n(¤t_config->name, \ - &pipe_config->name) && \ - !intel_compare_link_m_n(¤t_config->alt_name, \ - &pipe_config->name)) { \ - pipe_config_mismatch(fastset, crtc, __stringify(name), \ - "(expected tu %i data %i/%i link %i/%i, " \ - "or tu %i data %i/%i link %i/%i, " \ - "found tu %i, data %i/%i link %i/%i)", \ - current_config->name.tu, \ - current_config->name.data_m, \ - current_config->name.data_n, \ - current_config->name.link_m, \ - current_config->name.link_n, \ - current_config->alt_name.tu, \ - current_config->alt_name.data_m, \ - current_config->alt_name.data_n, \ - current_config->alt_name.link_m, \ - current_config->alt_name.link_n, \ - pipe_config->name.tu, \ - pipe_config->name.data_m, \ - pipe_config->name.data_n, \ - pipe_config->name.link_m, \ - pipe_config->name.link_n); \ - ret = false; \ - } \ -} while (0) - #define PIPE_CONF_CHECK_FLAGS(name, mask) do { \ if ((current_config->name ^ pipe_config->name) & (mask)) { \ pipe_config_mismatch(fastset, crtc, __stringify(name), \ @@ -5747,7 +5712,7 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, if (HAS_DOUBLE_BUFFERED_M_N(dev_priv)) { if (!fastset || !pipe_config->seamless_m_n) - PIPE_CONF_CHECK_M_N_ALT(dp_m_n, dp_m2_n2); + PIPE_CONF_CHECK_M_N(dp_m_n); } else { PIPE_CONF_CHECK_M_N(dp_m_n); PIPE_CONF_CHECK_M_N(dp_m2_n2); @@ -7615,6 +7580,12 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) intel_modeset_verify_crtc(crtc, state, old_crtc_state, new_crtc_state); + /* + * Activate DRRS after state readout to avoid + * dp_m_n vs. dp_m2_n2 confusion on BDW+. + */ + intel_drrs_activate(new_crtc_state); + /* * DSB cleanup is done in cleanup_work aligning with framebuffer * cleanup. So copy and reset the dsb structure to sync with -- cgit From 52a90349f2edb6bd7e56462a8c3416e15b8ded60 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 21 Oct 2022 19:24:39 +0300 Subject: drm/i915: Introduce intel_crtc_needs_fastset() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the somewhat obscure crtc_state.update_pipe checks with a more descriptive thing. Also nicely matches the intel_crtc_needs_modeset() counterpart for full modesets. v2: Handle one more case in the fbc code Reviewed-by: Jani Nikula #v1 Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221021162442.27283-2-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/hsw_ips.c | 6 ++--- drivers/gpu/drm/i915/display/intel_crtc.c | 2 +- drivers/gpu/drm/i915/display/intel_cursor.c | 6 +++-- drivers/gpu/drm/i915/display/intel_display.c | 28 ++++++++++++---------- drivers/gpu/drm/i915/display/intel_display_types.h | 6 +++++ drivers/gpu/drm/i915/display/intel_fbc.c | 3 ++- .../gpu/drm/i915/display/intel_modeset_verify.c | 3 ++- 7 files changed, 33 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/display/hsw_ips.c b/drivers/gpu/drm/i915/display/hsw_ips.c index a5be4af792cb..c23fabb76fda 100644 --- a/drivers/gpu/drm/i915/display/hsw_ips.c +++ b/drivers/gpu/drm/i915/display/hsw_ips.c @@ -105,7 +105,7 @@ static bool hsw_ips_need_disable(struct intel_atomic_state *state, */ if (IS_HASWELL(i915) && (new_crtc_state->uapi.color_mgmt_changed || - new_crtc_state->update_pipe) && + intel_crtc_needs_fastset(new_crtc_state)) && new_crtc_state->gamma_mode == GAMMA_MODE_MODE_SPLIT) return true; @@ -147,7 +147,7 @@ static bool hsw_ips_need_enable(struct intel_atomic_state *state, */ if (IS_HASWELL(i915) && (new_crtc_state->uapi.color_mgmt_changed || - new_crtc_state->update_pipe) && + intel_crtc_needs_fastset(new_crtc_state)) && new_crtc_state->gamma_mode == GAMMA_MODE_MODE_SPLIT) return true; @@ -155,7 +155,7 @@ static bool hsw_ips_need_enable(struct intel_atomic_state *state, * We can't read out IPS on broadwell, assume the worst and * forcibly enable IPS on the first fastset. */ - if (new_crtc_state->update_pipe && old_crtc_state->inherited) + if (intel_crtc_needs_fastset(new_crtc_state) && old_crtc_state->inherited) return true; return !old_crtc_state->ips_enabled; diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c index 6be1fe34c83b..af7dbac7ed32 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc.c +++ b/drivers/gpu/drm/i915/display/intel_crtc.c @@ -387,7 +387,7 @@ static bool intel_crtc_needs_vblank_work(const struct intel_crtc_state *crtc_sta !intel_crtc_needs_modeset(crtc_state) && !crtc_state->preload_luts && (crtc_state->uapi.color_mgmt_changed || - crtc_state->update_pipe); + intel_crtc_needs_fastset(crtc_state)); } static void intel_crtc_vblank_work(struct kthread_work *base) diff --git a/drivers/gpu/drm/i915/display/intel_cursor.c b/drivers/gpu/drm/i915/display/intel_cursor.c index 87899e89b3a7..96422c98656a 100644 --- a/drivers/gpu/drm/i915/display/intel_cursor.c +++ b/drivers/gpu/drm/i915/display/intel_cursor.c @@ -631,8 +631,10 @@ intel_legacy_cursor_update(struct drm_plane *_plane, * * FIXME bigjoiner fastpath would be good */ - if (!crtc_state->hw.active || intel_crtc_needs_modeset(crtc_state) || - crtc_state->update_pipe || crtc_state->bigjoiner_pipes) + if (!crtc_state->hw.active || + intel_crtc_needs_modeset(crtc_state) || + intel_crtc_needs_fastset(crtc_state) || + crtc_state->bigjoiner_pipes) goto slow; /* diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 92305f832ce7..71fa608c3cfd 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -4851,7 +4851,8 @@ static int intel_crtc_atomic_check(struct intel_atomic_state *state, if (c8_planes_changed(crtc_state)) crtc_state->uapi.color_mgmt_changed = true; - if (mode_changed || crtc_state->update_pipe || + if (mode_changed || + intel_crtc_needs_fastset(crtc_state) || crtc_state->uapi.color_mgmt_changed) { ret = intel_color_check(crtc_state); if (ret) @@ -4878,7 +4879,8 @@ static int intel_crtc_atomic_check(struct intel_atomic_state *state, } if (DISPLAY_VER(dev_priv) >= 9) { - if (mode_changed || crtc_state->update_pipe) { + if (mode_changed || + intel_crtc_needs_fastset(crtc_state)) { ret = skl_update_scaler_crtc(crtc_state); if (ret) return ret; @@ -6889,7 +6891,7 @@ static int intel_atomic_check(struct drm_device *dev, goto fail; if (!intel_crtc_needs_modeset(new_crtc_state) && - !new_crtc_state->update_pipe) + !intel_crtc_needs_fastset(new_crtc_state)) continue; intel_crtc_state_dump(new_crtc_state, state, @@ -6927,7 +6929,8 @@ static int intel_atomic_prepare_commit(struct intel_atomic_state *state) for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) { bool mode_changed = intel_crtc_needs_modeset(crtc_state); - if (mode_changed || crtc_state->update_pipe || + if (mode_changed || + intel_crtc_needs_fastset(crtc_state) || crtc_state->uapi.color_mgmt_changed) { intel_dsb_prepare(crtc_state); } @@ -7012,13 +7015,13 @@ static void commit_pipe_pre_planes(struct intel_atomic_state *state, */ if (!modeset) { if (new_crtc_state->uapi.color_mgmt_changed || - new_crtc_state->update_pipe) + intel_crtc_needs_fastset(new_crtc_state)) intel_color_commit_arm(new_crtc_state); if (DISPLAY_VER(dev_priv) >= 9 || IS_BROADWELL(dev_priv)) bdw_set_pipemisc(new_crtc_state); - if (new_crtc_state->update_pipe) + if (intel_crtc_needs_fastset(new_crtc_state)) intel_pipe_fastset(old_crtc_state, new_crtc_state); } @@ -7078,16 +7081,16 @@ static void intel_update_crtc(struct intel_atomic_state *state, if (!modeset) { if (new_crtc_state->preload_luts && (new_crtc_state->uapi.color_mgmt_changed || - new_crtc_state->update_pipe)) + intel_crtc_needs_fastset(new_crtc_state))) intel_color_load_luts(new_crtc_state); intel_pre_plane_update(state, crtc); - if (new_crtc_state->update_pipe) + if (intel_crtc_needs_fastset(new_crtc_state)) intel_encoders_update_pipe(state, crtc); if (DISPLAY_VER(i915) >= 11 && - new_crtc_state->update_pipe) + intel_crtc_needs_fastset(new_crtc_state)) icl_set_pipe_chicken(new_crtc_state); } @@ -7095,7 +7098,7 @@ static void intel_update_crtc(struct intel_atomic_state *state, if (!modeset && (new_crtc_state->uapi.color_mgmt_changed || - new_crtc_state->update_pipe)) + intel_crtc_needs_fastset(new_crtc_state))) intel_color_commit_noarm(new_crtc_state); intel_crtc_planes_update_noarm(state, crtc); @@ -7117,7 +7120,7 @@ static void intel_update_crtc(struct intel_atomic_state *state, * valid pipe configuration from the BIOS we need to take care * of enabling them on the CRTC's first fastset. */ - if (new_crtc_state->update_pipe && !modeset && + if (intel_crtc_needs_fastset(new_crtc_state) && !modeset && old_crtc_state->inherited) intel_crtc_arm_fifo_underrun(crtc, new_crtc_state); } @@ -7475,9 +7478,8 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { if (intel_crtc_needs_modeset(new_crtc_state) || - new_crtc_state->update_pipe) { + intel_crtc_needs_fastset(new_crtc_state)) intel_modeset_get_crtc_power_domains(new_crtc_state, &put_domains[crtc->pipe]); - } } intel_commit_modeset_disables(state); diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index c09cb8b89ad7..16c6077f49f1 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -2058,6 +2058,12 @@ intel_crtc_needs_modeset(const struct intel_crtc_state *crtc_state) return drm_atomic_crtc_needs_modeset(&crtc_state->uapi); } +static inline bool +intel_crtc_needs_fastset(const struct intel_crtc_state *crtc_state) +{ + return crtc_state->update_pipe; +} + static inline u32 intel_plane_ggtt_offset(const struct intel_plane_state *plane_state) { return i915_ggtt_offset(plane_state->ggtt_vma); diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c index 64b371f9a5fd..3f24f326b989 100644 --- a/drivers/gpu/drm/i915/display/intel_fbc.c +++ b/drivers/gpu/drm/i915/display/intel_fbc.c @@ -1520,7 +1520,8 @@ void intel_fbc_update(struct intel_atomic_state *state, mutex_lock(&fbc->lock); - if (crtc_state->update_pipe && plane_state->no_fbc_reason) { + if (intel_crtc_needs_fastset(crtc_state) && + plane_state->no_fbc_reason) { if (fbc->state.plane == plane) __intel_fbc_disable(fbc); } else { diff --git a/drivers/gpu/drm/i915/display/intel_modeset_verify.c b/drivers/gpu/drm/i915/display/intel_modeset_verify.c index 0fdcf2e6d57f..842d70f0dfd2 100644 --- a/drivers/gpu/drm/i915/display/intel_modeset_verify.c +++ b/drivers/gpu/drm/i915/display/intel_modeset_verify.c @@ -227,7 +227,8 @@ void intel_modeset_verify_crtc(struct intel_crtc *crtc, struct intel_crtc_state *old_crtc_state, struct intel_crtc_state *new_crtc_state) { - if (!intel_crtc_needs_modeset(new_crtc_state) && !new_crtc_state->update_pipe) + if (!intel_crtc_needs_modeset(new_crtc_state) && + !intel_crtc_needs_fastset(new_crtc_state)) return; intel_wm_state_verify(crtc, new_crtc_state); -- cgit From 925ac8bc33bfe05e0bf3df3a0ff5183b00654aa0 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 21 Oct 2022 19:24:40 +0300 Subject: drm/i915: Remove some local 'mode_changed' bools MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These 'mode_changed' booleans aren't very helpful. Just replace them with direct intel_crtc_needs_modeset() calls which is more descriptive. Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221021162442.27283-3-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 71fa608c3cfd..49d8d5781825 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -4831,14 +4831,14 @@ static int intel_crtc_atomic_check(struct intel_atomic_state *state, struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc); - bool mode_changed = intel_crtc_needs_modeset(crtc_state); int ret; if (DISPLAY_VER(dev_priv) < 5 && !IS_G4X(dev_priv) && - mode_changed && !crtc_state->hw.active) + intel_crtc_needs_modeset(crtc_state) && + !crtc_state->hw.active) crtc_state->update_wm_post = true; - if (mode_changed) { + if (intel_crtc_needs_modeset(crtc_state)) { ret = intel_dpll_crtc_get_shared_dpll(state, crtc); if (ret) return ret; @@ -4851,7 +4851,7 @@ static int intel_crtc_atomic_check(struct intel_atomic_state *state, if (c8_planes_changed(crtc_state)) crtc_state->uapi.color_mgmt_changed = true; - if (mode_changed || + if (intel_crtc_needs_modeset(crtc_state) || intel_crtc_needs_fastset(crtc_state) || crtc_state->uapi.color_mgmt_changed) { ret = intel_color_check(crtc_state); @@ -4879,7 +4879,7 @@ static int intel_crtc_atomic_check(struct intel_atomic_state *state, } if (DISPLAY_VER(dev_priv) >= 9) { - if (mode_changed || + if (intel_crtc_needs_modeset(crtc_state) || intel_crtc_needs_fastset(crtc_state)) { ret = skl_update_scaler_crtc(crtc_state); if (ret) @@ -6927,9 +6927,7 @@ static int intel_atomic_prepare_commit(struct intel_atomic_state *state) return ret; for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) { - bool mode_changed = intel_crtc_needs_modeset(crtc_state); - - if (mode_changed || + if (intel_crtc_needs_modeset(crtc_state) || intel_crtc_needs_fastset(crtc_state) || crtc_state->uapi.color_mgmt_changed) { intel_dsb_prepare(crtc_state); -- cgit From 7de5b6b54630c670af6822bebe70ff7b4281dc23 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 21 Oct 2022 19:24:41 +0300 Subject: drm/i915: Don't flag both full modeset and fastset at the same time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Be consistent in whether we flag a full modeset or a fastset for the pipe. intel_modeset_all_pipes() would seem to be the only codepath not getting this right. The other case is when we flag the fastset initially, currently we just clear the mode_changed flag and set the update_pipe flag. But we could still have connectors_changed==true or active_changed==true forcing a full modeset anyway. So check for that after clearing the mode_changed flag. And let's add a WARN to make sure we did get it right. v2: Deal with {connectors,active}_changed Reviewed-by: Jani Nikula #v1 Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221021162442.27283-4-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 49d8d5781825..74669ea35956 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -5939,6 +5939,7 @@ int intel_modeset_all_pipes(struct intel_atomic_state *state, crtc->base.base.id, crtc->base.name, reason); crtc_state->uapi.mode_changed = true; + crtc_state->update_pipe = false; ret = drm_atomic_add_affected_connectors(&state->base, &crtc->base); @@ -6114,7 +6115,8 @@ static void intel_crtc_check_fastset(const struct intel_crtc_state *old_crtc_sta return; new_crtc_state->uapi.mode_changed = false; - new_crtc_state->update_pipe = true; + if (!intel_crtc_needs_modeset(new_crtc_state)) + new_crtc_state->update_pipe = true; } static int intel_crtc_add_planes_to_state(struct intel_atomic_state *state, @@ -6890,6 +6892,11 @@ static int intel_atomic_check(struct drm_device *dev, if (ret) goto fail; + /* Either full modeset or fastset (or neither), never both */ + drm_WARN_ON(&dev_priv->drm, + intel_crtc_needs_modeset(new_crtc_state) && + intel_crtc_needs_fastset(new_crtc_state)); + if (!intel_crtc_needs_modeset(new_crtc_state) && !intel_crtc_needs_fastset(new_crtc_state)) continue; -- cgit From f5e674e92e9526430e01ef996bef5b50723f59bc Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 21 Oct 2022 19:24:42 +0300 Subject: drm/i915: Introduce intel_crtc_needs_color_update() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a common helper to answer the question "do we need to update color management stuff?". Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221021162442.27283-5-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/hsw_ips.c | 6 ++---- drivers/gpu/drm/i915/display/intel_crtc.c | 3 +-- drivers/gpu/drm/i915/display/intel_display.c | 18 +++++------------- drivers/gpu/drm/i915/display/intel_display_types.h | 8 ++++++++ 4 files changed, 16 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/display/hsw_ips.c b/drivers/gpu/drm/i915/display/hsw_ips.c index c23fabb76fda..83aa3800245f 100644 --- a/drivers/gpu/drm/i915/display/hsw_ips.c +++ b/drivers/gpu/drm/i915/display/hsw_ips.c @@ -104,8 +104,7 @@ static bool hsw_ips_need_disable(struct intel_atomic_state *state, * Disable IPS before we program the LUT. */ if (IS_HASWELL(i915) && - (new_crtc_state->uapi.color_mgmt_changed || - intel_crtc_needs_fastset(new_crtc_state)) && + intel_crtc_needs_color_update(new_crtc_state) && new_crtc_state->gamma_mode == GAMMA_MODE_MODE_SPLIT) return true; @@ -146,8 +145,7 @@ static bool hsw_ips_need_enable(struct intel_atomic_state *state, * Re-enable IPS after the LUT has been programmed. */ if (IS_HASWELL(i915) && - (new_crtc_state->uapi.color_mgmt_changed || - intel_crtc_needs_fastset(new_crtc_state)) && + intel_crtc_needs_color_update(new_crtc_state) && new_crtc_state->gamma_mode == GAMMA_MODE_MODE_SPLIT) return true; diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c index af7dbac7ed32..037fc140b585 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc.c +++ b/drivers/gpu/drm/i915/display/intel_crtc.c @@ -386,8 +386,7 @@ static bool intel_crtc_needs_vblank_work(const struct intel_crtc_state *crtc_sta return crtc_state->hw.active && !intel_crtc_needs_modeset(crtc_state) && !crtc_state->preload_luts && - (crtc_state->uapi.color_mgmt_changed || - intel_crtc_needs_fastset(crtc_state)); + intel_crtc_needs_color_update(crtc_state); } static void intel_crtc_vblank_work(struct kthread_work *base) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 74669ea35956..c4132a9af3a1 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -4851,9 +4851,7 @@ static int intel_crtc_atomic_check(struct intel_atomic_state *state, if (c8_planes_changed(crtc_state)) crtc_state->uapi.color_mgmt_changed = true; - if (intel_crtc_needs_modeset(crtc_state) || - intel_crtc_needs_fastset(crtc_state) || - crtc_state->uapi.color_mgmt_changed) { + if (intel_crtc_needs_color_update(crtc_state)) { ret = intel_color_check(crtc_state); if (ret) return ret; @@ -6934,11 +6932,8 @@ static int intel_atomic_prepare_commit(struct intel_atomic_state *state) return ret; for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) { - if (intel_crtc_needs_modeset(crtc_state) || - intel_crtc_needs_fastset(crtc_state) || - crtc_state->uapi.color_mgmt_changed) { + if (intel_crtc_needs_color_update(crtc_state)) intel_dsb_prepare(crtc_state); - } } return 0; @@ -7019,8 +7014,7 @@ static void commit_pipe_pre_planes(struct intel_atomic_state *state, * CRTC was enabled. */ if (!modeset) { - if (new_crtc_state->uapi.color_mgmt_changed || - intel_crtc_needs_fastset(new_crtc_state)) + if (intel_crtc_needs_color_update(new_crtc_state)) intel_color_commit_arm(new_crtc_state); if (DISPLAY_VER(dev_priv) >= 9 || IS_BROADWELL(dev_priv)) @@ -7085,8 +7079,7 @@ static void intel_update_crtc(struct intel_atomic_state *state, if (!modeset) { if (new_crtc_state->preload_luts && - (new_crtc_state->uapi.color_mgmt_changed || - intel_crtc_needs_fastset(new_crtc_state))) + intel_crtc_needs_color_update(new_crtc_state)) intel_color_load_luts(new_crtc_state); intel_pre_plane_update(state, crtc); @@ -7102,8 +7095,7 @@ static void intel_update_crtc(struct intel_atomic_state *state, intel_fbc_update(state, crtc); if (!modeset && - (new_crtc_state->uapi.color_mgmt_changed || - intel_crtc_needs_fastset(new_crtc_state))) + intel_crtc_needs_color_update(new_crtc_state)) intel_color_commit_noarm(new_crtc_state); intel_crtc_planes_update_noarm(state, crtc); diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 16c6077f49f1..8450bb50dc34 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -2064,6 +2064,14 @@ intel_crtc_needs_fastset(const struct intel_crtc_state *crtc_state) return crtc_state->update_pipe; } +static inline bool +intel_crtc_needs_color_update(const struct intel_crtc_state *crtc_state) +{ + return crtc_state->uapi.color_mgmt_changed || + intel_crtc_needs_fastset(crtc_state) || + intel_crtc_needs_modeset(crtc_state); +} + static inline u32 intel_plane_ggtt_offset(const struct intel_plane_state *plane_state) { return i915_ggtt_offset(plane_state->ggtt_vma); -- cgit From a7af4d67cf0ffd882007a16c68378ab742e9cba8 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 21 Oct 2022 09:40:35 +0100 Subject: drm/vc4: Fix spelling mistake "mmaping" -> "mmapping" There are a couple of spelling mistakes in DRM_DEBUG messages. Fix them. Signed-off-by: Colin Ian King Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20221021084035.65367-1-colin.i.king@gmail.com --- drivers/gpu/drm/vc4/vc4_bo.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c index 231add8b8e12..43d9b3a6a352 100644 --- a/drivers/gpu/drm/vc4/vc4_bo.c +++ b/drivers/gpu/drm/vc4/vc4_bo.c @@ -736,12 +736,12 @@ static int vc4_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struct struct vc4_bo *bo = to_vc4_bo(obj); if (bo->validated_shader && (vma->vm_flags & VM_WRITE)) { - DRM_DEBUG("mmaping of shader BOs for writing not allowed.\n"); + DRM_DEBUG("mmapping of shader BOs for writing not allowed.\n"); return -EINVAL; } if (bo->madv != VC4_MADV_WILLNEED) { - DRM_DEBUG("mmaping of %s BO not allowed\n", + DRM_DEBUG("mmapping of %s BO not allowed\n", bo->madv == VC4_MADV_DONTNEED ? "purgeable" : "purged"); return -EINVAL; -- cgit From 7e160d9c660f15aa3fbea160dd02c3946d356509 Mon Sep 17 00:00:00 2001 From: wangjianli Date: Sat, 22 Oct 2022 14:05:51 +0800 Subject: gpu/drm: fix repeated words in comments Delete the redundant word 'the'. Signed-off-by: wangjianli Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20221022060551.56918-1-wangjianli@cdjrlc.com --- drivers/gpu/drm/drm_mipi_dsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 3ec02748d56f..497ef4b6a90a 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -606,7 +606,7 @@ int mipi_dsi_turn_on_peripheral(struct mipi_dsi_device *dsi) EXPORT_SYMBOL(mipi_dsi_turn_on_peripheral); /* - * mipi_dsi_set_maximum_return_packet_size() - specify the maximum size of the + * mipi_dsi_set_maximum_return_packet_size() - specify the maximum size of * the payload in a long packet transmitted from the peripheral back to the * host processor * @dsi: DSI peripheral device -- cgit From 2556e1a83574f6248b70534c5d50e3ef9eaa4eb5 Mon Sep 17 00:00:00 2001 From: wangjianli Date: Sat, 22 Oct 2022 14:07:01 +0800 Subject: gpu/drm: fix repeated words in comments Delete the redundant word 'the'. Signed-off-by: wangjianli Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20221022060701.58280-1-wangjianli@cdjrlc.com --- drivers/gpu/drm/drm_rect.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_rect.c b/drivers/gpu/drm/drm_rect.c index 0460e874896e..85c79a38c13a 100644 --- a/drivers/gpu/drm/drm_rect.c +++ b/drivers/gpu/drm/drm_rect.c @@ -80,7 +80,7 @@ static u32 clip_scaled(int src, int dst, int *clip) * @dst: destination window rectangle * @clip: clip rectangle * - * Clip rectangle @dst by rectangle @clip. Clip rectangle @src by the + * Clip rectangle @dst by rectangle @clip. Clip rectangle @src by * the corresponding amounts, retaining the vertical and horizontal scaling * factors from @src to @dst. * -- cgit From e577d4b13064c337b83fe7edecb3f34e87144821 Mon Sep 17 00:00:00 2001 From: Pin-yen Lin Date: Thu, 13 Oct 2022 19:04:08 +0800 Subject: drm/bridge: it6505: Initialize AUX channel in it6505_i2c_probe During device boot, the HPD interrupt could be triggered before the DRM subsystem registers it6505 as a DRM bridge. In such cases, the driver tries to access AUX channel and causes NULL pointer dereference. Initializing the AUX channel earlier to prevent such error. Fixes: b5c84a9edcd4 ("drm/bridge: add it6505 driver") Signed-off-by: Pin-yen Lin Reviewed-by: Robert Foss Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20221013110411.1674359-2-treapking@chromium.org --- drivers/gpu/drm/bridge/ite-it6505.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c index 1fd09911fe8c..24460beb5905 100644 --- a/drivers/gpu/drm/bridge/ite-it6505.c +++ b/drivers/gpu/drm/bridge/ite-it6505.c @@ -2871,10 +2871,7 @@ static int it6505_bridge_attach(struct drm_bridge *bridge, } /* Register aux channel */ - it6505->aux.name = "DP-AUX"; - it6505->aux.dev = dev; it6505->aux.drm_dev = bridge->dev; - it6505->aux.transfer = it6505_aux_transfer; ret = drm_dp_aux_register(&it6505->aux); @@ -3354,6 +3351,11 @@ static int it6505_i2c_probe(struct i2c_client *client, debugfs_init(it6505); pm_runtime_enable(dev); + it6505->aux.name = "DP-AUX"; + it6505->aux.dev = dev; + it6505->aux.transfer = it6505_aux_transfer; + drm_dp_aux_init(&it6505->aux); + it6505->bridge.funcs = &it6505_bridge_funcs; it6505->bridge.type = DRM_MODE_CONNECTOR_DisplayPort; it6505->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID | -- cgit From 5827b1e1c20514fe36b2bb92fab28df088cc2499 Mon Sep 17 00:00:00 2001 From: Pin-yen Lin Date: Thu, 13 Oct 2022 19:04:09 +0800 Subject: drm/bridge: it6505: Setup links in it6505_irq_hpd Move the DPCD read and link setup steps to HPD IRQ handler to remove an unnecessary dependency between .detect callback and the HPD IRQ handler before registering it6505 as a DRM bridge. This is safe because there is always a .detect call after each HPD IRQ handler triggered by the drm_helper_hpd_irq_event call. Signed-off-by: Pin-yen Lin Reviewed-by: Robert Foss Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20221013110411.1674359-3-treapking@chromium.org --- drivers/gpu/drm/bridge/ite-it6505.c | 80 ++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 45 deletions(-) diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c index 24460beb5905..6feeb3e49b0a 100644 --- a/drivers/gpu/drm/bridge/ite-it6505.c +++ b/drivers/gpu/drm/bridge/ite-it6505.c @@ -725,28 +725,6 @@ static void it6505_calc_video_info(struct it6505 *it6505) DRM_MODE_ARG(&it6505->video_info)); } -static int it6505_drm_dp_link_probe(struct drm_dp_aux *aux, - struct it6505_drm_dp_link *link) -{ - u8 values[3]; - int err; - - memset(link, 0, sizeof(*link)); - - err = drm_dp_dpcd_read(aux, DP_DPCD_REV, values, sizeof(values)); - if (err < 0) - return err; - - link->revision = values[0]; - link->rate = drm_dp_bw_code_to_link_rate(values[1]); - link->num_lanes = values[2] & DP_MAX_LANE_COUNT_MASK; - - if (values[2] & DP_ENHANCED_FRAME_CAP) - link->capabilities = DP_ENHANCED_FRAME_CAP; - - return 0; -} - static int it6505_drm_dp_link_set_power(struct drm_dp_aux *aux, struct it6505_drm_dp_link *link, u8 mode) @@ -1456,11 +1434,19 @@ static void it6505_parse_link_capabilities(struct it6505 *it6505) int bcaps; if (it6505->dpcd[0] == 0) { - it6505_aux_on(it6505); - it6505_get_dpcd(it6505, DP_DPCD_REV, it6505->dpcd, - ARRAY_SIZE(it6505->dpcd)); + dev_err(dev, "DPCD is not initialized"); + return; } + memset(link, 0, sizeof(*link)); + + link->revision = it6505->dpcd[0]; + link->rate = drm_dp_bw_code_to_link_rate(it6505->dpcd[1]); + link->num_lanes = it6505->dpcd[2] & DP_MAX_LANE_COUNT_MASK; + + if (it6505->dpcd[2] & DP_ENHANCED_FRAME_CAP) + link->capabilities = DP_ENHANCED_FRAME_CAP; + DRM_DEV_DEBUG_DRIVER(dev, "DPCD Rev.: %d.%d", link->revision >> 4, link->revision & 0x0F); @@ -2323,19 +2309,32 @@ static int it6505_process_hpd_irq(struct it6505 *it6505) static void it6505_irq_hpd(struct it6505 *it6505) { struct device *dev = &it6505->client->dev; + int dp_sink_count; it6505->hpd_state = it6505_get_sink_hpd_status(it6505); DRM_DEV_DEBUG_DRIVER(dev, "hpd change interrupt, change to %s", it6505->hpd_state ? "high" : "low"); - if (it6505->bridge.dev) - drm_helper_hpd_irq_event(it6505->bridge.dev); - DRM_DEV_DEBUG_DRIVER(dev, "it6505->sink_count: %d", - it6505->sink_count); - if (it6505->hpd_state) { wait_for_completion_timeout(&it6505->wait_edid_complete, msecs_to_jiffies(6000)); + it6505_aux_on(it6505); + if (it6505->dpcd[0] == 0) { + it6505_get_dpcd(it6505, DP_DPCD_REV, it6505->dpcd, + ARRAY_SIZE(it6505->dpcd)); + it6505_variable_config(it6505); + it6505_parse_link_capabilities(it6505); + } + it6505->auto_train_retry = AUTO_TRAIN_RETRY; + + it6505_drm_dp_link_set_power(&it6505->aux, &it6505->link, + DP_SET_POWER_D0); + dp_sink_count = it6505_dpcd_read(it6505, DP_SINK_COUNT); + it6505->sink_count = DP_GET_SINK_COUNT(dp_sink_count); + + DRM_DEV_DEBUG_DRIVER(dev, "it6505->sink_count: %d", + it6505->sink_count); + it6505_lane_termination_on(it6505); it6505_lane_power_on(it6505); @@ -2363,6 +2362,9 @@ static void it6505_irq_hpd(struct it6505 *it6505) it6505_lane_off(it6505); it6505_link_reset_step_train(it6505); } + + if (it6505->bridge.dev) + drm_helper_hpd_irq_event(it6505->bridge.dev); } static void it6505_irq_hpd_irq(struct it6505 *it6505) @@ -2625,26 +2627,14 @@ static enum drm_connector_status it6505_detect(struct it6505 *it6505) goto unlock; if (it6505->enable_drv_hold) { - status = it6505_get_sink_hpd_status(it6505) ? - connector_status_connected : - connector_status_disconnected; + status = it6505->hpd_state ? connector_status_connected : + connector_status_disconnected; goto unlock; } - if (it6505_get_sink_hpd_status(it6505)) { - it6505_aux_on(it6505); - it6505_drm_dp_link_probe(&it6505->aux, &it6505->link); + if (it6505->hpd_state) { it6505_drm_dp_link_set_power(&it6505->aux, &it6505->link, DP_SET_POWER_D0); - it6505->auto_train_retry = AUTO_TRAIN_RETRY; - - if (it6505->dpcd[0] == 0) { - it6505_get_dpcd(it6505, DP_DPCD_REV, it6505->dpcd, - ARRAY_SIZE(it6505->dpcd)); - it6505_variable_config(it6505); - it6505_parse_link_capabilities(it6505); - } - dp_sink_count = it6505_dpcd_read(it6505, DP_SINK_COUNT); it6505->sink_count = DP_GET_SINK_COUNT(dp_sink_count); DRM_DEV_DEBUG_DRIVER(dev, "it6505->sink_count:%d branch:%d", -- cgit From ab28896f1a831581b0b59ef1f7e6fa64066c2546 Mon Sep 17 00:00:00 2001 From: Pin-yen Lin Date: Thu, 13 Oct 2022 19:04:10 +0800 Subject: drm/bridge: it6505: Improve synchronization between extcon subsystem Originally, the it6505 relies on a short sleep in the IRQ handler and a long sleep to make sure it6505->lane_swap and it6505->lane_count is configured in it6505_extcon_work and it6505_detect, respectively. Use completion and additional DPCD read to remove the unnecessary waits, and use a different lock for it6505_extcon_work and the threaded IRQ handler because they no longer need to run exclusively. The wait time of the completion is usually less than 10ms in local experiments, but leave it larger here just in case. Signed-off-by: Pin-yen Lin Reviewed-by: Robert Foss Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20221013110411.1674359-4-treapking@chromium.org --- drivers/gpu/drm/bridge/ite-it6505.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c index 6feeb3e49b0a..b929fc766e24 100644 --- a/drivers/gpu/drm/bridge/ite-it6505.c +++ b/drivers/gpu/drm/bridge/ite-it6505.c @@ -412,6 +412,7 @@ struct it6505 { * Mutex protects extcon and interrupt functions from interfering * each other. */ + struct mutex irq_lock; struct mutex extcon_lock; struct mutex mode_lock; /* used to bridge_detect */ struct mutex aux_lock; /* used to aux data transfers */ @@ -440,7 +441,7 @@ struct it6505 { enum hdcp_state hdcp_status; struct delayed_work hdcp_work; struct work_struct hdcp_wait_ksv_list; - struct completion wait_edid_complete; + struct completion extcon_completion; u8 auto_train_retry; bool hdcp_desired; bool is_repeater; @@ -2316,8 +2317,8 @@ static void it6505_irq_hpd(struct it6505 *it6505) it6505->hpd_state ? "high" : "low"); if (it6505->hpd_state) { - wait_for_completion_timeout(&it6505->wait_edid_complete, - msecs_to_jiffies(6000)); + wait_for_completion_timeout(&it6505->extcon_completion, + msecs_to_jiffies(1000)); it6505_aux_on(it6505); if (it6505->dpcd[0] == 0) { it6505_get_dpcd(it6505, DP_DPCD_REV, it6505->dpcd, @@ -2493,8 +2494,7 @@ static irqreturn_t it6505_int_threaded_handler(int unused, void *data) }; int int_status[3], i; - msleep(100); - mutex_lock(&it6505->extcon_lock); + mutex_lock(&it6505->irq_lock); if (it6505->enable_drv_hold || !it6505->powered) goto unlock; @@ -2524,7 +2524,7 @@ static irqreturn_t it6505_int_threaded_handler(int unused, void *data) } unlock: - mutex_unlock(&it6505->extcon_lock); + mutex_unlock(&it6505->irq_lock); return IRQ_HANDLED; } @@ -2701,9 +2701,12 @@ static void it6505_extcon_work(struct work_struct *work) */ if (ret) it6505_poweron(it6505); + + complete_all(&it6505->extcon_completion); } else { DRM_DEV_DEBUG_DRIVER(dev, "start to power off"); pm_runtime_put_sync(dev); + reinit_completion(&it6505->extcon_completion); drm_helper_hpd_irq_event(it6505->bridge.dev); memset(it6505->dpcd, 0, sizeof(it6505->dpcd)); @@ -3274,6 +3277,7 @@ static int it6505_i2c_probe(struct i2c_client *client, if (!it6505) return -ENOMEM; + mutex_init(&it6505->irq_lock); mutex_init(&it6505->extcon_lock); mutex_init(&it6505->mode_lock); mutex_init(&it6505->aux_lock); @@ -3329,7 +3333,7 @@ static int it6505_i2c_probe(struct i2c_client *client, INIT_WORK(&it6505->link_works, it6505_link_training_work); INIT_WORK(&it6505->hdcp_wait_ksv_list, it6505_hdcp_wait_ksv_list); INIT_DELAYED_WORK(&it6505->hdcp_work, it6505_hdcp_work); - init_completion(&it6505->wait_edid_complete); + init_completion(&it6505->extcon_completion); memset(it6505->dpcd, 0, sizeof(it6505->dpcd)); it6505->powered = false; it6505->enable_drv_hold = DEFAULT_DRV_HOLD; -- cgit From 5490c50438c6a8af849f3894a1b7d655349a7b7b Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Wed, 19 Oct 2022 16:38:17 +0200 Subject: drm/i915: use intel_uncore_rmw when appropriate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch replaces all occurences of the form intel_uncore_write(reg, intel_uncore_read(reg) OP val) with intel_uncore_rmw. Signed-off-by: Andrzej Hajda Reviewed-by: Ville Syrjälä Reviewed-by: Andi Shyti Signed-off-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20221019143818.244339-1-andrzej.hajda@intel.com --- drivers/gpu/drm/i915/intel_pm.c | 187 ++++++++++++++-------------------------- 1 file changed, 66 insertions(+), 121 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 95f1e40b8972..f3f15c2d5bb7 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -60,25 +60,20 @@ static void gen9_init_clock_gating(struct drm_i915_private *dev_priv) * Must match Sampler, Pixel Back End, and Media. See * WaCompressedResourceSamplerPbeMediaNewHashMode. */ - intel_uncore_write(&dev_priv->uncore, CHICKEN_PAR1_1, - intel_uncore_read(&dev_priv->uncore, CHICKEN_PAR1_1) | - SKL_DE_COMPRESSED_HASH_MODE); + intel_uncore_rmw(&dev_priv->uncore, CHICKEN_PAR1_1, 0, SKL_DE_COMPRESSED_HASH_MODE); } /* See Bspec note for PSR2_CTL bit 31, Wa#828:skl,bxt,kbl,cfl */ - intel_uncore_write(&dev_priv->uncore, CHICKEN_PAR1_1, - intel_uncore_read(&dev_priv->uncore, CHICKEN_PAR1_1) | SKL_EDP_PSR_FIX_RDWRAP); + intel_uncore_rmw(&dev_priv->uncore, CHICKEN_PAR1_1, 0, SKL_EDP_PSR_FIX_RDWRAP); /* WaEnableChickenDCPR:skl,bxt,kbl,glk,cfl */ - intel_uncore_write(&dev_priv->uncore, GEN8_CHICKEN_DCPR_1, - intel_uncore_read(&dev_priv->uncore, GEN8_CHICKEN_DCPR_1) | MASK_WAKEMEM); + intel_uncore_rmw(&dev_priv->uncore, GEN8_CHICKEN_DCPR_1, 0, MASK_WAKEMEM); /* * WaFbcWakeMemOn:skl,bxt,kbl,glk,cfl * Display WA #0859: skl,bxt,kbl,glk,cfl */ - intel_uncore_write(&dev_priv->uncore, DISP_ARB_CTL, intel_uncore_read(&dev_priv->uncore, DISP_ARB_CTL) | - DISP_FBC_MEMORY_WAKE); + intel_uncore_rmw(&dev_priv->uncore, DISP_ARB_CTL, 0, DISP_FBC_MEMORY_WAKE); } static void bxt_init_clock_gating(struct drm_i915_private *dev_priv) @@ -86,15 +81,13 @@ static void bxt_init_clock_gating(struct drm_i915_private *dev_priv) gen9_init_clock_gating(dev_priv); /* WaDisableSDEUnitClockGating:bxt */ - intel_uncore_write(&dev_priv->uncore, GEN8_UCGCTL6, intel_uncore_read(&dev_priv->uncore, GEN8_UCGCTL6) | - GEN8_SDEUNIT_CLOCK_GATE_DISABLE); + intel_uncore_rmw(&dev_priv->uncore, GEN8_UCGCTL6, 0, GEN8_SDEUNIT_CLOCK_GATE_DISABLE); /* * FIXME: * GEN8_HDCUNIT_CLOCK_GATE_DISABLE_HDCREQ applies on 3x6 GT SKUs only. */ - intel_uncore_write(&dev_priv->uncore, GEN8_UCGCTL6, intel_uncore_read(&dev_priv->uncore, GEN8_UCGCTL6) | - GEN8_HDCUNIT_CLOCK_GATE_DISABLE_HDCREQ); + intel_uncore_rmw(&dev_priv->uncore, GEN8_UCGCTL6, 0, GEN8_HDCUNIT_CLOCK_GATE_DISABLE_HDCREQ); /* * Wa: Backlight PWM may stop in the asserted state, causing backlight @@ -115,16 +108,13 @@ static void bxt_init_clock_gating(struct drm_i915_private *dev_priv) * WaFbcTurnOffFbcWatermark:bxt * Display WA #0562: bxt */ - intel_uncore_write(&dev_priv->uncore, DISP_ARB_CTL, intel_uncore_read(&dev_priv->uncore, DISP_ARB_CTL) | - DISP_FBC_WM_DIS); + intel_uncore_rmw(&dev_priv->uncore, DISP_ARB_CTL, 0, DISP_FBC_WM_DIS); /* * WaFbcHighMemBwCorruptionAvoidance:bxt * Display WA #0883: bxt */ - intel_uncore_write(&dev_priv->uncore, ILK_DPFC_CHICKEN(INTEL_FBC_A), - intel_uncore_read(&dev_priv->uncore, ILK_DPFC_CHICKEN(INTEL_FBC_A)) | - DPFC_DISABLE_DUMMY0); + intel_uncore_rmw(&dev_priv->uncore, ILK_DPFC_CHICKEN(INTEL_FBC_A), 0, DPFC_DISABLE_DUMMY0); } static void glk_init_clock_gating(struct drm_i915_private *dev_priv) @@ -4059,9 +4049,9 @@ void vlv_wm_sanitize(struct drm_i915_private *dev_priv) */ static void ilk_init_lp_watermarks(struct drm_i915_private *dev_priv) { - intel_uncore_write(&dev_priv->uncore, WM3_LP_ILK, intel_uncore_read(&dev_priv->uncore, WM3_LP_ILK) & ~WM_LP_ENABLE); - intel_uncore_write(&dev_priv->uncore, WM2_LP_ILK, intel_uncore_read(&dev_priv->uncore, WM2_LP_ILK) & ~WM_LP_ENABLE); - intel_uncore_write(&dev_priv->uncore, WM1_LP_ILK, intel_uncore_read(&dev_priv->uncore, WM1_LP_ILK) & ~WM_LP_ENABLE); + intel_uncore_rmw(&dev_priv->uncore, WM3_LP_ILK, WM_LP_ENABLE, 0); + intel_uncore_rmw(&dev_priv->uncore, WM2_LP_ILK, WM_LP_ENABLE, 0); + intel_uncore_rmw(&dev_priv->uncore, WM1_LP_ILK, WM_LP_ENABLE, 0); /* * Don't touch WM_LP_SPRITE_ENABLE here. @@ -4115,9 +4105,7 @@ static void g4x_disable_trickle_feed(struct drm_i915_private *dev_priv) enum pipe pipe; for_each_pipe(dev_priv, pipe) { - intel_uncore_write(&dev_priv->uncore, DSPCNTR(pipe), - intel_uncore_read(&dev_priv->uncore, DSPCNTR(pipe)) | - DISP_TRICKLE_FEED_DISABLE); + intel_uncore_rmw(&dev_priv->uncore, DSPCNTR(pipe), 0, DISP_TRICKLE_FEED_DISABLE); intel_uncore_write(&dev_priv->uncore, DSPSURF(pipe), intel_uncore_read(&dev_priv->uncore, DSPSURF(pipe))); intel_uncore_posting_read(&dev_priv->uncore, DSPSURF(pipe)); @@ -4166,19 +4154,13 @@ static void ilk_init_clock_gating(struct drm_i915_private *dev_priv) */ if (IS_IRONLAKE_M(dev_priv)) { /* WaFbcAsynchFlipDisableFbcQueue:ilk */ - intel_uncore_write(&dev_priv->uncore, ILK_DISPLAY_CHICKEN1, - intel_uncore_read(&dev_priv->uncore, ILK_DISPLAY_CHICKEN1) | - ILK_FBCQ_DIS); - intel_uncore_write(&dev_priv->uncore, ILK_DISPLAY_CHICKEN2, - intel_uncore_read(&dev_priv->uncore, ILK_DISPLAY_CHICKEN2) | - ILK_DPARB_GATE); + intel_uncore_rmw(&dev_priv->uncore, ILK_DISPLAY_CHICKEN1, 0, ILK_FBCQ_DIS); + intel_uncore_rmw(&dev_priv->uncore, ILK_DISPLAY_CHICKEN2, 0, ILK_DPARB_GATE); } intel_uncore_write(&dev_priv->uncore, ILK_DSPCLK_GATE_D, dspclk_gate); - intel_uncore_write(&dev_priv->uncore, ILK_DISPLAY_CHICKEN2, - intel_uncore_read(&dev_priv->uncore, ILK_DISPLAY_CHICKEN2) | - ILK_ELPIN_409_SELECT); + intel_uncore_rmw(&dev_priv->uncore, ILK_DISPLAY_CHICKEN2, 0, ILK_ELPIN_409_SELECT); g4x_disable_trickle_feed(dev_priv); @@ -4198,8 +4180,7 @@ static void cpt_init_clock_gating(struct drm_i915_private *dev_priv) intel_uncore_write(&dev_priv->uncore, SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE | PCH_DPLUNIT_CLOCK_GATE_DISABLE | PCH_CPUNIT_CLOCK_GATE_DISABLE); - intel_uncore_write(&dev_priv->uncore, SOUTH_CHICKEN2, intel_uncore_read(&dev_priv->uncore, SOUTH_CHICKEN2) | - DPLS_EDP_PPS_FIX_DIS); + intel_uncore_rmw(&dev_priv->uncore, SOUTH_CHICKEN2, 0, DPLS_EDP_PPS_FIX_DIS); /* The below fixes the weird display corruption, a few pixels shifted * downward, on (only) LVDS of some HP laptops with IVY. */ @@ -4237,9 +4218,7 @@ static void gen6_init_clock_gating(struct drm_i915_private *dev_priv) intel_uncore_write(&dev_priv->uncore, ILK_DSPCLK_GATE_D, dspclk_gate); - intel_uncore_write(&dev_priv->uncore, ILK_DISPLAY_CHICKEN2, - intel_uncore_read(&dev_priv->uncore, ILK_DISPLAY_CHICKEN2) | - ILK_ELPIN_409_SELECT); + intel_uncore_rmw(&dev_priv->uncore, ILK_DISPLAY_CHICKEN2, 0, ILK_ELPIN_409_SELECT); intel_uncore_write(&dev_priv->uncore, GEN6_UCGCTL1, intel_uncore_read(&dev_priv->uncore, GEN6_UCGCTL1) | @@ -4299,14 +4278,12 @@ static void lpt_init_clock_gating(struct drm_i915_private *dev_priv) * disabled when not needed anymore in order to save power. */ if (HAS_PCH_LPT_LP(dev_priv)) - intel_uncore_write(&dev_priv->uncore, SOUTH_DSPCLK_GATE_D, - intel_uncore_read(&dev_priv->uncore, SOUTH_DSPCLK_GATE_D) | - PCH_LP_PARTITION_LEVEL_DISABLE); + intel_uncore_rmw(&dev_priv->uncore, SOUTH_DSPCLK_GATE_D, + 0, PCH_LP_PARTITION_LEVEL_DISABLE); /* WADPOClockGatingDisable:hsw */ - intel_uncore_write(&dev_priv->uncore, TRANS_CHICKEN1(PIPE_A), - intel_uncore_read(&dev_priv->uncore, TRANS_CHICKEN1(PIPE_A)) | - TRANS_CHICKEN1_DP0UNIT_GC_DISABLE); + intel_uncore_rmw(&dev_priv->uncore, TRANS_CHICKEN1(PIPE_A), + 0, TRANS_CHICKEN1_DP0UNIT_GC_DISABLE); } static void lpt_suspend_hw(struct drm_i915_private *dev_priv) @@ -4365,8 +4342,7 @@ static void gen12lp_init_clock_gating(struct drm_i915_private *dev_priv) /* Wa_1409825376:tgl (pre-prod)*/ if (IS_TGL_DISPLAY_STEP(dev_priv, STEP_A0, STEP_C0)) - intel_uncore_write(&dev_priv->uncore, GEN9_CLKGATE_DIS_3, intel_uncore_read(&dev_priv->uncore, GEN9_CLKGATE_DIS_3) | - TGL_VRH_GATING_DIS); + intel_uncore_rmw(&dev_priv->uncore, GEN9_CLKGATE_DIS_3, 0, TGL_VRH_GATING_DIS); /* Wa_14013723622:tgl,rkl,dg1,adl-s */ if (DISPLAY_VER(dev_priv) == 12) @@ -4391,8 +4367,7 @@ static void dg1_init_clock_gating(struct drm_i915_private *dev_priv) /* Wa_1409836686:dg1[a0] */ if (IS_DG1_GRAPHICS_STEP(dev_priv, STEP_A0, STEP_B0)) - intel_uncore_write(&dev_priv->uncore, GEN9_CLKGATE_DIS_3, intel_uncore_read(&dev_priv->uncore, GEN9_CLKGATE_DIS_3) | - DPT_GATING_DIS); + intel_uncore_rmw(&dev_priv->uncore, GEN9_CLKGATE_DIS_3, 0, DPT_GATING_DIS); } static void xehpsdv_init_clock_gating(struct drm_i915_private *dev_priv) @@ -4434,8 +4409,7 @@ static void cnp_init_clock_gating(struct drm_i915_private *dev_priv) return; /* Display WA #1181 WaSouthDisplayDisablePWMCGEGating: cnp */ - intel_uncore_write(&dev_priv->uncore, SOUTH_DSPCLK_GATE_D, intel_uncore_read(&dev_priv->uncore, SOUTH_DSPCLK_GATE_D) | - CNP_PWM_CGE_GATING_DISABLE); + intel_uncore_rmw(&dev_priv->uncore, SOUTH_DSPCLK_GATE_D, 0, CNP_PWM_CGE_GATING_DISABLE); } static void cfl_init_clock_gating(struct drm_i915_private *dev_priv) @@ -4444,23 +4418,20 @@ static void cfl_init_clock_gating(struct drm_i915_private *dev_priv) gen9_init_clock_gating(dev_priv); /* WAC6entrylatency:cfl */ - intel_uncore_write(&dev_priv->uncore, FBC_LLC_READ_CTRL, intel_uncore_read(&dev_priv->uncore, FBC_LLC_READ_CTRL) | - FBC_LLC_FULLY_OPEN); + intel_uncore_rmw(&dev_priv->uncore, FBC_LLC_READ_CTRL, 0, FBC_LLC_FULLY_OPEN); /* * WaFbcTurnOffFbcWatermark:cfl * Display WA #0562: cfl */ - intel_uncore_write(&dev_priv->uncore, DISP_ARB_CTL, intel_uncore_read(&dev_priv->uncore, DISP_ARB_CTL) | - DISP_FBC_WM_DIS); + intel_uncore_rmw(&dev_priv->uncore, DISP_ARB_CTL, 0, DISP_FBC_WM_DIS); /* * WaFbcNukeOnHostModify:cfl * Display WA #0873: cfl */ - intel_uncore_write(&dev_priv->uncore, ILK_DPFC_CHICKEN(INTEL_FBC_A), - intel_uncore_read(&dev_priv->uncore, ILK_DPFC_CHICKEN(INTEL_FBC_A)) | - DPFC_NUKE_ON_ANY_MODIFICATION); + intel_uncore_rmw(&dev_priv->uncore, ILK_DPFC_CHICKEN(INTEL_FBC_A), + 0, DPFC_NUKE_ON_ANY_MODIFICATION); } static void kbl_init_clock_gating(struct drm_i915_private *dev_priv) @@ -4468,33 +4439,30 @@ static void kbl_init_clock_gating(struct drm_i915_private *dev_priv) gen9_init_clock_gating(dev_priv); /* WAC6entrylatency:kbl */ - intel_uncore_write(&dev_priv->uncore, FBC_LLC_READ_CTRL, intel_uncore_read(&dev_priv->uncore, FBC_LLC_READ_CTRL) | - FBC_LLC_FULLY_OPEN); + intel_uncore_rmw(&dev_priv->uncore, FBC_LLC_READ_CTRL, 0, FBC_LLC_FULLY_OPEN); /* WaDisableSDEUnitClockGating:kbl */ if (IS_KBL_GRAPHICS_STEP(dev_priv, 0, STEP_C0)) - intel_uncore_write(&dev_priv->uncore, GEN8_UCGCTL6, intel_uncore_read(&dev_priv->uncore, GEN8_UCGCTL6) | - GEN8_SDEUNIT_CLOCK_GATE_DISABLE); + intel_uncore_rmw(&dev_priv->uncore, GEN8_UCGCTL6, + 0, GEN8_SDEUNIT_CLOCK_GATE_DISABLE); /* WaDisableGamClockGating:kbl */ if (IS_KBL_GRAPHICS_STEP(dev_priv, 0, STEP_C0)) - intel_uncore_write(&dev_priv->uncore, GEN6_UCGCTL1, intel_uncore_read(&dev_priv->uncore, GEN6_UCGCTL1) | - GEN6_GAMUNIT_CLOCK_GATE_DISABLE); + intel_uncore_rmw(&dev_priv->uncore, GEN6_UCGCTL1, + 0, GEN6_GAMUNIT_CLOCK_GATE_DISABLE); /* * WaFbcTurnOffFbcWatermark:kbl * Display WA #0562: kbl */ - intel_uncore_write(&dev_priv->uncore, DISP_ARB_CTL, intel_uncore_read(&dev_priv->uncore, DISP_ARB_CTL) | - DISP_FBC_WM_DIS); + intel_uncore_rmw(&dev_priv->uncore, DISP_ARB_CTL, 0, DISP_FBC_WM_DIS); /* * WaFbcNukeOnHostModify:kbl * Display WA #0873: kbl */ - intel_uncore_write(&dev_priv->uncore, ILK_DPFC_CHICKEN(INTEL_FBC_A), - intel_uncore_read(&dev_priv->uncore, ILK_DPFC_CHICKEN(INTEL_FBC_A)) | - DPFC_NUKE_ON_ANY_MODIFICATION); + intel_uncore_rmw(&dev_priv->uncore, ILK_DPFC_CHICKEN(INTEL_FBC_A), + 0, DPFC_NUKE_ON_ANY_MODIFICATION); } static void skl_init_clock_gating(struct drm_i915_private *dev_priv) @@ -4506,31 +4474,26 @@ static void skl_init_clock_gating(struct drm_i915_private *dev_priv) GEN8_DOP_CLOCK_GATE_ENABLE, 0); /* WAC6entrylatency:skl */ - intel_uncore_write(&dev_priv->uncore, FBC_LLC_READ_CTRL, intel_uncore_read(&dev_priv->uncore, FBC_LLC_READ_CTRL) | - FBC_LLC_FULLY_OPEN); + intel_uncore_rmw(&dev_priv->uncore, FBC_LLC_READ_CTRL, 0, FBC_LLC_FULLY_OPEN); /* * WaFbcTurnOffFbcWatermark:skl * Display WA #0562: skl */ - intel_uncore_write(&dev_priv->uncore, DISP_ARB_CTL, intel_uncore_read(&dev_priv->uncore, DISP_ARB_CTL) | - DISP_FBC_WM_DIS); + intel_uncore_rmw(&dev_priv->uncore, DISP_ARB_CTL, 0, DISP_FBC_WM_DIS); /* * WaFbcNukeOnHostModify:skl * Display WA #0873: skl */ - intel_uncore_write(&dev_priv->uncore, ILK_DPFC_CHICKEN(INTEL_FBC_A), - intel_uncore_read(&dev_priv->uncore, ILK_DPFC_CHICKEN(INTEL_FBC_A)) | - DPFC_NUKE_ON_ANY_MODIFICATION); + intel_uncore_rmw(&dev_priv->uncore, ILK_DPFC_CHICKEN(INTEL_FBC_A), + 0, DPFC_NUKE_ON_ANY_MODIFICATION); /* * WaFbcHighMemBwCorruptionAvoidance:skl * Display WA #0883: skl */ - intel_uncore_write(&dev_priv->uncore, ILK_DPFC_CHICKEN(INTEL_FBC_A), - intel_uncore_read(&dev_priv->uncore, ILK_DPFC_CHICKEN(INTEL_FBC_A)) | - DPFC_DISABLE_DUMMY0); + intel_uncore_rmw(&dev_priv->uncore, ILK_DPFC_CHICKEN(INTEL_FBC_A), 0, DPFC_DISABLE_DUMMY0); } static void bdw_init_clock_gating(struct drm_i915_private *dev_priv) @@ -4538,43 +4501,37 @@ static void bdw_init_clock_gating(struct drm_i915_private *dev_priv) enum pipe pipe; /* WaFbcAsynchFlipDisableFbcQueue:hsw,bdw */ - intel_uncore_write(&dev_priv->uncore, CHICKEN_PIPESL_1(PIPE_A), - intel_uncore_read(&dev_priv->uncore, CHICKEN_PIPESL_1(PIPE_A)) | - HSW_FBCQ_DIS); + intel_uncore_rmw(&dev_priv->uncore, CHICKEN_PIPESL_1(PIPE_A), 0, HSW_FBCQ_DIS); /* WaSwitchSolVfFArbitrationPriority:bdw */ - intel_uncore_write(&dev_priv->uncore, GAM_ECOCHK, intel_uncore_read(&dev_priv->uncore, GAM_ECOCHK) | HSW_ECOCHK_ARB_PRIO_SOL); + intel_uncore_rmw(&dev_priv->uncore, GAM_ECOCHK, 0, HSW_ECOCHK_ARB_PRIO_SOL); /* WaPsrDPAMaskVBlankInSRD:bdw */ - intel_uncore_write(&dev_priv->uncore, CHICKEN_PAR1_1, - intel_uncore_read(&dev_priv->uncore, CHICKEN_PAR1_1) | DPA_MASK_VBLANK_SRD); + intel_uncore_rmw(&dev_priv->uncore, CHICKEN_PAR1_1, 0, DPA_MASK_VBLANK_SRD); for_each_pipe(dev_priv, pipe) { /* WaPsrDPRSUnmaskVBlankInSRD:bdw */ - intel_uncore_write(&dev_priv->uncore, CHICKEN_PIPESL_1(pipe), - intel_uncore_read(&dev_priv->uncore, CHICKEN_PIPESL_1(pipe)) | - BDW_DPRS_MASK_VBLANK_SRD); + intel_uncore_rmw(&dev_priv->uncore, CHICKEN_PIPESL_1(pipe), + 0, BDW_DPRS_MASK_VBLANK_SRD); } /* WaVSRefCountFullforceMissDisable:bdw */ /* WaDSRefCountFullforceMissDisable:bdw */ - intel_uncore_write(&dev_priv->uncore, GEN7_FF_THREAD_MODE, - intel_uncore_read(&dev_priv->uncore, GEN7_FF_THREAD_MODE) & - ~(GEN8_FF_DS_REF_CNT_FFME | GEN7_FF_VS_REF_CNT_FFME)); + intel_uncore_rmw(&dev_priv->uncore, GEN7_FF_THREAD_MODE, + GEN8_FF_DS_REF_CNT_FFME | GEN7_FF_VS_REF_CNT_FFME, 0); intel_uncore_write(&dev_priv->uncore, RING_PSMI_CTL(RENDER_RING_BASE), _MASKED_BIT_ENABLE(GEN8_RC_SEMA_IDLE_MSG_DISABLE)); /* WaDisableSDEUnitClockGating:bdw */ - intel_uncore_write(&dev_priv->uncore, GEN8_UCGCTL6, intel_uncore_read(&dev_priv->uncore, GEN8_UCGCTL6) | - GEN8_SDEUNIT_CLOCK_GATE_DISABLE); + intel_uncore_rmw(&dev_priv->uncore, GEN8_UCGCTL6, 0, GEN8_SDEUNIT_CLOCK_GATE_DISABLE); /* WaProgramL3SqcReg1Default:bdw */ gen8_set_l3sqc_credits(dev_priv, 30, 2); /* WaKVMNotificationOnConfigChange:bdw */ - intel_uncore_write(&dev_priv->uncore, CHICKEN_PAR2_1, intel_uncore_read(&dev_priv->uncore, CHICKEN_PAR2_1) - | KVM_CONFIG_CHANGE_NOTIFICATION_SELECT); + intel_uncore_rmw(&dev_priv->uncore, CHICKEN_PAR2_1, + 0, KVM_CONFIG_CHANGE_NOTIFICATION_SELECT); lpt_init_clock_gating(dev_priv); @@ -4583,24 +4540,20 @@ static void bdw_init_clock_gating(struct drm_i915_private *dev_priv) * Also see the CHICKEN2 write in bdw_init_workarounds() to disable DOP * clock gating. */ - intel_uncore_write(&dev_priv->uncore, GEN6_UCGCTL1, - intel_uncore_read(&dev_priv->uncore, GEN6_UCGCTL1) | GEN6_EU_TCUNIT_CLOCK_GATE_DISABLE); + intel_uncore_rmw(&dev_priv->uncore, GEN6_UCGCTL1, 0, GEN6_EU_TCUNIT_CLOCK_GATE_DISABLE); } static void hsw_init_clock_gating(struct drm_i915_private *dev_priv) { /* WaFbcAsynchFlipDisableFbcQueue:hsw,bdw */ - intel_uncore_write(&dev_priv->uncore, CHICKEN_PIPESL_1(PIPE_A), - intel_uncore_read(&dev_priv->uncore, CHICKEN_PIPESL_1(PIPE_A)) | - HSW_FBCQ_DIS); + intel_uncore_rmw(&dev_priv->uncore, CHICKEN_PIPESL_1(PIPE_A), 0, HSW_FBCQ_DIS); /* This is required by WaCatErrorRejectionIssue:hsw */ - intel_uncore_write(&dev_priv->uncore, GEN7_SQ_CHICKEN_MBCUNIT_CONFIG, - intel_uncore_read(&dev_priv->uncore, GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) | - GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB); + intel_uncore_rmw(&dev_priv->uncore, GEN7_SQ_CHICKEN_MBCUNIT_CONFIG, + 0, GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB); /* WaSwitchSolVfFArbitrationPriority:hsw */ - intel_uncore_write(&dev_priv->uncore, GAM_ECOCHK, intel_uncore_read(&dev_priv->uncore, GAM_ECOCHK) | HSW_ECOCHK_ARB_PRIO_SOL); + intel_uncore_rmw(&dev_priv->uncore, GAM_ECOCHK, 0, HSW_ECOCHK_ARB_PRIO_SOL); lpt_init_clock_gating(dev_priv); } @@ -4612,9 +4565,7 @@ static void ivb_init_clock_gating(struct drm_i915_private *dev_priv) intel_uncore_write(&dev_priv->uncore, ILK_DSPCLK_GATE_D, ILK_VRHUNIT_CLOCK_GATE_DISABLE); /* WaFbcAsynchFlipDisableFbcQueue:ivb */ - intel_uncore_write(&dev_priv->uncore, ILK_DISPLAY_CHICKEN1, - intel_uncore_read(&dev_priv->uncore, ILK_DISPLAY_CHICKEN1) | - ILK_FBCQ_DIS); + intel_uncore_rmw(&dev_priv->uncore, ILK_DISPLAY_CHICKEN1, 0, ILK_FBCQ_DIS); /* WaDisableBackToBackFlipFix:ivb */ intel_uncore_write(&dev_priv->uncore, IVB_CHICKEN3, @@ -4640,9 +4591,8 @@ static void ivb_init_clock_gating(struct drm_i915_private *dev_priv) GEN6_RCZUNIT_CLOCK_GATE_DISABLE); /* This is required by WaCatErrorRejectionIssue:ivb */ - intel_uncore_write(&dev_priv->uncore, GEN7_SQ_CHICKEN_MBCUNIT_CONFIG, - intel_uncore_read(&dev_priv->uncore, GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) | - GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB); + intel_uncore_rmw(&dev_priv->uncore, GEN7_SQ_CHICKEN_MBCUNIT_CONFIG, + 0, GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB); g4x_disable_trickle_feed(dev_priv); @@ -4669,9 +4619,8 @@ static void vlv_init_clock_gating(struct drm_i915_private *dev_priv) _MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE)); /* This is required by WaCatErrorRejectionIssue:vlv */ - intel_uncore_write(&dev_priv->uncore, GEN7_SQ_CHICKEN_MBCUNIT_CONFIG, - intel_uncore_read(&dev_priv->uncore, GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) | - GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB); + intel_uncore_rmw(&dev_priv->uncore, GEN7_SQ_CHICKEN_MBCUNIT_CONFIG, + 0, GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB); /* * According to the spec, bit 13 (RCZUNIT) must be set on IVB. @@ -4683,8 +4632,7 @@ static void vlv_init_clock_gating(struct drm_i915_private *dev_priv) /* WaDisableL3Bank2xClockGate:vlv * Disabling L3 clock gating- MMIO 940c[25] = 1 * Set bit 25, to disable L3_BANK_2x_CLK_GATING */ - intel_uncore_write(&dev_priv->uncore, GEN7_UCGCTL4, - intel_uncore_read(&dev_priv->uncore, GEN7_UCGCTL4) | GEN7_L3BANK2X_CLOCK_GATE_DISABLE); + intel_uncore_rmw(&dev_priv->uncore, GEN7_UCGCTL4, 0, GEN7_L3BANK2X_CLOCK_GATE_DISABLE); /* * WaDisableVLVClockGating_VBIIssue:vlv @@ -4698,21 +4646,18 @@ static void chv_init_clock_gating(struct drm_i915_private *dev_priv) { /* WaVSRefCountFullforceMissDisable:chv */ /* WaDSRefCountFullforceMissDisable:chv */ - intel_uncore_write(&dev_priv->uncore, GEN7_FF_THREAD_MODE, - intel_uncore_read(&dev_priv->uncore, GEN7_FF_THREAD_MODE) & - ~(GEN8_FF_DS_REF_CNT_FFME | GEN7_FF_VS_REF_CNT_FFME)); + intel_uncore_rmw(&dev_priv->uncore, GEN7_FF_THREAD_MODE, + GEN8_FF_DS_REF_CNT_FFME | GEN7_FF_VS_REF_CNT_FFME, 0); /* WaDisableSemaphoreAndSyncFlipWait:chv */ intel_uncore_write(&dev_priv->uncore, RING_PSMI_CTL(RENDER_RING_BASE), _MASKED_BIT_ENABLE(GEN8_RC_SEMA_IDLE_MSG_DISABLE)); /* WaDisableCSUnitClockGating:chv */ - intel_uncore_write(&dev_priv->uncore, GEN6_UCGCTL1, intel_uncore_read(&dev_priv->uncore, GEN6_UCGCTL1) | - GEN6_CSUNIT_CLOCK_GATE_DISABLE); + intel_uncore_rmw(&dev_priv->uncore, GEN6_UCGCTL1, 0, GEN6_CSUNIT_CLOCK_GATE_DISABLE); /* WaDisableSDEUnitClockGating:chv */ - intel_uncore_write(&dev_priv->uncore, GEN8_UCGCTL6, intel_uncore_read(&dev_priv->uncore, GEN8_UCGCTL6) | - GEN8_SDEUNIT_CLOCK_GATE_DISABLE); + intel_uncore_rmw(&dev_priv->uncore, GEN8_UCGCTL6, 0, GEN8_SDEUNIT_CLOCK_GATE_DISABLE); /* * WaProgramL3SqcReg1Default:chv -- cgit From c61aa7407d0d1ebf66d59fd54971964e22a6f2da Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Wed, 19 Oct 2022 16:38:18 +0200 Subject: drm/i915/gt: use intel_uncore_rmw when appropriate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch replaces all occurences of the form intel_uncore_write(reg, intel_uncore_read(reg) OP val) with intel_uncore_rmw. Signed-off-by: Andrzej Hajda Reviewed-by: Ville Syrjälä Reviewed-by: Andi Shyti Signed-off-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20221019143818.244339-2-andrzej.hajda@intel.com --- drivers/gpu/drm/i915/gt/intel_rps.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_rps.c b/drivers/gpu/drm/i915/gt/intel_rps.c index fc23c562d9b2..070005dd0da4 100644 --- a/drivers/gpu/drm/i915/gt/intel_rps.c +++ b/drivers/gpu/drm/i915/gt/intel_rps.c @@ -625,9 +625,7 @@ static void gen5_rps_disable(struct intel_rps *rps) rgvswctl = intel_uncore_read16(uncore, MEMSWCTL); /* Ack interrupts, disable EFC interrupt */ - intel_uncore_write(uncore, MEMINTREN, - intel_uncore_read(uncore, MEMINTREN) & - ~MEMINT_EVAL_CHG_EN); + intel_uncore_rmw(uncore, MEMINTREN, MEMINT_EVAL_CHG_EN, 0); intel_uncore_write(uncore, MEMINTRSTS, MEMINT_EVAL_CHG); /* Go back to the starting frequency */ -- cgit From 20293269d81779a0d0c0865f5877b240c3335c97 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Fri, 30 Sep 2022 10:43:08 +0530 Subject: drm/amdgpu: Remove ATC L2 access for MMHUB 2.1.x MMHUB 2.1.x versions don't have ATCL2. Remove accesses to ATCL2 registers. Since they are non-existing registers, read access will cause a 'Completer Abort' and gets reported when AER is enabled with the below patch. Tagging with the patch so that this is backported along with it. v2: squash in uninitialized warning fix (Nathan Chancellor) Fixes: 8795e182b02d ("PCI/portdrv: Don't disable AER reporting in get_port_device_capability()") Signed-off-by: Lijo Lazar Reviewed-by: Guchun Chen Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c index 4d304f22889e..998b5d17b271 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c @@ -32,8 +32,6 @@ #include "gc/gc_10_1_0_offset.h" #include "soc15_common.h" -#define mmMM_ATC_L2_MISC_CG_Sienna_Cichlid 0x064d -#define mmMM_ATC_L2_MISC_CG_Sienna_Cichlid_BASE_IDX 0 #define mmDAGB0_CNTL_MISC2_Sienna_Cichlid 0x0070 #define mmDAGB0_CNTL_MISC2_Sienna_Cichlid_BASE_IDX 0 @@ -574,7 +572,6 @@ static void mmhub_v2_0_update_medium_grain_clock_gating(struct amdgpu_device *ad case IP_VERSION(2, 1, 0): case IP_VERSION(2, 1, 1): case IP_VERSION(2, 1, 2): - def = data = RREG32_SOC15(MMHUB, 0, mmMM_ATC_L2_MISC_CG_Sienna_Cichlid); def1 = data1 = RREG32_SOC15(MMHUB, 0, mmDAGB0_CNTL_MISC2_Sienna_Cichlid); break; default: @@ -608,8 +605,6 @@ static void mmhub_v2_0_update_medium_grain_clock_gating(struct amdgpu_device *ad case IP_VERSION(2, 1, 0): case IP_VERSION(2, 1, 1): case IP_VERSION(2, 1, 2): - if (def != data) - WREG32_SOC15(MMHUB, 0, mmMM_ATC_L2_MISC_CG_Sienna_Cichlid, data); if (def1 != data1) WREG32_SOC15(MMHUB, 0, mmDAGB0_CNTL_MISC2_Sienna_Cichlid, data1); break; @@ -634,8 +629,8 @@ static void mmhub_v2_0_update_medium_grain_light_sleep(struct amdgpu_device *ade case IP_VERSION(2, 1, 0): case IP_VERSION(2, 1, 1): case IP_VERSION(2, 1, 2): - def = data = RREG32_SOC15(MMHUB, 0, mmMM_ATC_L2_MISC_CG_Sienna_Cichlid); - break; + /* There is no ATCL2 in MMHUB for 2.1.x */ + return; default: def = data = RREG32_SOC15(MMHUB, 0, mmMM_ATC_L2_MISC_CG); break; @@ -646,18 +641,8 @@ static void mmhub_v2_0_update_medium_grain_light_sleep(struct amdgpu_device *ade else data &= ~MM_ATC_L2_MISC_CG__MEM_LS_ENABLE_MASK; - if (def != data) { - switch (adev->ip_versions[MMHUB_HWIP][0]) { - case IP_VERSION(2, 1, 0): - case IP_VERSION(2, 1, 1): - case IP_VERSION(2, 1, 2): - WREG32_SOC15(MMHUB, 0, mmMM_ATC_L2_MISC_CG_Sienna_Cichlid, data); - break; - default: - WREG32_SOC15(MMHUB, 0, mmMM_ATC_L2_MISC_CG, data); - break; - } - } + if (def != data) + WREG32_SOC15(MMHUB, 0, mmMM_ATC_L2_MISC_CG, data); } static int mmhub_v2_0_set_clockgating(struct amdgpu_device *adev, @@ -695,7 +680,10 @@ static void mmhub_v2_0_get_clockgating(struct amdgpu_device *adev, u64 *flags) case IP_VERSION(2, 1, 0): case IP_VERSION(2, 1, 1): case IP_VERSION(2, 1, 2): - data = RREG32_SOC15(MMHUB, 0, mmMM_ATC_L2_MISC_CG_Sienna_Cichlid); + /* There is no ATCL2 in MMHUB for 2.1.x. Keep the status + * based on DAGB + */ + data = MM_ATC_L2_MISC_CG__ENABLE_MASK; data1 = RREG32_SOC15(MMHUB, 0, mmDAGB0_CNTL_MISC2_Sienna_Cichlid); break; default: -- cgit From 7b5a4d7b9e2952a15c8d2b2391dfacd7ce841a1a Mon Sep 17 00:00:00 2001 From: Rafael Mendonca Date: Mon, 17 Oct 2022 22:27:50 -0300 Subject: drm/amdkfd: Fix memory leak in kfd_mem_dmamap_userptr() If the number of pages from the userptr BO differs from the SG BO then the allocated memory for the SG table doesn't get freed before returning -EINVAL, which may lead to a memory leak in some error paths. Fix this by checking the number of pages before allocating memory for the SG table. Fixes: 264fb4d332f5 ("drm/amdgpu: Add multi-GPU DMA mapping helpers") Signed-off-by: Rafael Mendonca Reviewed-by: Felix Kuehling Signed-off-by: Felix Kuehling Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index 8ad01e1ee4c6..da9d475d7ef2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -510,13 +510,13 @@ kfd_mem_dmamap_userptr(struct kgd_mem *mem, struct ttm_tt *ttm = bo->tbo.ttm; int ret; + if (WARN_ON(ttm->num_pages != src_ttm->num_pages)) + return -EINVAL; + ttm->sg = kmalloc(sizeof(*ttm->sg), GFP_KERNEL); if (unlikely(!ttm->sg)) return -ENOMEM; - if (WARN_ON(ttm->num_pages != src_ttm->num_pages)) - return -EINVAL; - /* Same sequence as in amdgpu_ttm_tt_pin_userptr */ ret = sg_alloc_table_from_pages(ttm->sg, src_ttm->pages, ttm->num_pages, 0, -- cgit From 03ce7b387e8b0f4a1dc97a878545bdf7c7f23251 Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira Date: Tue, 18 Oct 2022 08:28:15 -0400 Subject: drm/amd/display: Check if link state is valid The link state is set to false if there is no link and local sink. Even though the stream state may not change, it is desirable to commit the new stream when HPD goes low to high. Reviewed-by: Harry Wentland Signed-off-by: Rodrigo Siqueira Co-developed-by: Aurabindo Pillai Signed-off-by: Aurabindo Pillai Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 997ab031f816..7b576bd24cb5 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -1500,6 +1500,8 @@ static bool context_changed( for (i = 0; i < dc->current_state->stream_count; i++) { if (dc->current_state->streams[i] != context->streams[i]) return true; + if (!context->streams[i]->link->link_state_valid) + return true; } return false; -- cgit From 10fdb0a11c555e0d6f7698d2874581d06e99ee71 Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira Date: Tue, 18 Oct 2022 08:28:16 -0400 Subject: drm/amd/display: Rework context change check Context change is all about streams; for this reason, this commit renames context_changed to streams_changed. Additionally, to make this function more flexible, this commit changes the function signature to receive the stream array and the stream count as a parameter. Reviewed-by: Harry Wentland Signed-off-by: Rodrigo Siqueira Co-developed-by: Aurabindo Pillai Signed-off-by: Aurabindo Pillai Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 7b576bd24cb5..9219d1efde2a 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -1488,19 +1488,19 @@ static void program_timing_sync( } } -static bool context_changed( - struct dc *dc, - struct dc_state *context) +static bool streams_changed(struct dc *dc, + struct dc_stream_state *streams[], + uint8_t stream_count) { uint8_t i; - if (context->stream_count != dc->current_state->stream_count) + if (stream_count != dc->current_state->stream_count) return true; for (i = 0; i < dc->current_state->stream_count; i++) { - if (dc->current_state->streams[i] != context->streams[i]) + if (dc->current_state->streams[i] != streams[i]) return true; - if (!context->streams[i]->link->link_state_valid) + if (!streams[i]->link->link_state_valid) return true; } @@ -1895,7 +1895,7 @@ bool dc_commit_state(struct dc *dc, struct dc_state *context) enum dc_status result = DC_ERROR_UNEXPECTED; int i; - if (!context_changed(dc, context)) + if (!streams_changed(dc, context->streams, context->stream_count)) return DC_OK; DC_LOG_DC("%s: %d streams\n", -- cgit From 7b36f4d18e3e4941d12fe027ad6ad6123c257027 Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira Date: Tue, 18 Oct 2022 08:28:17 -0400 Subject: drm/amd/display: Enable new commit sequence only for DCN32x Change commit sequence will impact all ASICs. It is prudent to run this update in small steps to keep issues under control and avoid any potential regression. With this idea in mind, this commit is preparation work for the complete transition to the new commit sequence. To maintain this change manageable across multiple ASICs, this commit adds a new function named dc_commit_streams which is a copy of the dc_commit_state with some minor changes. Finally, inside the dc_commit_state, we check if we are using DCN32x or above and enable the new sequence only for those devices. Reviewed-by: Harry Wentland Signed-off-by: Rodrigo Siqueira Co-developed-by: Aurabindo Pillai Signed-off-by: Aurabindo Pillai Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 46 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/amd/display/dc/dc.h | 13 +++------ 2 files changed, 50 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 9219d1efde2a..5d9e9e8f87d3 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -1890,11 +1890,57 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c return result; } +enum dc_status dc_commit_streams(struct dc *dc, struct dc_state *context) +{ + enum dc_status res = DC_OK; + int i; + + if (!streams_changed(dc, context->streams, context->stream_count)) + return res; + + DC_LOG_DC("%s: %d streams\n", + __func__, context->stream_count); + + for (i = 0; i < context->stream_count; i++) { + struct dc_stream_state *stream = context->streams[i]; + + dc_stream_log(dc, stream); + } + + /* + * Previous validation was perfomred with fast_validation = true and + * the full DML state required for hardware programming was skipped. + * + * Re-validate here to calculate these parameters / watermarks. + */ + res = dc_validate_global_state(dc, context, false); + if (res != DC_OK) { + DC_LOG_ERROR("DC commit global validation failure: %s (%d)", + dc_status_to_str(res), res); + return res; + } + + res = dc_commit_state_no_check(dc, context); + + return (res == DC_OK); +} + +/* TODO: When the transition to the new commit sequence is done, remove this + * function in favor of dc_commit_streams. */ bool dc_commit_state(struct dc *dc, struct dc_state *context) { enum dc_status result = DC_ERROR_UNEXPECTED; int i; + /* TODO: Since change commit sequence can have a huge impact, + * we decided to only enable it for DCN3x. However, as soon as + * we get more confident about this change we'll need to enable + * the new sequence for all ASICs. */ + if (dc->ctx->dce_version >= DCN_VERSION_3_2) { + result = dc_commit_streams(dc, context); + return result == DC_OK; + } + if (!streams_changed(dc, context->streams, context->stream_count)) return DC_OK; diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index bfc5474c0f4c..2e71781f155b 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -1321,15 +1321,10 @@ void dc_resource_state_destruct(struct dc_state *context); bool dc_resource_is_dsc_encoding_supported(const struct dc *dc); -/* - * TODO update to make it about validation sets - * Set up streams and links associated to drive sinks - * The streams parameter is an absolute set of all active streams. - * - * After this call: - * Phy, Encoder, Timing Generator are programmed and enabled. - * New streams are enabled with blank stream; no memory read. - */ +enum dc_status dc_commit_streams(struct dc *dc, struct dc_state *context); + +/* TODO: When the transition to the new commit sequence is done, remove this + * function in favor of dc_commit_streams. */ bool dc_commit_state(struct dc *dc, struct dc_state *context); struct dc_state *dc_create_state(struct dc *dc); -- cgit From 0e986cea0347902b2c72b09c8fe9c0f30d7decb4 Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira Date: Tue, 18 Oct 2022 08:28:18 -0400 Subject: drm/amd/display: Copy DC context in the commit streams DC adds an instance of DML (which contains VBA) to each context, and multiple threads might write back to the global VBA resulting in data overwriting. To keep the consistency with other parts of the DC code, this commit changes dc_commit_streams to copy the current DC state, and as a result, it also changes the function signature to expect streams instead of a context. Reviewed-by: Harry Wentland Signed-off-by: Rodrigo Siqueira Co-developed-by: Aurabindo Pillai Signed-off-by: Aurabindo Pillai Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 41 +++++++++++++++++++++++++------- drivers/gpu/drm/amd/display/dc/dc.h | 4 +++- 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 5d9e9e8f87d3..af81c2835738 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -1890,23 +1890,44 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c return result; } -enum dc_status dc_commit_streams(struct dc *dc, struct dc_state *context) +/** + * dc_commit_streams - Commit current stream state + * + * @dc: DC object with the commit state to be configured in the hardware + * @streams: Array with a list of stream state + * @stream_count: Total of streams + * + * Function responsible for commit streams change to the hardware. + * + * Return: + * Return DC_OK if everything work as expected, otherwise, return a dc_status + * code. + */ +enum dc_status dc_commit_streams(struct dc *dc, + struct dc_stream_state *streams[], + uint8_t stream_count) { - enum dc_status res = DC_OK; int i; + struct dc_state *context; + enum dc_status res = DC_OK; - if (!streams_changed(dc, context->streams, context->stream_count)) + if (!streams_changed(dc, streams, stream_count)) return res; - DC_LOG_DC("%s: %d streams\n", - __func__, context->stream_count); + DC_LOG_DC("%s: %d streams\n", __func__, stream_count); - for (i = 0; i < context->stream_count; i++) { - struct dc_stream_state *stream = context->streams[i]; + for (i = 0; i < stream_count; i++) { + struct dc_stream_state *stream = streams[i]; dc_stream_log(dc, stream); } + context = dc_create_state(dc); + if (!context) + goto context_alloc_fail; + + dc_resource_state_copy_construct_current(dc, context); + /* * Previous validation was perfomred with fast_validation = true and * the full DML state required for hardware programming was skipped. @@ -1922,6 +1943,10 @@ enum dc_status dc_commit_streams(struct dc *dc, struct dc_state *context) res = dc_commit_state_no_check(dc, context); +context_alloc_fail: + + DC_LOG_DC("%s Finished.\n", __func__); + return (res == DC_OK); } @@ -1937,7 +1962,7 @@ bool dc_commit_state(struct dc *dc, struct dc_state *context) * we get more confident about this change we'll need to enable * the new sequence for all ASICs. */ if (dc->ctx->dce_version >= DCN_VERSION_3_2) { - result = dc_commit_streams(dc, context); + result = dc_commit_streams(dc, context->streams, context->stream_count); return result == DC_OK; } diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 2e71781f155b..6adecb62e534 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -1321,7 +1321,9 @@ void dc_resource_state_destruct(struct dc_state *context); bool dc_resource_is_dsc_encoding_supported(const struct dc *dc); -enum dc_status dc_commit_streams(struct dc *dc, struct dc_state *context); +enum dc_status dc_commit_streams(struct dc *dc, + struct dc_stream_state *streams[], + uint8_t stream_count); /* TODO: When the transition to the new commit sequence is done, remove this * function in favor of dc_commit_streams. */ -- cgit From f6ae69f49fcf697b6ffa93d58eb3746897f61cf8 Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira Date: Tue, 18 Oct 2022 08:28:19 -0400 Subject: drm/amd/display: Include surface of unaffected streams The commit stream function does not include surfaces of unaffected streams, which may lead to some blank screens during mode change in some edge cases. This commit adds surfaces of unaffected streams followed by kernel-doc for documenting some of the fields that participate in this change. v2: squash in kerneldoc warning fix (Alex) Reviewed-by: Harry Wentland Signed-off-by: Rodrigo Siqueira Co-developed-by: Aurabindo Pillai Signed-off-by: Aurabindo Pillai Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 12 +++++++++++- drivers/gpu/drm/amd/display/dc/dc.h | 15 +++++++++++++-- drivers/gpu/drm/amd/display/dc/dc_stream.h | 4 ++++ 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index af81c2835738..b904b03cf94e 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -1907,9 +1907,10 @@ enum dc_status dc_commit_streams(struct dc *dc, struct dc_stream_state *streams[], uint8_t stream_count) { - int i; + int i, j; struct dc_state *context; enum dc_status res = DC_OK; + struct dc_validation_set set[MAX_STREAMS] = {0}; if (!streams_changed(dc, streams, stream_count)) return res; @@ -1918,8 +1919,17 @@ enum dc_status dc_commit_streams(struct dc *dc, for (i = 0; i < stream_count; i++) { struct dc_stream_state *stream = streams[i]; + struct dc_stream_status *status = dc_stream_get_status(stream); dc_stream_log(dc, stream); + + set[i].stream = stream; + + if (status) { + set[i].plane_count = status->plane_count; + for (j = 0; j < status->plane_count; j++) + set[i].plane_states[j] = status->plane_states[j]; + } } context = dc_create_state(dc); diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 6adecb62e534..836cdf5d4114 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -1269,12 +1269,23 @@ void dc_post_update_surfaces_to_stream( #include "dc_stream.h" -/* - * Structure to store surface/stream associations for validation +/** + * struct dc_validation_set - Struct to store surface/stream associations for validation */ struct dc_validation_set { + /** + * @stream: Stream state properties + */ struct dc_stream_state *stream; + + /** + * @plane_state: Surface state + */ struct dc_plane_state *plane_states[MAX_SURFACES]; + + /** + * @plane_count: Total of active planes + */ uint8_t plane_count; }; diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index 9e6025c98db9..73dccd485895 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -41,6 +41,10 @@ struct timing_sync_info { struct dc_stream_status { int primary_otg_inst; int stream_enc_inst; + + /** + * @plane_count: Total of planes attached to a single stream + */ int plane_count; int audio_inst; struct timing_sync_info timing_sync_info; -- cgit From 987b96eb860036ab79051fb271f7fbdc01c9daf5 Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira Date: Tue, 18 Oct 2022 08:28:20 -0400 Subject: drm/amd/display: Handle virtual hardware detect If virtual hardware is detected, there is no reason to run the full dc_commit_streams process, and DC can return true immediately. Reviewed-by: Harry Wentland Signed-off-by: Rodrigo Siqueira Co-developed-by: Aurabindo Pillai Signed-off-by: Aurabindo Pillai Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index b904b03cf94e..61b574b9e736 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -1912,6 +1912,9 @@ enum dc_status dc_commit_streams(struct dc *dc, enum dc_status res = DC_OK; struct dc_validation_set set[MAX_STREAMS] = {0}; + if (dc->ctx->dce_environment == DCE_ENV_VIRTUAL_HW) + return res; + if (!streams_changed(dc, streams, stream_count)) return res; -- cgit From a5e39ae27c3a305c6aafc0e423b0cb2c677facde Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira Date: Tue, 18 Oct 2022 08:28:21 -0400 Subject: drm/amd/display: Add function for validate and update new stream DC stream can be seen as a representation of the DCN backend or the data struct that represents the center of the display pipeline. The front end (i.e., planes) is connected to the DC stream, and in its turn, streams are connected to the DC link. Due to this dynamic, DC must handle the following scenarios: 1. A stream is removed; 2. A new stream is created; 3. An unchanged stream had some updates on its planes. These combinations require that the new stream data struct become updated and has a valid global state. For handling multiple corner cases associated with stream operations, this commit introduces a function dedicated to manipulating stream changes and invokes the state validation function after that. Reviewed-by: Harry Wentland Signed-off-by: Rodrigo Siqueira Co-developed-by: Aurabindo Pillai Signed-off-by: Aurabindo Pillai Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 16 +- drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 219 +++++++++++++++++++++- drivers/gpu/drm/amd/display/dc/dc.h | 6 + 3 files changed, 227 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 61b574b9e736..d568387c4bda 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -1941,21 +1941,17 @@ enum dc_status dc_commit_streams(struct dc *dc, dc_resource_state_copy_construct_current(dc, context); - /* - * Previous validation was perfomred with fast_validation = true and - * the full DML state required for hardware programming was skipped. - * - * Re-validate here to calculate these parameters / watermarks. - */ - res = dc_validate_global_state(dc, context, false); + res = dc_validate_with_context(dc, set, stream_count, context, false); if (res != DC_OK) { - DC_LOG_ERROR("DC commit global validation failure: %s (%d)", - dc_status_to_str(res), res); - return res; + BREAK_TO_DEBUGGER(); + goto fail; } res = dc_commit_state_no_check(dc, context); +fail: + dc_release_state(context); + context_alloc_fail: DC_LOG_DC("%s Finished.\n", __func__); diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index fd8db482e56f..e001b138b2ac 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -2593,15 +2593,226 @@ bool dc_resource_is_dsc_encoding_supported(const struct dc *dc) return dc->res_pool->res_cap->num_dsc > 0; } +static bool planes_changed_for_existing_stream(struct dc_state *context, + struct dc_stream_state *stream, + const struct dc_validation_set set[], + int set_count) +{ + int i, j; + struct dc_stream_status *stream_status = NULL; + + for (i = 0; i < context->stream_count; i++) { + if (context->streams[i] == stream) { + stream_status = &context->stream_status[i]; + break; + } + } + + if (!stream_status) + ASSERT(0); + + for (i = 0; i < set_count; i++) + if (set[i].stream == stream) + break; + + if (i == set_count) + ASSERT(0); + + if (set[i].plane_count != stream_status->plane_count) + return true; + + for (j = 0; j < set[i].plane_count; j++) + if (set[i].plane_states[j] != stream_status->plane_states[j]) + return true; + + return false; +} + +/** + * dc_validate_with_context - Validate and update the potential new stream in the context object + * + * @dc: Used to get the current state status + * @set: An array of dc_validation_set with all the current streams reference + * @set_count: Total of streams + * @context: New context + * @fast_validate: Enable or disable fast validation + * + * This function updates the potential new stream in the context object. It + * creates multiple lists for the add, remove, and unchanged streams. In + * particular, if the unchanged streams have a plane that changed, it is + * necessary to remove all planes from the unchanged streams. In summary, this + * function is responsible for validating the new context. + * + * Return: + * In case of success, return DC_OK (1), otherwise, return a DC error. + */ +enum dc_status dc_validate_with_context(struct dc *dc, + const struct dc_validation_set set[], + int set_count, + struct dc_state *context, + bool fast_validate) +{ + struct dc_stream_state *unchanged_streams[MAX_PIPES] = { 0 }; + struct dc_stream_state *del_streams[MAX_PIPES] = { 0 }; + struct dc_stream_state *add_streams[MAX_PIPES] = { 0 }; + int old_stream_count = context->stream_count; + enum dc_status res = DC_ERROR_UNEXPECTED; + int unchanged_streams_count = 0; + int del_streams_count = 0; + int add_streams_count = 0; + bool found = false; + int i, j, k; + + DC_LOGGER_INIT(dc->ctx->logger); + + /* First build a list of streams to be remove from current context */ + for (i = 0; i < old_stream_count; i++) { + struct dc_stream_state *stream = context->streams[i]; + + for (j = 0; j < set_count; j++) { + if (stream == set[j].stream) { + found = true; + break; + } + } + + if (!found) + del_streams[del_streams_count++] = stream; + + found = false; + } + + /* Second, build a list of new streams */ + for (i = 0; i < set_count; i++) { + struct dc_stream_state *stream = set[i].stream; + + for (j = 0; j < old_stream_count; j++) { + if (stream == context->streams[j]) { + found = true; + break; + } + } + + if (!found) + add_streams[add_streams_count++] = stream; + + found = false; + } + + /* Build a list of unchanged streams which is necessary for handling + * planes change such as added, removed, and updated. + */ + for (i = 0; i < set_count; i++) { + /* Check if stream is part of the delete list */ + for (j = 0; j < del_streams_count; j++) { + if (set[i].stream == del_streams[j]) { + found = true; + break; + } + } + + if (!found) { + /* Check if stream is part of the add list */ + for (j = 0; j < add_streams_count; j++) { + if (set[i].stream == add_streams[j]) { + found = true; + break; + } + } + } + + if (!found) + unchanged_streams[unchanged_streams_count++] = set[i].stream; + + found = false; + } + + /* Remove all planes for unchanged streams if planes changed */ + for (i = 0; i < unchanged_streams_count; i++) { + if (planes_changed_for_existing_stream(context, + unchanged_streams[i], + set, + set_count)) { + if (!dc_rem_all_planes_for_stream(dc, + unchanged_streams[i], + context)) { + res = DC_FAIL_DETACH_SURFACES; + goto fail; + } + } + } + + /* Remove all planes for removed streams and then remove the streams */ + for (i = 0; i < del_streams_count; i++) { + /* Need to cpy the dwb data from the old stream in order to efc to work */ + if (del_streams[i]->num_wb_info > 0) { + for (j = 0; j < add_streams_count; j++) { + if (del_streams[i]->sink == add_streams[j]->sink) { + add_streams[j]->num_wb_info = del_streams[i]->num_wb_info; + for (k = 0; k < del_streams[i]->num_wb_info; k++) + add_streams[j]->writeback_info[k] = del_streams[i]->writeback_info[k]; + } + } + } + + if (!dc_rem_all_planes_for_stream(dc, del_streams[i], context)) { + res = DC_FAIL_DETACH_SURFACES; + goto fail; + } + + res = dc_remove_stream_from_ctx(dc, context, del_streams[i]); + if (res != DC_OK) + goto fail; + } + + /* Add new streams and then add all planes for the new stream */ + for (i = 0; i < add_streams_count; i++) { + calculate_phy_pix_clks(add_streams[i]); + res = dc_add_stream_to_ctx(dc, context, add_streams[i]); + if (res != DC_OK) + goto fail; + + if (!add_all_planes_for_stream(dc, add_streams[i], set, set_count, context)) { + res = DC_FAIL_ATTACH_SURFACES; + goto fail; + } + } + + /* Add all planes for unchanged streams if planes changed */ + for (i = 0; i < unchanged_streams_count; i++) { + if (planes_changed_for_existing_stream(context, + unchanged_streams[i], + set, + set_count)) { + if (!add_all_planes_for_stream(dc, unchanged_streams[i], set, set_count, context)) { + res = DC_FAIL_ATTACH_SURFACES; + goto fail; + } + } + } + + res = dc_validate_global_state(dc, context, fast_validate); + +fail: + if (res != DC_OK) + DC_LOG_WARNING("%s:resource validation failed, dc_status:%d\n", + __func__, + res); + + return res; +} /** - * dc_validate_global_state() - Determine if HW can support a given state - * Checks HW resource availability and bandwidth requirement. + * dc_validate_global_state() - Determine if hardware can support a given state + * * @dc: dc struct for this driver * @new_ctx: state to be validated * @fast_validate: set to true if only yes/no to support matters * - * Return: DC_OK if the result can be programmed. Otherwise, an error code. + * Checks hardware resource availability and bandwidth requirement. + * + * Return: + * DC_OK if the result can be programmed. Otherwise, an error code. */ enum dc_status dc_validate_global_state( struct dc *dc, @@ -3734,4 +3945,4 @@ bool dc_resource_acquire_secondary_pipe_for_mpc_odm( } return true; -} \ No newline at end of file +} diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 836cdf5d4114..bf938cda379a 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -1297,6 +1297,12 @@ enum dc_status dc_validate_plane(struct dc *dc, const struct dc_plane_state *pla void get_clock_requirements_for_state(struct dc_state *state, struct AsicStateEx *info); +enum dc_status dc_validate_with_context(struct dc *dc, + const struct dc_validation_set set[], + int set_count, + struct dc_state *context, + bool fast_validate); + bool dc_set_generic_gpio_for_stereo(bool enable, struct gpio_service *gpio_service); -- cgit From 170390e587a69b2a24abac39eb3ae6ec28a4d7f2 Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira Date: Tue, 18 Oct 2022 08:28:22 -0400 Subject: drm/amd/display: Handle seamless boot stream A seamless boot stream has hardware resources assigned to it, and adding a new stream means rebuilding the current assignment. It is desirable to avoid this situation since it may cause light-up issues on the VGA monitor on USB-C. This commit swaps the seamless boot stream to pipe 0 (if necessary) to ensure that the pipe context matches. Reviewed-by: Harry Wentland Signed-off-by: Rodrigo Siqueira Co-developed-by: Aurabindo Pillai Signed-off-by: Aurabindo Pillai Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index e001b138b2ac..ba2d4347f722 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -2765,6 +2765,21 @@ enum dc_status dc_validate_with_context(struct dc *dc, goto fail; } + /* Swap seamless boot stream to pipe 0 (if needed) to ensure pipe_ctx + * matches. This may change in the future if seamless_boot_stream can be + * multiple. + */ + for (i = 0; i < add_streams_count; i++) { + mark_seamless_boot_stream(dc, add_streams[i]); + if (add_streams[i]->apply_seamless_boot_optimization && i != 0) { + struct dc_stream_state *temp = add_streams[0]; + + add_streams[0] = add_streams[i]; + add_streams[i] = temp; + break; + } + } + /* Add new streams and then add all planes for the new stream */ for (i = 0; i < add_streams_count; i++) { calculate_phy_pix_clks(add_streams[i]); -- cgit From eef019eabc3cd0fddcffefbf67806a4d8cca29bb Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira Date: Tue, 18 Oct 2022 08:28:23 -0400 Subject: drm/amd/display: Update OTG instance in the commit stream OTG instance is not updated in dc_commit_state_no_check for newly committed streams because mode_change is not set. Notice that OTG update is part of the software state, and after hardware programming, it must be updated; for this reason, this commit updates the OTG offset right after hardware programming. Reviewed-by: Harry Wentland Signed-off-by: Rodrigo Siqueira Co-developed-by: Aurabindo Pillai Signed-off-by: Aurabindo Pillai Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index d568387c4bda..b7afada35b24 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -1949,6 +1949,12 @@ enum dc_status dc_commit_streams(struct dc *dc, res = dc_commit_state_no_check(dc, context); + for (i = 0; i < stream_count; i++) { + for (j = 0; j < context->stream_count; j++) + if (streams[i]->stream_id == context->streams[j]->stream_id) + streams[i]->out.otg_offset = context->stream_status[j].primary_otg_inst; + } + fail: dc_release_state(context); -- cgit From 7fffb03b4045c862f904a88b852dc509c4e46406 Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira Date: Tue, 18 Oct 2022 08:28:24 -0400 Subject: drm/amd/display: Avoid ABM when ODM combine is enabled for eDP ODM to combine on the eDP panel with ABM causes the color difference to the panel since the ABM module only sets one pipe. Hence, this commit blocks ABM in case of ODM combined on eDP. Reviewed-by: Harry Wentland Signed-off-by: Rodrigo Siqueira Co-developed-by: Aurabindo Pillai Signed-off-by: Aurabindo Pillai Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index b7afada35b24..375439c51cd3 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -1950,9 +1950,19 @@ enum dc_status dc_commit_streams(struct dc *dc, res = dc_commit_state_no_check(dc, context); for (i = 0; i < stream_count; i++) { - for (j = 0; j < context->stream_count; j++) + for (j = 0; j < context->stream_count; j++) { if (streams[i]->stream_id == context->streams[j]->stream_id) streams[i]->out.otg_offset = context->stream_status[j].primary_otg_inst; + + if (dc_is_embedded_signal(streams[i]->signal)) { + struct dc_stream_status *status = dc_stream_get_status_from_state(context, streams[i]); + + if (dc->hwss.is_abm_supported) + status->is_abm_supported = dc->hwss.is_abm_supported(dc, context, streams[i]); + else + status->is_abm_supported = true; + } + } } fail: -- cgit From dddde627807c22d6f15f4417eb395b13a1ca88f9 Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira Date: Tue, 18 Oct 2022 08:28:25 -0400 Subject: drm/amd/display: Use update plane and stream routine for DCN32x Sub-viewport (Subvp) feature is used for changing MCLK without causing any display artifact, requiring special treatment from the plane and stream perspective since DC needs to read data from the cache when using subvp. However, the function dc_commit_updates_for_stream does not provide all the support needed by this feature which will make this function legacy at some point. For this reason, this commit enables dc_update_planes_and_stream for ASICs that support this feature but preserves the old behavior for other ASICs. However, dc_update_planes_and_stream should replace dc_commit_updates_for_stream for all ASICs since it does most of the tasks executed by dc_commit_updates_for_stream with other extra operations, but we need to run tests before making this change. Reviewed-by: Harry Wentland Signed-off-by: Rodrigo Siqueira Co-developed-by: Aurabindo Pillai Signed-off-by: Aurabindo Pillai Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 375439c51cd3..56629197a6a1 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -3904,6 +3904,18 @@ void dc_commit_updates_for_stream(struct dc *dc, struct dc_context *dc_ctx = dc->ctx; int i, j; + /* TODO: Since change commit sequence can have a huge impact, + * we decided to only enable it for DCN3x. However, as soon as + * we get more confident about this change we'll need to enable + * the new sequence for all ASICs. + */ + if (dc->ctx->dce_version >= DCN_VERSION_3_2) { + dc_update_planes_and_stream(dc, srf_updates, + surface_count, stream, + stream_update); + return; + } + stream_status = dc_stream_get_status(stream); context = dc->current_state; -- cgit From fa16dec20440156fda208c3d289dfa15af3953dc Mon Sep 17 00:00:00 2001 From: Kenneth Feng Date: Thu, 20 Oct 2022 15:25:25 +0800 Subject: drm/amd/pm: allow gfxoff on gc_11_0_3 allow gfxoff on gc_11_0_3 Signed-off-by: Kenneth Feng Reviewed-by: Yang Wang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 1 + drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c index e3842dc100d6..5eefba2948a5 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c @@ -5051,6 +5051,7 @@ static int gfx_v11_0_set_powergating_state(void *handle, switch (adev->ip_versions[GC_HWIP][0]) { case IP_VERSION(11, 0, 0): case IP_VERSION(11, 0, 2): + case IP_VERSION(11, 0, 3): amdgpu_gfx_off_ctrl(adev, enable); break; case IP_VERSION(11, 0, 1): diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c index feb4d68f3fd9..43fb102a65f5 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c @@ -840,6 +840,7 @@ int smu_v13_0_gfx_off_control(struct smu_context *smu, bool enable) case IP_VERSION(13, 0, 5): case IP_VERSION(13, 0, 7): case IP_VERSION(13, 0, 8): + case IP_VERSION(13, 0, 10): if (!(adev->pm.pp_feature & PP_GFXOFF_MASK)) return 0; if (enable) -- cgit From 345b16961afe0deae8633ce10dbff46c7e64e35f Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira Date: Thu, 6 Oct 2022 17:26:48 -0400 Subject: drm/amd/display: Remove wrong pipe control lock When using a device based on DCN32/321, we have an issue where a second 4k@60Hz display does not light up, and the system becomes unresponsive for a few minutes. In the debug process, it was possible to see a hang in the function dcn20_post_unlock_program_front_end in this part: for (j = 0; j < TIMEOUT_FOR_PIPE_ENABLE_MS*1000 && hubp->funcs->hubp_is_flip_pending(hubp); j++) mdelay(1); } The hubp_is_flip_pending always returns positive for waiting pending flips which is a symptom of pipe hang. Additionally, the dmesg log shows this message after a few minutes: BUG: soft lockup - CPU#4 stuck for 26s! ... [ +0.000003] dcn20_post_unlock_program_front_end+0x112/0x340 [amdgpu] [ +0.000171] dc_commit_state_no_check+0x63d/0xbf0 [amdgpu] [ +0.000155] ? dc_validate_global_state+0x358/0x3d0 [amdgpu] [ +0.000154] dc_commit_state+0xe2/0xf0 [amdgpu] This confirmed the hypothesis that we had a pipe hanging somewhere. Next, after checking the ftrace entries, we have the below weird sequence: [..] 2) | dcn10_lock_all_pipes [amdgpu]() { 2) 0.120 us | optc1_is_tg_enabled [amdgpu](); 2) | dcn20_pipe_control_lock [amdgpu]() { 2) | dc_dmub_srv_clear_inbox0_ack [amdgpu]() { 2) 0.121 us | amdgpu_dm_dmub_reg_write [amdgpu](); 2) 0.551 us | } 2) | dc_dmub_srv_send_inbox0_cmd [amdgpu]() { 2) 0.110 us | amdgpu_dm_dmub_reg_write [amdgpu](); 2) 0.511 us | } 2) | dc_dmub_srv_wait_for_inbox0_ack [amdgpu]() { 2) 0.110 us | amdgpu_dm_dmub_reg_read [amdgpu](); 2) 0.110 us | amdgpu_dm_dmub_reg_read [amdgpu](); 2) 0.110 us | amdgpu_dm_dmub_reg_read [amdgpu](); 2) 0.110 us | amdgpu_dm_dmub_reg_read [amdgpu](); 2) 0.110 us | amdgpu_dm_dmub_reg_read [amdgpu](); 2) 0.110 us | amdgpu_dm_dmub_reg_read [amdgpu](); 2) 0.110 us | amdgpu_dm_dmub_reg_read [amdgpu](); [..] We are not expected to read from dmub register so many times and for so long. From the trace log, it was possible to identify that the function dcn20_pipe_control_lock was triggering the dmub operation when it was unnecessary and causing the hang issue. This commit drops the unnecessary dmub code and, consequently, fixes the second display not lighting up the issue. Tested-by: Daniel Wheeler Acked-by: Qingqing Zhuo Signed-off-by: Rodrigo Siqueira Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c index d732b6f031a1..a7e0001a8f46 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c @@ -1270,16 +1270,6 @@ void dcn20_pipe_control_lock( lock, &hw_locks, &inst_flags); - } else if (pipe->stream && pipe->stream->mall_stream_config.type == SUBVP_MAIN) { - union dmub_inbox0_cmd_lock_hw hw_lock_cmd = { 0 }; - hw_lock_cmd.bits.command_code = DMUB_INBOX0_CMD__HW_LOCK; - hw_lock_cmd.bits.hw_lock_client = HW_LOCK_CLIENT_DRIVER; - hw_lock_cmd.bits.lock_pipe = 1; - hw_lock_cmd.bits.otg_inst = pipe->stream_res.tg->inst; - hw_lock_cmd.bits.lock = lock; - if (!lock) - hw_lock_cmd.bits.should_release = 1; - dmub_hw_lock_mgr_inbox0_cmd(dc->ctx->dmub_srv, hw_lock_cmd); } else if (pipe->plane_state != NULL && pipe->plane_state->triplebuffer_flips) { if (lock) pipe->stream_res.tg->funcs->triplebuffer_lock(pipe->stream_res.tg); @@ -1856,7 +1846,7 @@ void dcn20_post_unlock_program_front_end( for (j = 0; j < TIMEOUT_FOR_PIPE_ENABLE_MS*1000 && hubp->funcs->hubp_is_flip_pending(hubp); j++) - mdelay(1); + udelay(1); } } -- cgit From 27fcf77830d0e8af53cd562909ff37aa3ec345dd Mon Sep 17 00:00:00 2001 From: Alvin Lee Date: Thu, 6 Oct 2022 17:26:49 -0400 Subject: drm/amd/display: Don't return false if no stream pipe_ctx[i] exists even if the pipe is not in use. If the pipe is not in use it will always have a null stream, so don't return false in this case. Tested-by: Daniel Wheeler Reviewed-by: Rodrigo Siqueira Acked-by: Qingqing Zhuo Signed-off-by: Alvin Lee Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c index d51d0c40ae5b..b03a7814e96d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c @@ -200,7 +200,7 @@ bool dcn32_all_pipes_have_stream_and_plane(struct dc *dc, struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; if (!pipe->stream) - return false; + continue; if (!pipe->plane_state) return false; -- cgit From 6c16afdcec20b01879ad17440f42c9944786dc7d Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 19 Oct 2022 16:57:42 -0400 Subject: drm/amdgpu: fix sdma doorbell init ordering on APUs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 8795e182b02d ("PCI/portdrv: Don't disable AER reporting in get_port_device_capability()") uncovered a bug in amdgpu that required a reordering of the driver init sequence to avoid accessing a special register on the GPU before it was properly set up leading to an PCI AER error. This reordering uncovered a different hw programming ordering dependency in some APUs where the SDMA doorbells need to be programmed before the GFX doorbells. To fix this, move the SDMA doorbell programming back into the soc15 common code, but use the actual doorbell range values directly rather than the values stored in the ring structure since those will not be initialized at this point. This is a partial revert, but with the doorbell assignment fixed so the proper doorbell index is set before it's used. Fixes: e3163bc8ffdfdb ("drm/amdgpu: move nbio sdma_doorbell_range() into sdma code for vega") Acked-by: Christian König Signed-off-by: Alex Deucher Cc: skhan@linuxfoundation.org --- drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c | 5 ----- drivers/gpu/drm/amd/amdgpu/soc15.c | 21 +++++++++++++++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c index 298fa11702e7..1122bd4eae98 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c @@ -1417,11 +1417,6 @@ static int sdma_v4_0_start(struct amdgpu_device *adev) WREG32_SDMA(i, mmSDMA0_CNTL, temp); if (!amdgpu_sriov_vf(adev)) { - ring = &adev->sdma.instance[i].ring; - adev->nbio.funcs->sdma_doorbell_range(adev, i, - ring->use_doorbell, ring->doorbell_index, - adev->doorbell_index.sdma_doorbell_range); - /* unhalt engine */ temp = RREG32_SDMA(i, mmSDMA0_F32_CNTL); temp = REG_SET_FIELD(temp, SDMA0_F32_CNTL, HALT, 0); diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.c b/drivers/gpu/drm/amd/amdgpu/soc15.c index 183024d7c184..e3b2b6b4f1a6 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc15.c +++ b/drivers/gpu/drm/amd/amdgpu/soc15.c @@ -1211,6 +1211,20 @@ static int soc15_common_sw_fini(void *handle) return 0; } +static void soc15_sdma_doorbell_range_init(struct amdgpu_device *adev) +{ + int i; + + /* sdma doorbell range is programed by hypervisor */ + if (!amdgpu_sriov_vf(adev)) { + for (i = 0; i < adev->sdma.num_instances; i++) { + adev->nbio.funcs->sdma_doorbell_range(adev, i, + true, adev->doorbell_index.sdma_engine[i] << 1, + adev->doorbell_index.sdma_doorbell_range); + } + } +} + static int soc15_common_hw_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; @@ -1230,6 +1244,13 @@ static int soc15_common_hw_init(void *handle) /* enable the doorbell aperture */ soc15_enable_doorbell_aperture(adev, true); + /* HW doorbell routing policy: doorbell writing not + * in SDMA/IH/MM/ACV range will be routed to CP. So + * we need to init SDMA doorbell range prior + * to CP ip block init and ring test. IH already + * happens before CP. + */ + soc15_sdma_doorbell_range_init(adev); return 0; } -- cgit From 9feece0d96124096e7268007bd2d3905a29d92ac Mon Sep 17 00:00:00 2001 From: ruanjinjie Date: Wed, 19 Oct 2022 15:45:02 +0800 Subject: drm/amd/display: Make some symbols static These symbols qp_table_422_10bpc_min, qp_table_444_8bpc_max, qp_table_420_12bpc_max, qp_table_444_10bpc_min, qp_table_420_8bpc_max, qp_table_444_8bpc_min, qp_table_444_12bpc_min, qp_table_420_12bpc_min, qp_table_422_12bpc_min, qp_table_422_12bpc_max, qp_table_444_12bpc_max, qp_table_420_8bpc_min, qp_table_422_8bpc_min, qp_table_422_10bpc_max, qp_table_420_10bpc_max, qp_table_420_10bpc_min, qp_table_444_10bpc_max, qp_table_422_8bpc_max are not used outside of the file, so mark them static. ./drivers/gpu/drm/amd/amdgpu/../display/dc/dml/dsc/qp_tables.h:28:18: warning: symbol 'qp_table_422_10bpc_min' was not declared. Should it be static? ./drivers/gpu/drm/amd/amdgpu/../display/dc/dml/dsc/qp_tables.h:61:18: warning: symbol 'qp_table_444_8bpc_max' was not declared. Should it be static? ./drivers/gpu/drm/amd/amdgpu/../display/dc/dml/dsc/qp_tables.h:102:18: warning: symbol 'qp_table_420_12bpc_max' was not declared. Should it be static? ./drivers/gpu/drm/amd/amdgpu/../display/dc/dml/dsc/qp_tables.h:135:18: warning: symbol 'qp_table_444_10bpc_min' was not declared. Should it be static? ./drivers/gpu/drm/amd/amdgpu/../display/dc/dml/dsc/qp_tables.h:188:18: warning: symbol 'qp_table_420_8bpc_max' was not declared. Should it be static? ./drivers/gpu/drm/amd/amdgpu/../display/dc/dml/dsc/qp_tables.h:209:18: warning: symbol 'qp_table_444_8bpc_min' was not declared. Should it be static? ./drivers/gpu/drm/amd/amdgpu/../display/dc/dml/dsc/qp_tables.h:250:18: warning: symbol 'qp_table_444_12bpc_min' was not declared. Should it be static? ./drivers/gpu/drm/amd/amdgpu/../display/dc/dml/dsc/qp_tables.h:315:18: warning: symbol 'qp_table_420_12bpc_min' was not declared. Should it be static? ./drivers/gpu/drm/amd/amdgpu/../display/dc/dml/dsc/qp_tables.h:348:18: warning: symbol 'qp_table_422_12bpc_min' was not declared. Should it be static? ./drivers/gpu/drm/amd/amdgpu/../display/dc/dml/dsc/qp_tables.h:389:18: warning: symbol 'qp_table_422_12bpc_max' was not declared. Should it be static? ./drivers/gpu/drm/amd/amdgpu/../display/dc/dml/dsc/qp_tables.h:430:18: warning: symbol 'qp_table_444_12bpc_max' was not declared. Should it be static? ./drivers/gpu/drm/amd/amdgpu/../display/dc/dml/dsc/qp_tables.h:495:18: warning: symbol 'qp_table_420_8bpc_min' was not declared. Should it be static? ./drivers/gpu/drm/amd/amdgpu/../display/dc/dml/dsc/qp_tables.h:516:18: warning: symbol 'qp_table_422_8bpc_min' was not declared. Should it be static? ./drivers/gpu/drm/amd/amdgpu/../display/dc/dml/dsc/qp_tables.h:541:18: warning: symbol 'qp_table_422_10bpc_max' was not declared. Should it be static? ./drivers/gpu/drm/amd/amdgpu/../display/dc/dml/dsc/qp_tables.h:574:16: warning: symbol 'qp_table_420_10bpc_max' was not declared. Should it be static? ./drivers/gpu/drm/amd/amdgpu/../display/dc/dml/dsc/qp_tables.h:601:18: warning: symbol 'qp_table_420_10bpc_min' was not declared. Should it be static? ./drivers/gpu/drm/amd/amdgpu/../display/dc/dml/dsc/qp_tables.h:628:18: warning: symbol 'qp_table_444_10bpc_max' was not declared. Should it be static? ./drivers/gpu/drm/amd/amdgpu/../display/dc/dml/dsc/qp_tables.h:681:18: warning: symbol 'qp_table_422_8bpc_max' was not declared. Should it be static? Signed-off-by: ruanjinjie Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dml/dsc/qp_tables.h | 36 +++++++++++----------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dml/dsc/qp_tables.h b/drivers/gpu/drm/amd/display/dc/dml/dsc/qp_tables.h index e5fac9f4181d..dcff0dd2b6a1 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dsc/qp_tables.h +++ b/drivers/gpu/drm/amd/display/dc/dml/dsc/qp_tables.h @@ -25,7 +25,7 @@ */ -const qp_table qp_table_422_10bpc_min = { +static const qp_table qp_table_422_10bpc_min = { { 6, { 0, 4, 5, 6, 6, 6, 6, 7, 7, 8, 9, 9, 9, 12, 16} }, { 6.5, { 0, 4, 5, 6, 6, 6, 6, 7, 7, 8, 9, 9, 9, 12, 16} }, { 7, { 0, 4, 5, 6, 6, 6, 6, 7, 7, 7, 9, 9, 9, 11, 15} }, @@ -58,7 +58,7 @@ const qp_table qp_table_422_10bpc_min = { }; -const qp_table qp_table_444_8bpc_max = { +static const qp_table qp_table_444_8bpc_max = { { 6, { 4, 6, 8, 8, 9, 9, 9, 10, 11, 12, 12, 12, 12, 13, 15} }, { 6.5, { 4, 6, 7, 8, 8, 8, 9, 10, 11, 11, 12, 12, 12, 13, 15} }, { 7, { 4, 5, 7, 7, 8, 8, 8, 9, 10, 11, 11, 12, 12, 13, 14} }, @@ -99,7 +99,7 @@ const qp_table qp_table_444_8bpc_max = { }; -const qp_table qp_table_420_12bpc_max = { +static const qp_table qp_table_420_12bpc_max = { { 4, {11, 12, 13, 14, 15, 15, 15, 16, 17, 18, 18, 19, 19, 21, 22} }, { 4.5, {10, 11, 12, 13, 14, 15, 15, 16, 17, 18, 18, 19, 19, 20, 21} }, { 5, { 9, 11, 12, 13, 14, 15, 15, 16, 17, 17, 18, 18, 19, 20, 21} }, @@ -132,7 +132,7 @@ const qp_table qp_table_420_12bpc_max = { }; -const qp_table qp_table_444_10bpc_min = { +static const qp_table qp_table_444_10bpc_min = { { 6, { 0, 4, 7, 7, 9, 9, 9, 9, 9, 10, 10, 10, 10, 12, 18} }, { 6.5, { 0, 4, 6, 7, 8, 8, 9, 9, 9, 9, 10, 10, 10, 12, 18} }, { 7, { 0, 4, 6, 6, 8, 8, 8, 8, 8, 9, 9, 10, 10, 12, 17} }, @@ -185,7 +185,7 @@ const qp_table qp_table_444_10bpc_min = { }; -const qp_table qp_table_420_8bpc_max = { +static const qp_table qp_table_420_8bpc_max = { { 4, { 4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 10, 11, 11, 13, 14} }, { 4.5, { 4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 10, 11, 11, 12, 13} }, { 5, { 3, 4, 5, 6, 7, 7, 7, 8, 9, 9, 10, 10, 11, 12, 13} }, @@ -206,7 +206,7 @@ const qp_table qp_table_420_8bpc_max = { }; -const qp_table qp_table_444_8bpc_min = { +static const qp_table qp_table_444_8bpc_min = { { 6, { 0, 1, 3, 3, 5, 5, 5, 5, 5, 6, 6, 6, 6, 9, 14} }, { 6.5, { 0, 1, 2, 3, 4, 4, 5, 5, 5, 5, 6, 6, 6, 9, 14} }, { 7, { 0, 0, 2, 2, 4, 4, 4, 4, 4, 5, 5, 6, 6, 9, 13} }, @@ -247,7 +247,7 @@ const qp_table qp_table_444_8bpc_min = { }; -const qp_table qp_table_444_12bpc_min = { +static const qp_table qp_table_444_12bpc_min = { { 6, { 0, 5, 11, 11, 13, 13, 13, 13, 13, 14, 14, 14, 14, 17, 22} }, { 6.5, { 0, 5, 10, 11, 12, 12, 13, 13, 13, 13, 14, 14, 14, 17, 22} }, { 7, { 0, 5, 10, 10, 12, 12, 12, 12, 12, 13, 13, 14, 14, 17, 21} }, @@ -312,7 +312,7 @@ const qp_table qp_table_444_12bpc_min = { }; -const qp_table qp_table_420_12bpc_min = { +static const qp_table qp_table_420_12bpc_min = { { 4, { 0, 4, 9, 10, 11, 11, 11, 11, 11, 11, 13, 13, 13, 15, 21} }, { 4.5, { 0, 4, 8, 9, 10, 11, 11, 11, 11, 11, 13, 13, 13, 15, 20} }, { 5, { 0, 4, 8, 9, 10, 11, 11, 11, 11, 11, 13, 13, 13, 15, 20} }, @@ -345,7 +345,7 @@ const qp_table qp_table_420_12bpc_min = { }; -const qp_table qp_table_422_12bpc_min = { +static const qp_table qp_table_422_12bpc_min = { { 6, { 0, 4, 9, 10, 11, 11, 11, 11, 11, 11, 13, 13, 13, 16, 20} }, { 6.5, { 0, 4, 9, 10, 11, 11, 11, 11, 11, 11, 13, 13, 13, 16, 20} }, { 7, { 0, 4, 9, 10, 11, 11, 11, 11, 11, 11, 13, 13, 13, 15, 19} }, @@ -386,7 +386,7 @@ const qp_table qp_table_422_12bpc_min = { }; -const qp_table qp_table_422_12bpc_max = { +static const qp_table qp_table_422_12bpc_max = { { 6, {12, 12, 13, 14, 15, 15, 15, 16, 17, 18, 18, 19, 19, 20, 21} }, { 6.5, {12, 12, 13, 14, 15, 15, 15, 16, 17, 18, 18, 19, 19, 20, 21} }, { 7, {11, 12, 13, 14, 15, 15, 15, 16, 17, 17, 18, 18, 19, 19, 20} }, @@ -427,7 +427,7 @@ const qp_table qp_table_422_12bpc_max = { }; -const qp_table qp_table_444_12bpc_max = { +static const qp_table qp_table_444_12bpc_max = { { 6, {12, 14, 16, 16, 17, 17, 17, 18, 19, 20, 20, 20, 20, 21, 23} }, { 6.5, {12, 14, 15, 16, 16, 16, 17, 18, 19, 19, 20, 20, 20, 21, 23} }, { 7, {12, 13, 15, 15, 16, 16, 16, 17, 18, 19, 19, 20, 20, 21, 22} }, @@ -492,7 +492,7 @@ const qp_table qp_table_444_12bpc_max = { }; -const qp_table qp_table_420_8bpc_min = { +static const qp_table qp_table_420_8bpc_min = { { 4, { 0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 9, 13} }, { 4.5, { 0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 8, 12} }, { 5, { 0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 8, 12} }, @@ -513,7 +513,7 @@ const qp_table qp_table_420_8bpc_min = { }; -const qp_table qp_table_422_8bpc_min = { +static const qp_table qp_table_422_8bpc_min = { { 6, { 0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 5, 5, 5, 8, 12} }, { 6.5, { 0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 5, 5, 5, 8, 12} }, { 7, { 0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 11} }, @@ -538,7 +538,7 @@ const qp_table qp_table_422_8bpc_min = { }; -const qp_table qp_table_422_10bpc_max = { +static const qp_table qp_table_422_10bpc_max = { { 6, { 8, 8, 9, 10, 11, 11, 11, 12, 13, 14, 14, 15, 15, 16, 17} }, { 6.5, { 8, 8, 9, 10, 11, 11, 11, 12, 13, 14, 14, 15, 15, 16, 17} }, { 7, { 7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16} }, @@ -571,7 +571,7 @@ const qp_table qp_table_422_10bpc_max = { }; -const qp_table qp_table_420_10bpc_max = { +static const qp_table qp_table_420_10bpc_max = { { 4, { 8, 8, 9, 10, 11, 11, 11, 12, 13, 14, 14, 15, 15, 17, 18} }, { 4.5, { 8, 8, 9, 10, 11, 11, 11, 12, 13, 14, 14, 15, 15, 16, 17} }, { 5, { 7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 16, 17} }, @@ -598,7 +598,7 @@ const qp_table qp_table_420_10bpc_max = { }; -const qp_table qp_table_420_10bpc_min = { +static const qp_table qp_table_420_10bpc_min = { { 4, { 0, 4, 4, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 13, 17} }, { 4.5, { 0, 4, 4, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 12, 16} }, { 5, { 0, 4, 4, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 12, 16} }, @@ -625,7 +625,7 @@ const qp_table qp_table_420_10bpc_min = { }; -const qp_table qp_table_444_10bpc_max = { +static const qp_table qp_table_444_10bpc_max = { { 6, { 8, 10, 12, 12, 13, 13, 13, 14, 15, 16, 16, 16, 16, 17, 19} }, { 6.5, { 8, 10, 11, 12, 12, 12, 13, 14, 15, 15, 16, 16, 16, 17, 19} }, { 7, { 8, 9, 11, 11, 12, 12, 12, 13, 14, 15, 15, 16, 16, 17, 18} }, @@ -678,7 +678,7 @@ const qp_table qp_table_444_10bpc_max = { }; -const qp_table qp_table_422_8bpc_max = { +static const qp_table qp_table_422_8bpc_max = { { 6, { 4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 10, 11, 11, 12, 13} }, { 6.5, { 4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 10, 11, 11, 12, 13} }, { 7, { 3, 4, 5, 6, 7, 7, 7, 8, 9, 9, 10, 10, 11, 11, 12} }, -- cgit From 72c9abd5399d9f5c20a5b93737e67edba3189079 Mon Sep 17 00:00:00 2001 From: ruanjinjie Date: Wed, 19 Oct 2022 14:31:15 +0800 Subject: drm/amd/display: make dcn32_mmhubbub_funcs static The symbol is not used outside of the file, so mark it static. Fixes the following warning: drivers/gpu/drm/amd/amdgpu/../display/dc/dcn32/dcn32_mmhubbub.c:214:28: warning: symbol 'dcn32_mmhubbub_funcs' was not declared. Should it be static? Reviewed-by: Harry Wentland Signed-off-by: ruanjinjie Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mmhubbub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mmhubbub.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mmhubbub.c index 41b0baf8e183..c3b089ba511a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mmhubbub.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mmhubbub.c @@ -211,7 +211,7 @@ static void mmhubbub32_config_mcif_arb(struct mcif_wb *mcif_wb, REG_UPDATE(MCIF_WB_ARBITRATION_CONTROL, MCIF_WB_CLIENT_ARBITRATION_SLICE, params->arbitration_slice); } -const struct mcif_wb_funcs dcn32_mmhubbub_funcs = { +static const struct mcif_wb_funcs dcn32_mmhubbub_funcs = { .warmup_mcif = mmhubbub32_warmup_mcif, .enable_mcif = mmhubbub2_enable_mcif, .disable_mcif = mmhubbub2_disable_mcif, -- cgit From 178919f8ff2d4cd1ad32680eb767e6761e9d00ea Mon Sep 17 00:00:00 2001 From: ruanjinjie Date: Wed, 19 Oct 2022 14:23:47 +0800 Subject: drm/amd/display: make dcn32_mpc_funcs static The symbol is not used outside of the file, so mark it static. Fixes the following warning: drivers/gpu/drm/amd/amdgpu/../display/dc/dcn32/dcn32_mpc.c:985:24: warning: symbol 'dcn32_mpc_funcs' was not declared. Should it be static? Reviewed-by: Harry Wentland Signed-off-by: ruanjinjie Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c index 4edd0655965b..206a5ddbaf6d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c @@ -982,7 +982,7 @@ static bool mpc32_program_3dlut( return true; } -const struct mpc_funcs dcn32_mpc_funcs = { +static const struct mpc_funcs dcn32_mpc_funcs = { .read_mpcc_state = mpc1_read_mpcc_state, .insert_plane = mpc1_insert_plane, .remove_mpcc = mpc1_remove_mpcc, -- cgit From 3a3e841d050d9d919317ad2b65d80fc9c8c799dc Mon Sep 17 00:00:00 2001 From: Deming Wang Date: Thu, 6 Oct 2022 22:26:51 -0400 Subject: drm/amdkfd: use vma_lookup() instead of find_vma() Using vma_lookup() verifies the start address is contained in the found vma. This results in easier to read the code. Signed-off-by: Deming Wang Reviewed-by: Felix Kuehling Signed-off-by: Felix Kuehling Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 8 ++++---- drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 17 ++++++++--------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c index 2797029bd500..d4e6de2a6bf6 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c @@ -529,8 +529,8 @@ svm_migrate_ram_to_vram(struct svm_range *prange, uint32_t best_loc, for (addr = start; addr < end;) { unsigned long next; - vma = find_vma(mm, addr); - if (!vma || addr < vma->vm_start) + vma = vma_lookup(mm, addr); + if (!vma) break; next = min(vma->vm_end, end); @@ -798,8 +798,8 @@ int svm_migrate_vram_to_ram(struct svm_range *prange, struct mm_struct *mm, for (addr = start; addr < end;) { unsigned long next; - vma = find_vma(mm, addr); - if (!vma || addr < vma->vm_start) { + vma = vma_lookup(mm, addr); + if (!vma) { pr_debug("failed to find vma for prange %p\n", prange); r = -EFAULT; break; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index 64fdf63093a0..0100812478b2 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -1586,8 +1586,8 @@ static int svm_range_validate_and_map(struct mm_struct *mm, unsigned long npages; bool readonly; - vma = find_vma(mm, addr); - if (!vma || addr < vma->vm_start) { + vma = vma_lookup(mm, addr); + if (!vma) { r = -EFAULT; goto unreserve_out; } @@ -2542,8 +2542,8 @@ svm_range_get_range_boundaries(struct kfd_process *p, int64_t addr, struct interval_tree_node *node; unsigned long start_limit, end_limit; - vma = find_vma(p->mm, addr << PAGE_SHIFT); - if (!vma || (addr << PAGE_SHIFT) < vma->vm_start) { + vma = vma_lookup(p->mm, addr << PAGE_SHIFT); + if (!vma) { pr_debug("VMA does not exist in address [0x%llx]\n", addr); return -EFAULT; } @@ -2871,8 +2871,8 @@ retry_write_locked: /* __do_munmap removed VMA, return success as we are handling stale * retry fault. */ - vma = find_vma(mm, addr << PAGE_SHIFT); - if (!vma || (addr << PAGE_SHIFT) < vma->vm_start) { + vma = vma_lookup(mm, addr << PAGE_SHIFT); + if (!vma) { pr_debug("address 0x%llx VMA is removed\n", addr); r = 0; goto out_unlock_range; @@ -3152,9 +3152,8 @@ svm_range_is_valid(struct kfd_process *p, uint64_t start, uint64_t size) start <<= PAGE_SHIFT; end = start + (size << PAGE_SHIFT); do { - vma = find_vma(p->mm, start); - if (!vma || start < vma->vm_start || - (vma->vm_flags & device_vma)) + vma = vma_lookup(p->mm, start); + if (!vma || (vma->vm_flags & device_vma)) return -EFAULT; start = min(end, vma->vm_end); } while (start < end); -- cgit From b72362962a66693cd095389cbe41dd005bfcfb44 Mon Sep 17 00:00:00 2001 From: David Francis Date: Fri, 16 Sep 2022 11:15:01 -0400 Subject: drm/amd: Add IMU fw version to fw version queries IMU is a new firmware for GFX11. There are four means by which firmware version can be queried from the driver: device attributes, vf2pf, debugfs, and the AMDGPU_INFO_FW_VERSION option in the amdgpu info ioctl. Add IMU as an option for those four methods. V2: Added debugfs Reviewed-by: Likun Gao Reviewed-by: Alex Deucher Signed-off-by: David Francis Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 13 +++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c | 4 +++- drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c | 1 + drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h | 1 + include/uapi/drm/amdgpu_drm.h | 2 ++ 5 files changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index fe23e09eec98..bf1ff8f0e712 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -344,6 +344,10 @@ static int amdgpu_firmware_info(struct drm_amdgpu_info_firmware *fw_info, fw_info->ver = adev->mes.ucode_fw_version[1]; fw_info->feature = 0; break; + case AMDGPU_INFO_FW_IMU: + fw_info->ver = adev->gfx.imu_fw_version; + fw_info->feature = 0; + break; default: return -EINVAL; } @@ -1520,6 +1524,15 @@ static int amdgpu_debugfs_firmware_info_show(struct seq_file *m, void *unused) fw_info.feature, fw_info.ver); } + /* IMU */ + query_fw.fw_type = AMDGPU_INFO_FW_IMU; + query_fw.index = 0; + ret = amdgpu_firmware_info(&fw_info, &query_fw, adev); + if (ret) + return ret; + seq_printf(m, "IMU feature version: %u, firmware version: 0x%08x\n", + fw_info.feature, fw_info.ver); + /* PSP SOS */ query_fw.fw_type = AMDGPU_INFO_FW_SOS; ret = amdgpu_firmware_info(&fw_info, &query_fw, adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c index dd0bc649a57d..5cb62e6249c2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c @@ -698,6 +698,7 @@ FW_VERSION_ATTR(rlc_srlg_fw_version, 0444, gfx.rlc_srlg_fw_version); FW_VERSION_ATTR(rlc_srls_fw_version, 0444, gfx.rlc_srls_fw_version); FW_VERSION_ATTR(mec_fw_version, 0444, gfx.mec_fw_version); FW_VERSION_ATTR(mec2_fw_version, 0444, gfx.mec2_fw_version); +FW_VERSION_ATTR(imu_fw_version, 0444, gfx.imu_fw_version); FW_VERSION_ATTR(sos_fw_version, 0444, psp.sos.fw_version); FW_VERSION_ATTR(asd_fw_version, 0444, psp.asd_context.bin_desc.fw_version); FW_VERSION_ATTR(ta_ras_fw_version, 0444, psp.ras_context.context.bin_desc.fw_version); @@ -719,7 +720,8 @@ static struct attribute *fw_attrs[] = { &dev_attr_ta_ras_fw_version.attr, &dev_attr_ta_xgmi_fw_version.attr, &dev_attr_smc_fw_version.attr, &dev_attr_sdma_fw_version.attr, &dev_attr_sdma2_fw_version.attr, &dev_attr_vcn_fw_version.attr, - &dev_attr_dmcu_fw_version.attr, NULL + &dev_attr_dmcu_fw_version.attr, &dev_attr_imu_fw_version.attr, + NULL }; static const struct attribute_group fw_attr_group = { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c index 9c765b04aae3..c73abe54d974 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c @@ -547,6 +547,7 @@ static void amdgpu_virt_populate_vf2pf_ucode_info(struct amdgpu_device *adev) POPULATE_UCODE_INFO(vf2pf_info, AMD_SRIOV_UCODE_ID_RLC_SRLS, adev->gfx.rlc_srls_fw_version); POPULATE_UCODE_INFO(vf2pf_info, AMD_SRIOV_UCODE_ID_MEC, adev->gfx.mec_fw_version); POPULATE_UCODE_INFO(vf2pf_info, AMD_SRIOV_UCODE_ID_MEC2, adev->gfx.mec2_fw_version); + POPULATE_UCODE_INFO(vf2pf_info, AMD_SRIOV_UCODE_ID_IMU, adev->gfx.imu_fw_version); POPULATE_UCODE_INFO(vf2pf_info, AMD_SRIOV_UCODE_ID_SOS, adev->psp.sos.fw_version); POPULATE_UCODE_INFO(vf2pf_info, AMD_SRIOV_UCODE_ID_ASD, adev->psp.asd_context.bin_desc.fw_version); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h b/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h index e78e4c27b62a..6c97148ca0ed 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h @@ -70,6 +70,7 @@ enum amd_sriov_ucode_engine_id { AMD_SRIOV_UCODE_ID_RLC_SRLS, AMD_SRIOV_UCODE_ID_MEC, AMD_SRIOV_UCODE_ID_MEC2, + AMD_SRIOV_UCODE_ID_IMU, AMD_SRIOV_UCODE_ID_SOS, AMD_SRIOV_UCODE_ID_ASD, AMD_SRIOV_UCODE_ID_TA_RAS, diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h index 7ee65c0b4f70..0d93ec132ebb 100644 --- a/include/uapi/drm/amdgpu_drm.h +++ b/include/uapi/drm/amdgpu_drm.h @@ -763,6 +763,8 @@ struct drm_amdgpu_cs_chunk_data { #define AMDGPU_INFO_FW_MES_KIQ 0x19 /* Subquery id: Query MES firmware version */ #define AMDGPU_INFO_FW_MES 0x1a + /* Subquery id: Query IMU firmware version */ + #define AMDGPU_INFO_FW_IMU 0x1b /* number of bytes moved for TTM migration */ #define AMDGPU_INFO_NUM_BYTES_MOVED 0x0f -- cgit From a9232b068e3698b8aa4a29fb7292bfdeb0c8f4ff Mon Sep 17 00:00:00 2001 From: Prike Liang Date: Thu, 20 Oct 2022 14:44:26 +0800 Subject: drm/amdkfd: update gfx1037 Lx cache setting Update the gfx1037 L1/L2 cache setting. Signed-off-by: Prike Liang Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_crat.c | 53 ++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c index cd5f8b219bf9..d6fa787ff490 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c @@ -795,6 +795,54 @@ static struct kfd_gpu_cache_info yellow_carp_cache_info[] = { }, }; +static struct kfd_gpu_cache_info gfx1037_cache_info[] = { + { + /* TCP L1 Cache per CU */ + .cache_size = 16, + .cache_level = 1, + .flags = (CRAT_CACHE_FLAGS_ENABLED | + CRAT_CACHE_FLAGS_DATA_CACHE | + CRAT_CACHE_FLAGS_SIMD_CACHE), + .num_cu_shared = 1, + }, + { + /* Scalar L1 Instruction Cache per SQC */ + .cache_size = 32, + .cache_level = 1, + .flags = (CRAT_CACHE_FLAGS_ENABLED | + CRAT_CACHE_FLAGS_INST_CACHE | + CRAT_CACHE_FLAGS_SIMD_CACHE), + .num_cu_shared = 2, + }, + { + /* Scalar L1 Data Cache per SQC */ + .cache_size = 16, + .cache_level = 1, + .flags = (CRAT_CACHE_FLAGS_ENABLED | + CRAT_CACHE_FLAGS_DATA_CACHE | + CRAT_CACHE_FLAGS_SIMD_CACHE), + .num_cu_shared = 2, + }, + { + /* GL1 Data Cache per SA */ + .cache_size = 128, + .cache_level = 1, + .flags = (CRAT_CACHE_FLAGS_ENABLED | + CRAT_CACHE_FLAGS_DATA_CACHE | + CRAT_CACHE_FLAGS_SIMD_CACHE), + .num_cu_shared = 2, + }, + { + /* L2 Data Cache per GPU (Total Tex Cache) */ + .cache_size = 256, + .cache_level = 2, + .flags = (CRAT_CACHE_FLAGS_ENABLED | + CRAT_CACHE_FLAGS_DATA_CACHE | + CRAT_CACHE_FLAGS_SIMD_CACHE), + .num_cu_shared = 2, + }, +}; + static void kfd_populated_cu_info_cpu(struct kfd_topology_device *dev, struct crat_subtype_computeunit *cu) { @@ -1515,10 +1563,13 @@ static int kfd_fill_gpu_cache_info(struct kfd_dev *kdev, break; case IP_VERSION(10, 3, 3): case IP_VERSION(10, 3, 6): /* TODO: Double check these on production silicon */ - case IP_VERSION(10, 3, 7): /* TODO: Double check these on production silicon */ pcache_info = yellow_carp_cache_info; num_of_cache_types = ARRAY_SIZE(yellow_carp_cache_info); break; + case IP_VERSION(10, 3, 7): + pcache_info = gfx1037_cache_info; + num_of_cache_types = ARRAY_SIZE(gfx1037_cache_info); + break; case IP_VERSION(11, 0, 0): case IP_VERSION(11, 0, 1): case IP_VERSION(11, 0, 2): -- cgit From d62eaddbc9ae27e1d98389b74778b29d4c1388d4 Mon Sep 17 00:00:00 2001 From: Jesse Zhang Date: Tue, 11 Oct 2022 05:23:10 +0000 Subject: drm/amdkfd: correct the cache info for gfx1036 correct the cache information for gfx1036 Acked-by: Alex Deucher Reviewed-by: Yifan Zhang Signed-off-by: Yifan Zhang Signed-off-by: Jesse Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_crat.c | 53 ++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c index d6fa787ff490..8bfdfd062ff6 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c @@ -843,6 +843,54 @@ static struct kfd_gpu_cache_info gfx1037_cache_info[] = { }, }; +static struct kfd_gpu_cache_info gc_10_3_6_cache_info[] = { + { + /* TCP L1 Cache per CU */ + .cache_size = 16, + .cache_level = 1, + .flags = (CRAT_CACHE_FLAGS_ENABLED | + CRAT_CACHE_FLAGS_DATA_CACHE | + CRAT_CACHE_FLAGS_SIMD_CACHE), + .num_cu_shared = 1, + }, + { + /* Scalar L1 Instruction Cache per SQC */ + .cache_size = 32, + .cache_level = 1, + .flags = (CRAT_CACHE_FLAGS_ENABLED | + CRAT_CACHE_FLAGS_INST_CACHE | + CRAT_CACHE_FLAGS_SIMD_CACHE), + .num_cu_shared = 2, + }, + { + /* Scalar L1 Data Cache per SQC */ + .cache_size = 16, + .cache_level = 1, + .flags = (CRAT_CACHE_FLAGS_ENABLED | + CRAT_CACHE_FLAGS_DATA_CACHE | + CRAT_CACHE_FLAGS_SIMD_CACHE), + .num_cu_shared = 2, + }, + { + /* GL1 Data Cache per SA */ + .cache_size = 128, + .cache_level = 1, + .flags = (CRAT_CACHE_FLAGS_ENABLED | + CRAT_CACHE_FLAGS_DATA_CACHE | + CRAT_CACHE_FLAGS_SIMD_CACHE), + .num_cu_shared = 2, + }, + { + /* L2 Data Cache per GPU (Total Tex Cache) */ + .cache_size = 256, + .cache_level = 2, + .flags = (CRAT_CACHE_FLAGS_ENABLED | + CRAT_CACHE_FLAGS_DATA_CACHE | + CRAT_CACHE_FLAGS_SIMD_CACHE), + .num_cu_shared = 2, + }, +}; + static void kfd_populated_cu_info_cpu(struct kfd_topology_device *dev, struct crat_subtype_computeunit *cu) { @@ -1562,10 +1610,13 @@ static int kfd_fill_gpu_cache_info(struct kfd_dev *kdev, num_of_cache_types = ARRAY_SIZE(beige_goby_cache_info); break; case IP_VERSION(10, 3, 3): - case IP_VERSION(10, 3, 6): /* TODO: Double check these on production silicon */ pcache_info = yellow_carp_cache_info; num_of_cache_types = ARRAY_SIZE(yellow_carp_cache_info); break; + case IP_VERSION(10, 3, 6): + pcache_info = gc_10_3_6_cache_info; + num_of_cache_types = ARRAY_SIZE(gc_10_3_6_cache_info); + break; case IP_VERSION(10, 3, 7): pcache_info = gfx1037_cache_info; num_of_cache_types = ARRAY_SIZE(gfx1037_cache_info); -- cgit From fd72e2cb2f9dd2734e8013b3e185a21f0d605d3e Mon Sep 17 00:00:00 2001 From: Prike Liang Date: Fri, 21 Oct 2022 16:38:48 -0400 Subject: drm/amdkfd: introduce dummy cache info for property asic This dummy cache info will enable kfd base function support. Signed-off-by: Prike Liang Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_crat.c | 53 ++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c index 8bfdfd062ff6..5e0bad7e0b77 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c @@ -891,6 +891,54 @@ static struct kfd_gpu_cache_info gc_10_3_6_cache_info[] = { }, }; +static struct kfd_gpu_cache_info dummy_cache_info[] = { + { + /* TCP L1 Cache per CU */ + .cache_size = 16, + .cache_level = 1, + .flags = (CRAT_CACHE_FLAGS_ENABLED | + CRAT_CACHE_FLAGS_DATA_CACHE | + CRAT_CACHE_FLAGS_SIMD_CACHE), + .num_cu_shared = 1, + }, + { + /* Scalar L1 Instruction Cache per SQC */ + .cache_size = 32, + .cache_level = 1, + .flags = (CRAT_CACHE_FLAGS_ENABLED | + CRAT_CACHE_FLAGS_INST_CACHE | + CRAT_CACHE_FLAGS_SIMD_CACHE), + .num_cu_shared = 2, + }, + { + /* Scalar L1 Data Cache per SQC */ + .cache_size = 16, + .cache_level = 1, + .flags = (CRAT_CACHE_FLAGS_ENABLED | + CRAT_CACHE_FLAGS_DATA_CACHE | + CRAT_CACHE_FLAGS_SIMD_CACHE), + .num_cu_shared = 2, + }, + { + /* GL1 Data Cache per SA */ + .cache_size = 128, + .cache_level = 1, + .flags = (CRAT_CACHE_FLAGS_ENABLED | + CRAT_CACHE_FLAGS_DATA_CACHE | + CRAT_CACHE_FLAGS_SIMD_CACHE), + .num_cu_shared = 6, + }, + { + /* L2 Data Cache per GPU (Total Tex Cache) */ + .cache_size = 2048, + .cache_level = 2, + .flags = (CRAT_CACHE_FLAGS_ENABLED | + CRAT_CACHE_FLAGS_DATA_CACHE | + CRAT_CACHE_FLAGS_SIMD_CACHE), + .num_cu_shared = 6, + }, +}; + static void kfd_populated_cu_info_cpu(struct kfd_topology_device *dev, struct crat_subtype_computeunit *cu) { @@ -1630,7 +1678,10 @@ static int kfd_fill_gpu_cache_info(struct kfd_dev *kdev, kfd_fill_gpu_cache_info_from_gfx_config(kdev, pcache_info); break; default: - return -EINVAL; + pcache_info = dummy_cache_info; + num_of_cache_types = ARRAY_SIZE(dummy_cache_info); + pr_warn("dummy cache info is used temporarily and real cache info need update later.\n"); + break; } } -- cgit From 693073a04de491c82cd0e1d6bf979192375373c1 Mon Sep 17 00:00:00 2001 From: YuBiao Wang Date: Wed, 19 Oct 2022 11:36:32 +0800 Subject: drm/amdgpu: skip mes self test for gc 11.0.3 in recover Temporary disable mes self teset for gc 11.0.3 during gpu_recovery. Signed-off-by: YuBiao Wang Acked-by: Luben Tuikov Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index e0445e8cc342..5b8362727226 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -5381,7 +5381,7 @@ skip_hw_reset: drm_sched_start(&ring->sched, !tmp_adev->asic_reset_res); } - if (adev->enable_mes) + if (adev->enable_mes && adev->ip_versions[GC_HWIP][0] != IP_VERSION(11, 0, 3)) amdgpu_mes_self_test(tmp_adev); if (!drm_drv_uses_atomic_modeset(adev_to_drm(tmp_adev)) && !job_signaled) { -- cgit From f543d28687480fad06b708bc6e0b0b6ec953b078 Mon Sep 17 00:00:00 2001 From: Prike Liang Date: Fri, 21 Oct 2022 10:04:40 +0800 Subject: drm/amdgpu: disallow gfxoff until GC IP blocks complete s2idle resume In the S2idle suspend/resume phase the gfxoff is keeping functional so some IP blocks will be likely to reinitialize at gfxoff entry and that will result in failing to program GC registers.Therefore, let disallow gfxoff until AMDGPU IPs reinitialized completely. Signed-off-by: Prike Liang Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 5b8362727226..ddaecb2610c9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -3210,6 +3210,15 @@ static int amdgpu_device_ip_resume_phase2(struct amdgpu_device *adev) return r; } adev->ip_blocks[i].status.hw = true; + + if (adev->in_s0ix && adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SMC) { + /* disable gfxoff for IP resume. The gfxoff will be re-enabled in + * amdgpu_device_resume() after IP resume. + */ + amdgpu_gfx_off_ctrl(adev, false); + DRM_DEBUG("will disable gfxoff for re-initializing other blocks\n"); + } + } return 0; @@ -4185,6 +4194,13 @@ int amdgpu_device_resume(struct drm_device *dev, bool fbcon) /* Make sure IB tests flushed */ flush_delayed_work(&adev->delayed_init_work); + if (adev->in_s0ix) { + /* re-enable gfxoff after IP resume. This re-enables gfxoff after + * it was disabled for IP resume in amdgpu_device_ip_resume_phase2(). + */ + amdgpu_gfx_off_ctrl(adev, true); + DRM_DEBUG("will enable gfxoff for the mission mode\n"); + } if (fbcon) drm_fb_helper_set_suspend_unlocked(adev_to_drm(adev)->fb_helper, false); -- cgit From b66fca42c4e5739fa7ce17edd1c4d451b0d3c78d Mon Sep 17 00:00:00 2001 From: Fangzhi Zuo Date: Thu, 20 Oct 2022 11:46:30 -0400 Subject: drm/amd/display: Add UHBR135 and UHBR20 into debugfs Add support to manually force link rate to UHBR135 (0x546) and UHBR20 (0x7d0). Tested-by: Mark Broadworth Reviewed-by: Roman Li Acked-by: Rodrigo Siqueira Signed-off-by: Fangzhi Zuo Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index ee242d9d8b06..0c717d7b12e5 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -299,6 +299,8 @@ static ssize_t dp_link_settings_write(struct file *f, const char __user *buf, case LINK_RATE_HIGH2: case LINK_RATE_HIGH3: case LINK_RATE_UHBR10: + case LINK_RATE_UHBR13_5: + case LINK_RATE_UHBR20: break; default: valid_input = false; -- cgit From bbfbf09d193ac831c40db50ef4b31d11548a9eef Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira Date: Thu, 20 Oct 2022 11:46:31 -0400 Subject: drm/amd/display: Remove FPU guards from the DML folder As part of the programming expectation for using DML functions, DC requires that any DML function invoked outside DML uses: DC_FP_START(); ... dml function ... DC_FP_END(); Additionally, all the DML functions that can be invoked outside the DML folder call the function dc_assert_fp_enabled(), which is responsible for triggering a warning in the case that the DML function was not guarded by the DC_FP_START/END. For this reason, call DC_FP_START/END inside DML is wrong, and this commit removes all of those references. Tested-by: Mark Broadworth Reviewed-by: Nevenko Stupar Reviewed-by: Jun Lei Acked-by: Rodrigo Siqueira Signed-off-by: Rodrigo Siqueira Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c | 2 -- drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c | 17 +---------------- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c index e1e92daba668..d4c0f9cdac8e 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c @@ -520,9 +520,7 @@ void dcn30_fpu_calculate_wm_and_dlg( pipe_idx++; } - DC_FP_START(); dcn20_calculate_dlg_params(dc, context, pipes, pipe_cnt, vlevel); - DC_FP_END(); if (!pstate_en) /* Restore full p-state latency */ diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c index 819de0f11012..d8e68f13c288 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c @@ -1191,9 +1191,7 @@ static void dcn32_full_validate_bw_helper(struct dc *dc, } } else { // Most populate phantom DLG params before programming hardware / timing for phantom pipe - DC_FP_START(); dcn32_helper_populate_phantom_dlg_params(dc, context, pipes, *pipe_cnt); - DC_FP_END(); /* Call validate_apply_pipe_split flags after calling DML getters for * phantom dlg params, or some of the VBA params indicating pipe split @@ -1494,11 +1492,8 @@ bool dcn32_internal_validate_bw(struct dc *dc, dml_log_pipe_params(&context->bw_ctx.dml, pipes, pipe_cnt); - if (!fast_validate) { - DC_FP_START(); + if (!fast_validate) dcn32_full_validate_bw_helper(dc, context, pipes, &vlevel, split, merge, &pipe_cnt); - DC_FP_END(); - } if (fast_validate || (dc->debug.dml_disallow_alternate_prefetch_modes && @@ -2145,9 +2140,7 @@ static int build_synthetic_soc_states(struct clk_bw_params *bw_params, entry.fabricclk_mhz = 0; entry.dram_speed_mts = 0; - DC_FP_START(); insert_entry_into_table_sorted(table, num_entries, &entry); - DC_FP_END(); } // Insert the max DCFCLK @@ -2155,9 +2148,7 @@ static int build_synthetic_soc_states(struct clk_bw_params *bw_params, entry.fabricclk_mhz = 0; entry.dram_speed_mts = 0; - DC_FP_START(); insert_entry_into_table_sorted(table, num_entries, &entry); - DC_FP_END(); // Insert the UCLK DPMS for (i = 0; i < num_uclk_dpms; i++) { @@ -2165,9 +2156,7 @@ static int build_synthetic_soc_states(struct clk_bw_params *bw_params, entry.fabricclk_mhz = 0; entry.dram_speed_mts = bw_params->clk_table.entries[i].memclk_mhz * 16; - DC_FP_START(); insert_entry_into_table_sorted(table, num_entries, &entry); - DC_FP_END(); } // If FCLK is coarse grained, insert individual DPMs. @@ -2177,9 +2166,7 @@ static int build_synthetic_soc_states(struct clk_bw_params *bw_params, entry.fabricclk_mhz = bw_params->clk_table.entries[i].fclk_mhz; entry.dram_speed_mts = 0; - DC_FP_START(); insert_entry_into_table_sorted(table, num_entries, &entry); - DC_FP_END(); } } // If FCLK fine grained, only insert max @@ -2188,9 +2175,7 @@ static int build_synthetic_soc_states(struct clk_bw_params *bw_params, entry.fabricclk_mhz = max_fclk_mhz; entry.dram_speed_mts = 0; - DC_FP_START(); insert_entry_into_table_sorted(table, num_entries, &entry); - DC_FP_END(); } // At this point, the table contains all "points of interest" based on -- cgit From 14e2739c3695734bb4f5a0deca6fff4e10e5ef5d Mon Sep 17 00:00:00 2001 From: Wenjing Liu Date: Thu, 20 Oct 2022 11:46:32 -0400 Subject: drm/amd/display: refactor enable/disable audio stream hw sequence [why] 1. As recommended by hardware team, don't enable APG when stream is not enabled. 2. Move audio stream encoder programming into link_hwss. [how] 1. Merge dp_audio_enable into enable audio stream hw sequence. 2. Move stream encoder programming into link hwss level to unify stream encoder programming interface. Tested-by: Mark Broadworth Reviewed-by: Charlene Liu Acked-by: Rodrigo Siqueira Signed-off-by: Wenjing Liu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 6 +-- drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c | 14 +----- .../amd/display/dc/dce110/dce110_hw_sequencer.c | 50 ++++------------------ drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c | 8 ---- drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.c | 2 - drivers/gpu/drm/amd/display/dc/inc/link_hwss.h | 2 + .../gpu/drm/amd/display/dc/link/link_hwss_dio.c | 35 +++++++++++++++ .../gpu/drm/amd/display/dc/link/link_hwss_dio.h | 2 + .../gpu/drm/amd/display/dc/link/link_hwss_dpia.c | 2 + .../gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.c | 15 +++++++ 10 files changed, 68 insertions(+), 68 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index d7b1ace6328a..24ed057414e1 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -4229,6 +4229,7 @@ static void fpga_dp_hpo_enable_link_and_stream(struct dc_state *state, struct pi link_hwss->ext.set_throttled_vcp_size(pipe_ctx, avg_time_slots_per_mtp); dc->hwss.unblank_stream(pipe_ctx, &stream->link->cur_link_settings); + dc->hwss.enable_audio_stream(pipe_ctx); } void core_link_enable_stream( @@ -4308,10 +4309,7 @@ void core_link_enable_stream( /* Still enable stream features & audio on seamless boot for DP external displays */ if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT) { enable_stream_features(pipe_ctx); - if (pipe_ctx->stream_res.audio != NULL) { - pipe_ctx->stream_res.stream_enc->funcs->dp_audio_enable(pipe_ctx->stream_res.stream_enc); - dc->hwss.enable_audio_stream(pipe_ctx); - } + dc->hwss.enable_audio_stream(pipe_ctx); } #if defined(CONFIG_DRM_AMD_DC_HDCP) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c index 1254d38f1778..bd4cbe02d353 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -7339,19 +7339,7 @@ void dp_retrain_link_dp_test(struct dc_link *link, link->dc->hwss.unblank_stream(&pipes[i], link_setting); - if (pipes[i].stream_res.audio) { - /* notify audio driver for - * audio modes of monitor */ - pipes[i].stream_res.audio->funcs->az_enable( - pipes[i].stream_res.audio); - - /* un-mute audio */ - /* TODO: audio should be per stream rather than - * per link */ - pipes[i].stream_res.stream_enc->funcs-> - audio_mute_control( - pipes[i].stream_res.stream_enc, false); - } + link->dc->hwss.enable_audio_stream(&pipes[i]); } } } diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c index d260eaa1509e..a34bc631be00 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -688,16 +688,6 @@ void dce110_enable_stream(struct pipe_ctx *pipe_ctx) early_control = lane_count; tg->funcs->set_early_control(tg, early_control); - - /* enable audio only within mode set */ - if (pipe_ctx->stream_res.audio != NULL) { - if (dc_is_dp_signal(pipe_ctx->stream->signal)) - pipe_ctx->stream_res.stream_enc->funcs->dp_audio_enable(pipe_ctx->stream_res.stream_enc); - } - - - - } static enum bp_result link_transmitter_control( @@ -1081,12 +1071,14 @@ void dce110_enable_audio_stream(struct pipe_ctx *pipe_ctx) struct dc *dc; struct clk_mgr *clk_mgr; unsigned int i, num_audio = 1; + const struct link_hwss *link_hwss; if (!pipe_ctx->stream) return; dc = pipe_ctx->stream->ctx->dc; clk_mgr = dc->clk_mgr; + link_hwss = get_link_hwss(pipe_ctx->stream->link, &pipe_ctx->link_res); if (pipe_ctx->stream_res.audio && pipe_ctx->stream_res.audio->enabled == true) return; @@ -1103,56 +1095,35 @@ void dce110_enable_audio_stream(struct pipe_ctx *pipe_ctx) if (num_audio >= 1 && clk_mgr->funcs->enable_pme_wa) /*this is the first audio. apply the PME w/a in order to wake AZ from D3*/ clk_mgr->funcs->enable_pme_wa(clk_mgr); - /* un-mute audio */ - /* TODO: audio should be per stream rather than per link */ - if (is_dp_128b_132b_signal(pipe_ctx)) - pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->audio_mute_control( - pipe_ctx->stream_res.hpo_dp_stream_enc, false); - else - pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control( - pipe_ctx->stream_res.stream_enc, false); + + link_hwss->enable_audio_packet(pipe_ctx); + if (pipe_ctx->stream_res.audio) pipe_ctx->stream_res.audio->enabled = true; } - - if (dc_is_dp_signal(pipe_ctx->stream->signal)) - dp_source_sequence_trace(pipe_ctx->stream->link, DPCD_SOURCE_SEQ_AFTER_ENABLE_AUDIO_STREAM); } void dce110_disable_audio_stream(struct pipe_ctx *pipe_ctx) { struct dc *dc; struct clk_mgr *clk_mgr; + const struct link_hwss *link_hwss; if (!pipe_ctx || !pipe_ctx->stream) return; dc = pipe_ctx->stream->ctx->dc; clk_mgr = dc->clk_mgr; + link_hwss = get_link_hwss(pipe_ctx->stream->link, &pipe_ctx->link_res); if (pipe_ctx->stream_res.audio && pipe_ctx->stream_res.audio->enabled == false) return; - if (is_dp_128b_132b_signal(pipe_ctx)) - pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->audio_mute_control( - pipe_ctx->stream_res.hpo_dp_stream_enc, true); - else - pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control( - pipe_ctx->stream_res.stream_enc, true); + link_hwss->disable_audio_packet(pipe_ctx); + if (pipe_ctx->stream_res.audio) { pipe_ctx->stream_res.audio->enabled = false; - if (dc_is_dp_signal(pipe_ctx->stream->signal)) - if (is_dp_128b_132b_signal(pipe_ctx)) - pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_audio_disable( - pipe_ctx->stream_res.hpo_dp_stream_enc); - else - pipe_ctx->stream_res.stream_enc->funcs->dp_audio_disable( - pipe_ctx->stream_res.stream_enc); - else - pipe_ctx->stream_res.stream_enc->funcs->hdmi_audio_disable( - pipe_ctx->stream_res.stream_enc); - if (clk_mgr->funcs->enable_pme_wa) /*this is the first audio. apply the PME w/a in order to wake AZ from D3*/ clk_mgr->funcs->enable_pme_wa(clk_mgr); @@ -1163,9 +1134,6 @@ void dce110_disable_audio_stream(struct pipe_ctx *pipe_ctx) * stream->stream_engine_id); */ } - - if (dc_is_dp_signal(pipe_ctx->stream->signal)) - dp_source_sequence_trace(pipe_ctx->stream->link, DPCD_SOURCE_SEQ_AFTER_DISABLE_AUDIO_STREAM); } void dce110_disable_stream(struct pipe_ctx *pipe_ctx) diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c index a7e0001a8f46..1ac0ed5be605 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c @@ -2601,14 +2601,6 @@ void dcn20_enable_stream(struct pipe_ctx *pipe_ctx) if (dc->hwseq->funcs.set_pixels_per_cycle) dc->hwseq->funcs.set_pixels_per_cycle(pipe_ctx); - - /* enable audio only within mode set */ - if (pipe_ctx->stream_res.audio != NULL) { - if (is_dp_128b_132b_signal(pipe_ctx)) - pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_audio_enable(pipe_ctx->stream_res.hpo_dp_stream_enc); - else if (dc_is_dp_signal(pipe_ctx->stream->signal)) - pipe_ctx->stream_res.stream_enc->funcs->dp_audio_enable(pipe_ctx->stream_res.stream_enc); - } } void dcn20_program_dmdata_engine(struct pipe_ctx *pipe_ctx) diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.c index de5e18c2a3ac..2cec7131a96f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.c @@ -134,8 +134,6 @@ static void apg31_se_audio_setup( /* Disable forced mem power off */ REG_UPDATE(APG_MEM_PWR, APG_MEM_PWR_FORCE, 0); - - apg31_enable(apg); } static void apg31_audio_mute_control( diff --git a/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h b/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h index 89964c980b87..7a2c8bc280d5 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h +++ b/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h @@ -79,6 +79,8 @@ struct link_hwss { void (*disable_link_output)(struct dc_link *link, const struct link_resource *link_res, enum signal_type signal); + void (*enable_audio_packet)(struct pipe_ctx *pipe_ctx); + void (*disable_audio_packet)(struct pipe_ctx *pipe_ctx); }; #endif /* __DC_LINK_HWSS_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.c b/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.c index 4227adbc646a..fcc3ce2b8fbf 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.c @@ -170,11 +170,46 @@ static void update_dio_stream_allocation_table(struct dc_link *link, link_enc->funcs->update_mst_stream_allocation_table(link_enc, table); } +void enable_dio_audio_packet(struct pipe_ctx *pipe_ctx) +{ + if (dc_is_dp_signal(pipe_ctx->stream->signal)) + pipe_ctx->stream_res.stream_enc->funcs->dp_audio_enable( + pipe_ctx->stream_res.stream_enc); + + pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control( + pipe_ctx->stream_res.stream_enc, false); + + if (dc_is_dp_signal(pipe_ctx->stream->signal)) + dp_source_sequence_trace(pipe_ctx->stream->link, + DPCD_SOURCE_SEQ_AFTER_ENABLE_AUDIO_STREAM); +} + +void disable_dio_audio_packet(struct pipe_ctx *pipe_ctx) +{ + pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control( + pipe_ctx->stream_res.stream_enc, true); + + if (pipe_ctx->stream_res.audio) { + if (dc_is_dp_signal(pipe_ctx->stream->signal)) + pipe_ctx->stream_res.stream_enc->funcs->dp_audio_disable( + pipe_ctx->stream_res.stream_enc); + else + pipe_ctx->stream_res.stream_enc->funcs->hdmi_audio_disable( + pipe_ctx->stream_res.stream_enc); + } + + if (dc_is_dp_signal(pipe_ctx->stream->signal)) + dp_source_sequence_trace(pipe_ctx->stream->link, + DPCD_SOURCE_SEQ_AFTER_DISABLE_AUDIO_STREAM); +} + static const struct link_hwss dio_link_hwss = { .setup_stream_encoder = setup_dio_stream_encoder, .reset_stream_encoder = reset_dio_stream_encoder, .setup_stream_attribute = setup_dio_stream_attribute, .disable_link_output = disable_dio_link_output, + .enable_audio_packet = enable_dio_audio_packet, + .disable_audio_packet = disable_dio_audio_packet, .ext = { .set_throttled_vcp_size = set_dio_throttled_vcp_size, .enable_dp_link_output = enable_dio_dp_link_output, diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.h b/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.h index 126d37f847a1..006830376e7d 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.h +++ b/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.h @@ -50,5 +50,7 @@ void set_dio_dp_lane_settings(struct dc_link *link, const struct link_resource *link_res, const struct dc_link_settings *link_settings, const struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]); +void enable_dio_audio_packet(struct pipe_ctx *pipe_ctx); +void disable_dio_audio_packet(struct pipe_ctx *pipe_ctx); #endif /* __LINK_HWSS_DIO_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dpia.c b/drivers/gpu/drm/amd/display/dc/link/link_hwss_dpia.c index 64f7ea6a9aa3..f81949221e0d 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dpia.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_hwss_dpia.c @@ -57,6 +57,8 @@ static const struct link_hwss dpia_link_hwss = { .reset_stream_encoder = reset_dio_stream_encoder, .setup_stream_attribute = setup_dio_stream_attribute, .disable_link_output = disable_dio_link_output, + .enable_audio_packet = enable_dio_audio_packet, + .disable_audio_packet = disable_dio_audio_packet, .ext = { .set_throttled_vcp_size = set_dio_throttled_vcp_size, .enable_dp_link_output = enable_dio_dp_link_output, diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.c b/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.c index 153a88381f2c..668a66832579 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.c @@ -262,11 +262,26 @@ static void update_hpo_dp_stream_allocation_table(struct dc_link *link, table); } +static void enable_hpo_dp_audio_packet(struct pipe_ctx *pipe_ctx) +{ + pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_audio_enable( + pipe_ctx->stream_res.hpo_dp_stream_enc); +} + +static void disable_hpo_dp_audio_packet(struct pipe_ctx *pipe_ctx) +{ + if (pipe_ctx->stream_res.audio) + pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_audio_disable( + pipe_ctx->stream_res.hpo_dp_stream_enc); +} + static const struct link_hwss hpo_dp_link_hwss = { .setup_stream_encoder = setup_hpo_dp_stream_encoder, .reset_stream_encoder = reset_hpo_dp_stream_encoder, .setup_stream_attribute = setup_hpo_dp_stream_attribute, .disable_link_output = disable_hpo_dp_link_output, + .enable_audio_packet = enable_hpo_dp_audio_packet, + .disable_audio_packet = disable_hpo_dp_audio_packet, .ext = { .set_throttled_vcp_size = set_hpo_dp_throttled_vcp_size, .set_hblank_min_symbol_width = set_hpo_dp_hblank_min_symbol_width, -- cgit From c859181cfeacf87336fc385c5665444f0e59eafe Mon Sep 17 00:00:00 2001 From: Wenjing Liu Date: Thu, 20 Oct 2022 11:46:33 -0400 Subject: drm/amd/display: move stream encoder audio setup to link_hwss Unify stream encoder audio setup interface. Tested-by: Mark Broadworth Reviewed-by: Charlene Liu Acked-by: Rodrigo Siqueira Signed-off-by: Wenjing Liu Signed-off-by: Alex Deucher --- .../amd/display/dc/dce110/dce110_hw_sequencer.c | 22 +++++----------------- drivers/gpu/drm/amd/display/dc/inc/link_hwss.h | 3 +++ .../gpu/drm/amd/display/dc/link/link_hwss_dio.c | 17 +++++++++++++++++ .../gpu/drm/amd/display/dc/link/link_hwss_dio.h | 2 ++ .../gpu/drm/amd/display/dc/link/link_hwss_dpia.c | 1 + .../gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.c | 10 ++++++++++ 6 files changed, 38 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c index a34bc631be00..c5380ce70653 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -1455,6 +1455,9 @@ static enum dc_status apply_single_controller_ctx_to_hw( unsigned int event_triggers = 0; struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe; struct dce_hwseq *hws = dc->hwseq; + const struct link_hwss *link_hwss = get_link_hwss( + link, &pipe_ctx->link_res); + if (hws->funcs.disable_stream_gating) { hws->funcs.disable_stream_gating(dc, pipe_ctx); @@ -1465,23 +1468,8 @@ static enum dc_status apply_single_controller_ctx_to_hw( build_audio_output(context, pipe_ctx, &audio_output); - if (dc_is_dp_signal(pipe_ctx->stream->signal)) - if (is_dp_128b_132b_signal(pipe_ctx)) - pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_audio_setup( - pipe_ctx->stream_res.hpo_dp_stream_enc, - pipe_ctx->stream_res.audio->inst, - &pipe_ctx->stream->audio_info); - else - pipe_ctx->stream_res.stream_enc->funcs->dp_audio_setup( - pipe_ctx->stream_res.stream_enc, - pipe_ctx->stream_res.audio->inst, - &pipe_ctx->stream->audio_info); - else - pipe_ctx->stream_res.stream_enc->funcs->hdmi_audio_setup( - pipe_ctx->stream_res.stream_enc, - pipe_ctx->stream_res.audio->inst, - &pipe_ctx->stream->audio_info, - &audio_output.crtc_info); + link_hwss->setup_audio_output(pipe_ctx, &audio_output, + pipe_ctx->stream_res.audio->inst); pipe_ctx->stream_res.audio->funcs->az_configure( pipe_ctx->stream_res.audio, diff --git a/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h b/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h index 7a2c8bc280d5..0f69946cce9f 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h +++ b/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h @@ -38,6 +38,7 @@ struct link_resource; struct pipe_ctx; struct encoder_set_dp_phy_pattern_param; struct link_mst_stream_allocation_table; +struct audio_output; struct link_hwss_ext { /* function pointers below may require to check for NULL if caller @@ -79,6 +80,8 @@ struct link_hwss { void (*disable_link_output)(struct dc_link *link, const struct link_resource *link_res, enum signal_type signal); + void (*setup_audio_output)(struct pipe_ctx *pipe_ctx, + struct audio_output *audio_output, uint32_t audio_inst); void (*enable_audio_packet)(struct pipe_ctx *pipe_ctx); void (*disable_audio_packet)(struct pipe_ctx *pipe_ctx); }; diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.c b/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.c index fcc3ce2b8fbf..33148b753c03 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.c @@ -170,6 +170,22 @@ static void update_dio_stream_allocation_table(struct dc_link *link, link_enc->funcs->update_mst_stream_allocation_table(link_enc, table); } +void setup_dio_audio_output(struct pipe_ctx *pipe_ctx, + struct audio_output *audio_output, uint32_t audio_inst) +{ + if (dc_is_dp_signal(pipe_ctx->stream->signal)) + pipe_ctx->stream_res.stream_enc->funcs->dp_audio_setup( + pipe_ctx->stream_res.stream_enc, + audio_inst, + &pipe_ctx->stream->audio_info); + else + pipe_ctx->stream_res.stream_enc->funcs->hdmi_audio_setup( + pipe_ctx->stream_res.stream_enc, + audio_inst, + &pipe_ctx->stream->audio_info, + &audio_output->crtc_info); +} + void enable_dio_audio_packet(struct pipe_ctx *pipe_ctx) { if (dc_is_dp_signal(pipe_ctx->stream->signal)) @@ -208,6 +224,7 @@ static const struct link_hwss dio_link_hwss = { .reset_stream_encoder = reset_dio_stream_encoder, .setup_stream_attribute = setup_dio_stream_attribute, .disable_link_output = disable_dio_link_output, + .setup_audio_output = setup_dio_audio_output, .enable_audio_packet = enable_dio_audio_packet, .disable_audio_packet = disable_dio_audio_packet, .ext = { diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.h b/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.h index 006830376e7d..9a108c3d7831 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.h +++ b/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.h @@ -50,6 +50,8 @@ void set_dio_dp_lane_settings(struct dc_link *link, const struct link_resource *link_res, const struct dc_link_settings *link_settings, const struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]); +void setup_dio_audio_output(struct pipe_ctx *pipe_ctx, + struct audio_output *audio_output, uint32_t audio_inst); void enable_dio_audio_packet(struct pipe_ctx *pipe_ctx); void disable_dio_audio_packet(struct pipe_ctx *pipe_ctx); diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dpia.c b/drivers/gpu/drm/amd/display/dc/link/link_hwss_dpia.c index f81949221e0d..861f3cd5b356 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dpia.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_hwss_dpia.c @@ -57,6 +57,7 @@ static const struct link_hwss dpia_link_hwss = { .reset_stream_encoder = reset_dio_stream_encoder, .setup_stream_attribute = setup_dio_stream_attribute, .disable_link_output = disable_dio_link_output, + .setup_audio_output = setup_dio_audio_output, .enable_audio_packet = enable_dio_audio_packet, .disable_audio_packet = disable_dio_audio_packet, .ext = { diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.c b/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.c index 668a66832579..2f46e1ac4ce0 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.c @@ -262,6 +262,15 @@ static void update_hpo_dp_stream_allocation_table(struct dc_link *link, table); } +static void setup_hpo_dp_audio_output(struct pipe_ctx *pipe_ctx, + struct audio_output *audio_output, uint32_t audio_inst) +{ + pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_audio_setup( + pipe_ctx->stream_res.hpo_dp_stream_enc, + audio_inst, + &pipe_ctx->stream->audio_info); +} + static void enable_hpo_dp_audio_packet(struct pipe_ctx *pipe_ctx) { pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_audio_enable( @@ -280,6 +289,7 @@ static const struct link_hwss hpo_dp_link_hwss = { .reset_stream_encoder = reset_hpo_dp_stream_encoder, .setup_stream_attribute = setup_hpo_dp_stream_attribute, .disable_link_output = disable_hpo_dp_link_output, + .setup_audio_output = setup_hpo_dp_audio_output, .enable_audio_packet = enable_hpo_dp_audio_packet, .disable_audio_packet = disable_hpo_dp_audio_packet, .ext = { -- cgit From 0094f042f2f88f6e0fea01f0753773a95cc975bd Mon Sep 17 00:00:00 2001 From: Wenjing Liu Date: Thu, 20 Oct 2022 11:46:34 -0400 Subject: drm/amd/display: remove audio mute control in hpo dp VPG doesn't have the ability to mute audio output by sending all 0s in audio SDP. The existing implemention is disabling audio SDP instead. This is same as what dp_audio_enable does. Since it is no longer referenced by any callers, we decided to remove this interface for simplicity. Tested-by: Mark Broadworth Reviewed-by: Charlene Liu Acked-by: Rodrigo Siqueira Signed-off-by: Wenjing Liu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.c | 11 ----------- drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.h | 4 ---- .../drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.c | 9 --------- drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h | 3 --- 4 files changed, 27 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.c index 2cec7131a96f..24e9ff65434d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.c @@ -136,19 +136,8 @@ static void apg31_se_audio_setup( REG_UPDATE(APG_MEM_PWR, APG_MEM_PWR_FORCE, 0); } -static void apg31_audio_mute_control( - struct apg *apg, - bool mute) -{ - if (mute) - apg31_disable(apg); - else - apg31_enable(apg); -} - static struct apg_funcs dcn31_apg_funcs = { .se_audio_setup = apg31_se_audio_setup, - .audio_mute_control = apg31_audio_mute_control, .enable_apg = apg31_enable, .disable_apg = apg31_disable, }; diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.h index 24f568e120d8..1b81f6773c53 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.h +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_apg.h @@ -84,10 +84,6 @@ struct apg_funcs { unsigned int az_inst, struct audio_info *audio_info); - void (*audio_mute_control)( - struct apg *apg, - bool mute); - void (*enable_apg)( struct apg *apg); diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.c index 814f401db3b3..16639bd03adf 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.c @@ -600,14 +600,6 @@ static void dcn31_hpo_dp_stream_enc_map_stream_to_link( } } -static void dcn31_hpo_dp_stream_enc_mute_control( - struct hpo_dp_stream_encoder *enc, - bool mute) -{ - ASSERT(enc->apg); - enc->apg->funcs->audio_mute_control(enc->apg, mute); -} - static void dcn31_hpo_dp_stream_enc_audio_setup( struct hpo_dp_stream_encoder *enc, unsigned int az_inst, @@ -726,7 +718,6 @@ static const struct hpo_dp_stream_encoder_funcs dcn30_str_enc_funcs = { .stop_dp_info_packets = dcn31_hpo_dp_stream_enc_stop_dp_info_packets, .dp_set_dsc_pps_info_packet = dcn31_hpo_dp_stream_enc_set_dsc_pps_info_packet, .map_stream_to_link = dcn31_hpo_dp_stream_enc_map_stream_to_link, - .audio_mute_control = dcn31_hpo_dp_stream_enc_mute_control, .dp_audio_setup = dcn31_hpo_dp_stream_enc_audio_setup, .dp_audio_enable = dcn31_hpo_dp_stream_enc_audio_enable, .dp_audio_disable = dcn31_hpo_dp_stream_enc_audio_disable, diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h index 42afa1952890..6b3e6de374bd 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h @@ -317,9 +317,6 @@ struct hpo_dp_stream_encoder_funcs { uint32_t stream_enc_inst, uint32_t link_enc_inst); - void (*audio_mute_control)( - struct hpo_dp_stream_encoder *enc, bool mute); - void (*dp_audio_setup)( struct hpo_dp_stream_encoder *enc, unsigned int az_inst, -- cgit From 174fc82410a8c75d3937320658fca5a240ca8176 Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin Date: Thu, 20 Oct 2022 11:46:35 -0400 Subject: drm/amd/display: correctly populate dcn315 clock table Fix incorrect pstate read order as well as min and max state logic. Tested-by: Mark Broadworth Reviewed-by: Charlene Liu Acked-by: Rodrigo Siqueira Signed-off-by: Dmytro Laktyushkin Signed-off-by: Alex Deucher --- .../amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c | 71 +++++++--------------- 1 file changed, 23 insertions(+), 48 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c index 893991a0eb97..07edd9777edf 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c @@ -458,19 +458,6 @@ static void dcn315_get_dpm_table_from_smu(struct clk_mgr_internal *clk_mgr, dcn315_smu_transfer_dpm_table_smu_2_dram(clk_mgr); } -static uint32_t find_max_clk_value(const uint32_t clocks[], uint32_t num_clocks) -{ - uint32_t max = 0; - int i; - - for (i = 0; i < num_clocks; ++i) { - if (clocks[i] > max) - max = clocks[i]; - } - - return max; -} - static void dcn315_clk_mgr_helper_populate_bw_params( struct clk_mgr_internal *clk_mgr, struct integrated_info *bios_info, @@ -478,29 +465,21 @@ static void dcn315_clk_mgr_helper_populate_bw_params( { int i; struct clk_bw_params *bw_params = clk_mgr->base.bw_params; - uint32_t max_pstate = 0, max_fclk = 0, min_pstate = 0; + uint32_t max_pstate = clock_table->NumDfPstatesEnabled - 1; struct clk_limit_table_entry def_max = bw_params->clk_table.entries[bw_params->clk_table.num_entries - 1]; - /* Find highest fclk pstate */ - for (i = 0; i < clock_table->NumDfPstatesEnabled; i++) { - if (clock_table->DfPstateTable[i].FClk > max_fclk) { - max_fclk = clock_table->DfPstateTable[i].FClk; - max_pstate = i; - } - } - /* For 315 we want to base clock table on dcfclk, need at least one entry regardless of pmfw table */ for (i = 0; i < clock_table->NumDcfClkLevelsEnabled; i++) { int j; - uint32_t min_fclk = clock_table->DfPstateTable[0].FClk; - for (j = 1; j < clock_table->NumDfPstatesEnabled; j++) { - if (clock_table->DfPstateTable[j].Voltage <= clock_table->SocVoltage[i] - && clock_table->DfPstateTable[j].FClk < min_fclk) { - min_fclk = clock_table->DfPstateTable[j].FClk; - min_pstate = j; - } + /* DF table is sorted with clocks decreasing */ + for (j = clock_table->NumDfPstatesEnabled - 2; j >= 0; j--) { + if (clock_table->DfPstateTable[j].Voltage <= clock_table->SocVoltage[i]) + max_pstate = j; } + /* Max DCFCLK should match up with max pstate */ + if (i == clock_table->NumDcfClkLevelsEnabled - 1) + max_pstate = 0; /* First search defaults for the clocks we don't read using closest lower or equal default dcfclk */ for (j = bw_params->clk_table.num_entries - 1; j > 0; j--) @@ -511,9 +490,9 @@ static void dcn315_clk_mgr_helper_populate_bw_params( bw_params->clk_table.entries[i].dtbclk_mhz = bw_params->clk_table.entries[j].dtbclk_mhz; /* Now update clocks we do read */ - bw_params->clk_table.entries[i].fclk_mhz = min_fclk; - bw_params->clk_table.entries[i].memclk_mhz = clock_table->DfPstateTable[min_pstate].MemClk; - bw_params->clk_table.entries[i].voltage = clock_table->DfPstateTable[min_pstate].Voltage; + bw_params->clk_table.entries[i].fclk_mhz = clock_table->DfPstateTable[max_pstate].FClk; + bw_params->clk_table.entries[i].memclk_mhz = clock_table->DfPstateTable[max_pstate].MemClk; + bw_params->clk_table.entries[i].voltage = clock_table->SocVoltage[i]; bw_params->clk_table.entries[i].dcfclk_mhz = clock_table->DcfClocks[i]; bw_params->clk_table.entries[i].socclk_mhz = clock_table->SocClocks[i]; bw_params->clk_table.entries[i].dispclk_mhz = clock_table->DispClocks[i]; @@ -521,25 +500,16 @@ static void dcn315_clk_mgr_helper_populate_bw_params( bw_params->clk_table.entries[i].wck_ratio = 1; } - /* Make sure to include at least one entry and highest pstate */ - if (max_pstate != min_pstate || i == 0) { - bw_params->clk_table.entries[i].fclk_mhz = max_fclk; - bw_params->clk_table.entries[i].memclk_mhz = clock_table->DfPstateTable[max_pstate].MemClk; - bw_params->clk_table.entries[i].voltage = clock_table->DfPstateTable[max_pstate].Voltage; - bw_params->clk_table.entries[i].dcfclk_mhz = find_max_clk_value(clock_table->DcfClocks, NUM_DCFCLK_DPM_LEVELS); + /* Make sure to include at least one entry */ + if (i == 0) { + bw_params->clk_table.entries[i].fclk_mhz = clock_table->DfPstateTable[0].FClk; + bw_params->clk_table.entries[i].memclk_mhz = clock_table->DfPstateTable[0].MemClk; + bw_params->clk_table.entries[i].voltage = clock_table->DfPstateTable[0].Voltage; + bw_params->clk_table.entries[i].dcfclk_mhz = clock_table->DcfClocks[0]; bw_params->clk_table.entries[i].wck_ratio = 1; i++; } - bw_params->clk_table.num_entries = i--; - - /* Make sure all highest clocks are included*/ - bw_params->clk_table.entries[i].socclk_mhz = find_max_clk_value(clock_table->SocClocks, NUM_SOCCLK_DPM_LEVELS); - bw_params->clk_table.entries[i].dispclk_mhz = find_max_clk_value(clock_table->DispClocks, NUM_DISPCLK_DPM_LEVELS); - bw_params->clk_table.entries[i].dppclk_mhz = find_max_clk_value(clock_table->DppClocks, NUM_DPPCLK_DPM_LEVELS); - ASSERT(clock_table->DcfClocks[i] == find_max_clk_value(clock_table->DcfClocks, NUM_DCFCLK_DPM_LEVELS)); - bw_params->clk_table.entries[i].phyclk_mhz = def_max.phyclk_mhz; - bw_params->clk_table.entries[i].phyclk_d18_mhz = def_max.phyclk_d18_mhz; - bw_params->clk_table.entries[i].dtbclk_mhz = def_max.dtbclk_mhz; + bw_params->clk_table.num_entries = i; /* Set any 0 clocks to max default setting. Not an issue for * power since we aren't doing switching in such case anyway @@ -565,6 +535,11 @@ static void dcn315_clk_mgr_helper_populate_bw_params( if (!bw_params->clk_table.entries[i].dtbclk_mhz) bw_params->clk_table.entries[i].dtbclk_mhz = def_max.dtbclk_mhz; } + + /* Make sure all highest default clocks are included*/ + ASSERT(bw_params->clk_table.entries[i-1].phyclk_mhz == def_max.phyclk_mhz); + ASSERT(bw_params->clk_table.entries[i-1].phyclk_d18_mhz == def_max.phyclk_d18_mhz); + ASSERT(bw_params->clk_table.entries[i-1].dtbclk_mhz == def_max.dtbclk_mhz); ASSERT(bw_params->clk_table.entries[i-1].dcfclk_mhz); bw_params->vram_type = bios_info->memory_type; bw_params->num_channels = bios_info->ma_channel_number; -- cgit From bd829d5707730072fecc3267016a675a4789905b Mon Sep 17 00:00:00 2001 From: Ian Chen Date: Thu, 20 Oct 2022 11:46:36 -0400 Subject: drm/amd/display: Refactor eDP PSR codes We split out PSR config from "global" to "per-panel" config settings. Tested-by: Mark Broadworth Reviewed-by: Robin Chen Acked-by: Rodrigo Siqueira Signed-off-by: Ian Chen Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc.h | 1 - drivers/gpu/drm/amd/display/dc/dc_link.h | 14 +++++++++++--- drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c | 5 ++++- drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c | 15 +++++++++++++-- drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c | 14 +++++++++++++- drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c | 13 ++++++++++++- drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c | 4 ++++ drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c | 4 ++++ drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c | 4 ++++ drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c | 4 ++++ drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c | 2 +- 11 files changed, 70 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index bf938cda379a..e4e41f2e5054 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -764,7 +764,6 @@ struct dc_debug_options { bool disable_mem_low_power; bool pstate_enabled; bool disable_dmcu; - bool disable_psr; bool force_abm_enable; bool disable_stereo_support; bool vsr_support; diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h index caf0c7af2d0b..17f080f8af6c 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_link.h +++ b/drivers/gpu/drm/amd/display/dc/dc_link.h @@ -117,7 +117,7 @@ struct psr_settings { * Add a struct dc_panel_config under dc_link */ struct dc_panel_config { - // extra panel power sequence parameters + /* extra panel power sequence parameters */ struct pps { unsigned int extra_t3_ms; unsigned int extra_t7_ms; @@ -127,13 +127,21 @@ struct dc_panel_config { unsigned int extra_t12_ms; unsigned int extra_post_OUI_ms; } pps; - // ABM + /* PSR */ + struct psr { + bool disable_psr; + bool disallow_psrsu; + bool rc_disable; + bool rc_allow_static_screen; + bool rc_allow_fullscreen_VPB; + } psr; + /* ABM */ struct varib { unsigned int varibright_feature_enable; unsigned int def_varibright_level; unsigned int abm_config_setting; } varib; - // edp DSC + /* edp DSC */ struct dsc { bool disable_dsc_edp; unsigned int force_dsc_edp_policy; diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c index 887081472c0d..ce6c70e25703 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c @@ -671,12 +671,15 @@ static const struct dc_debug_options debug_defaults_diags = { .disable_pplib_wm_range = true, .disable_stutter = true, .disable_48mhz_pwrdwn = true, - .disable_psr = true, .enable_tri_buf = true, .use_max_lb = true }; static const struct dc_panel_config panel_config_defaults = { + .psr = { + .disable_psr = false, + .disallow_psrsu = false, + }, .ilr = { .optimize_edp_link_rate = true, }, diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c index 020f512e9690..af4fe695535e 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c @@ -723,7 +723,6 @@ static const struct dc_debug_options debug_defaults_drv = { .underflow_assert_delay_us = 0xFFFFFFFF, .dwb_fi_phase = -1, // -1 = disable, .dmub_command_table = true, - .disable_psr = false, .use_max_lb = true, .exit_idle_opt_for_cursor_updates = true }; @@ -742,11 +741,17 @@ static const struct dc_debug_options debug_defaults_diags = { .scl_reset_length10 = true, .dwb_fi_phase = -1, // -1 = disable .dmub_command_table = true, - .disable_psr = true, .enable_tri_buf = true, .use_max_lb = true }; +static const struct dc_panel_config panel_config_defaults = { + .psr = { + .disable_psr = false, + .disallow_psrsu = false, + }, +}; + static void dcn30_dpp_destroy(struct dpp **dpp) { kfree(TO_DCN20_DPP(*dpp)); @@ -2212,6 +2217,11 @@ void dcn30_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params } } +static void dcn30_get_panel_config_defaults(struct dc_panel_config *panel_config) +{ + *panel_config = panel_config_defaults; +} + static const struct resource_funcs dcn30_res_pool_funcs = { .destroy = dcn30_destroy_resource_pool, .link_enc_create = dcn30_link_encoder_create, @@ -2231,6 +2241,7 @@ static const struct resource_funcs dcn30_res_pool_funcs = { .release_post_bldn_3dlut = dcn30_release_post_bldn_3dlut, .update_bw_bounding_box = dcn30_update_bw_bounding_box, .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, + .get_panel_config_defaults = dcn30_get_panel_config_defaults, }; #define CTX ctx diff --git a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c b/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c index b925b6ddde5a..d3945876aced 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c @@ -112,10 +112,16 @@ static const struct dc_debug_options debug_defaults_diags = { .dwb_fi_phase = -1, // -1 = disable .dmub_command_table = true, .enable_tri_buf = true, - .disable_psr = true, .use_max_lb = true }; +static const struct dc_panel_config panel_config_defaults = { + .psr = { + .disable_psr = false, + .disallow_psrsu = false, + }, +}; + enum dcn302_clk_src_array_id { DCN302_CLK_SRC_PLL0, DCN302_CLK_SRC_PLL1, @@ -1132,6 +1138,11 @@ void dcn302_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_param DC_FP_END(); } +static void dcn302_get_panel_config_defaults(struct dc_panel_config *panel_config) +{ + *panel_config = panel_config_defaults; +} + static struct resource_funcs dcn302_res_pool_funcs = { .destroy = dcn302_destroy_resource_pool, .link_enc_create = dcn302_link_encoder_create, @@ -1151,6 +1162,7 @@ static struct resource_funcs dcn302_res_pool_funcs = { .release_post_bldn_3dlut = dcn30_release_post_bldn_3dlut, .update_bw_bounding_box = dcn302_update_bw_bounding_box, .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, + .get_panel_config_defaults = dcn302_get_panel_config_defaults, }; static struct dc_cap_funcs cap_funcs = { diff --git a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c index 527d5c902878..7e7f18bef098 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c @@ -96,7 +96,13 @@ static const struct dc_debug_options debug_defaults_diags = { .dwb_fi_phase = -1, // -1 = disable .dmub_command_table = true, .enable_tri_buf = true, - .disable_psr = true, +}; + +static const struct dc_panel_config panel_config_defaults = { + .psr = { + .disable_psr = false, + .disallow_psrsu = false, + }, }; enum dcn303_clk_src_array_id { @@ -1055,6 +1061,10 @@ static void dcn303_destroy_resource_pool(struct resource_pool **pool) *pool = NULL; } +static void dcn303_get_panel_config_defaults(struct dc_panel_config *panel_config) +{ + *panel_config = panel_config_defaults; +} void dcn303_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) { @@ -1082,6 +1092,7 @@ static struct resource_funcs dcn303_res_pool_funcs = { .release_post_bldn_3dlut = dcn30_release_post_bldn_3dlut, .update_bw_bounding_box = dcn303_update_bw_bounding_box, .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, + .get_panel_config_defaults = dcn303_get_panel_config_defaults, }; static struct dc_cap_funcs cap_funcs = { diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c index fddc21a5a04c..8729d6305996 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c @@ -911,6 +911,10 @@ static const struct dc_debug_options debug_defaults_diags = { }; static const struct dc_panel_config panel_config_defaults = { + .psr = { + .disable_psr = false, + .disallow_psrsu = false, + }, .ilr = { .optimize_edp_link_rate = true, }, diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c index d0ad72caead2..92eb56873eee 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c @@ -937,6 +937,10 @@ static const struct dc_debug_options debug_defaults_diags = { }; static const struct dc_panel_config panel_config_defaults = { + .psr = { + .disable_psr = false, + .disallow_psrsu = false, + }, .ilr = { .optimize_edp_link_rate = true, }, diff --git a/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c b/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c index 58746c437554..31cbc5762eab 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c @@ -907,6 +907,10 @@ static const struct dc_debug_options debug_defaults_diags = { }; static const struct dc_panel_config panel_config_defaults = { + .psr = { + .disable_psr = false, + .disallow_psrsu = false, + }, .ilr = { .optimize_edp_link_rate = true, }, diff --git a/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c b/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c index 6b40a11ac83a..af3eddc0cf32 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c @@ -906,6 +906,10 @@ static const struct dc_debug_options debug_defaults_diags = { }; static const struct dc_panel_config panel_config_defaults = { + .psr = { + .disable_psr = false, + .disallow_psrsu = false, + }, .ilr = { .optimize_edp_link_rate = true, }, diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c index d680f1c5b69f..ec2eae99b892 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c @@ -989,7 +989,7 @@ static enum dcn_zstate_support_state decide_zstate_support(struct dc *dc, struc if (context->bw_ctx.dml.vba.StutterPeriod > 5000.0 || optimized_min_dst_y_next_start_us > 5000) return DCN_ZSTATE_SUPPORT_ALLOW; - else if (link->psr_settings.psr_version == DC_PSR_VERSION_1 && !dc->debug.disable_psr) + else if (link->psr_settings.psr_version == DC_PSR_VERSION_1 && !link->panel_config.psr.disable_psr) return DCN_ZSTATE_SUPPORT_ALLOW_Z10_ONLY; else return DCN_ZSTATE_SUPPORT_DISALLOW; -- cgit From 6be153dc8c88409e63309bcec300b03cd7bce9a7 Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira Date: Thu, 20 Oct 2022 11:46:37 -0400 Subject: drm/amd/display: Convert documentation to a kernel-doc The dc_dmub_srv file has a lot of documentation associated with SubVP that could be converted to a kernel-doc. This commit just changes the comment style to a kernel-doc. Tested-by: Mark Broadworth Reviewed-by: Aurabindo Pillai Acked-by: Rodrigo Siqueira Signed-off-by: Rodrigo Siqueira Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c | 124 +++++++++++---------------- 1 file changed, 48 insertions(+), 76 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c index 0541e87e4f38..774e06936661 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c @@ -423,25 +423,20 @@ void dc_dmub_srv_get_visual_confirm_color_cmd(struct dc *dc, struct pipe_ctx *pi #ifdef CONFIG_DRM_AMD_DC_DCN /** - * *********************************************************************************************** - * populate_subvp_cmd_drr_info: Helper to populate DRR pipe info for the DMCUB subvp command + * populate_subvp_cmd_drr_info - Helper to populate DRR pipe info for the DMCUB subvp command * - * Populate the DMCUB SubVP command with DRR pipe info. All the information required for calculating - * the SubVP + DRR microschedule is populated here. + * @dc: [in] current dc state + * @subvp_pipe: [in] pipe_ctx for the SubVP pipe + * @vblank_pipe: [in] pipe_ctx for the DRR pipe + * @pipe_data: [in] Pipe data which stores the VBLANK/DRR info + * + * Populate the DMCUB SubVP command with DRR pipe info. All the information + * required for calculating the SubVP + DRR microschedule is populated here. * * High level algorithm: * 1. Get timing for SubVP pipe, phantom pipe, and DRR pipe * 2. Calculate the min and max vtotal which supports SubVP + DRR microschedule * 3. Populate the drr_info with the min and max supported vtotal values - * - * @param [in] dc: current dc state - * @param [in] subvp_pipe: pipe_ctx for the SubVP pipe - * @param [in] vblank_pipe: pipe_ctx for the DRR pipe - * @param [in] pipe_data: Pipe data which stores the VBLANK/DRR info - * - * @return: void - * - * *********************************************************************************************** */ static void populate_subvp_cmd_drr_info(struct dc *dc, struct pipe_ctx *subvp_pipe, @@ -493,22 +488,18 @@ static void populate_subvp_cmd_drr_info(struct dc *dc, } /** - * *********************************************************************************************** - * populate_subvp_cmd_vblank_pipe_info: Helper to populate VBLANK pipe info for the DMUB subvp command + * populate_subvp_cmd_vblank_pipe_info - Helper to populate VBLANK pipe info for the DMUB subvp command * - * Populate the DMCUB SubVP command with VBLANK pipe info. All the information required to calculate - * the microschedule for SubVP + VBLANK case is stored in the pipe_data (subvp_data and vblank_data). - * Also check if the VBLANK pipe is a DRR display -- if it is make a call to populate drr_info. + * @dc: [in] current dc state + * @context: [in] new dc state + * @cmd: [in] DMUB cmd to be populated with SubVP info + * @vblank_pipe: [in] pipe_ctx for the VBLANK pipe + * @cmd_pipe_index: [in] index for the pipe array in DMCUB SubVP cmd * - * @param [in] dc: current dc state - * @param [in] context: new dc state - * @param [in] cmd: DMUB cmd to be populated with SubVP info - * @param [in] vblank_pipe: pipe_ctx for the VBLANK pipe - * @param [in] cmd_pipe_index: index for the pipe array in DMCUB SubVP cmd - * - * @return: void - * - * *********************************************************************************************** + * Populate the DMCUB SubVP command with VBLANK pipe info. All the information + * required to calculate the microschedule for SubVP + VBLANK case is stored in + * the pipe_data (subvp_data and vblank_data). Also check if the VBLANK pipe + * is a DRR display -- if it is make a call to populate drr_info. */ static void populate_subvp_cmd_vblank_pipe_info(struct dc *dc, struct dc_state *context, @@ -551,22 +542,18 @@ static void populate_subvp_cmd_vblank_pipe_info(struct dc *dc, } /** - * *********************************************************************************************** - * update_subvp_prefetch_end_to_mall_start: Helper for SubVP + SubVP case - * - * For SubVP + SubVP, we use a single vertical interrupt to start the microschedule for both - * SubVP pipes. In order for this to work correctly, the MALL REGION of both SubVP pipes must - * start at the same time. This function lengthens the prefetch end to mall start delay of the - * SubVP pipe that has the shorter prefetch so that both MALL REGION's will start at the same time. - * - * @param [in] dc: current dc state - * @param [in] context: new dc state - * @param [in] cmd: DMUB cmd to be populated with SubVP info - * @param [in] subvp_pipes: Array of SubVP pipes (should always be length 2) + * update_subvp_prefetch_end_to_mall_start - Helper for SubVP + SubVP case * - * @return: void + * @dc: [in] current dc state + * @context: [in] new dc state + * @cmd: [in] DMUB cmd to be populated with SubVP info + * @subvp_pipes: [in] Array of SubVP pipes (should always be length 2) * - * *********************************************************************************************** + * For SubVP + SubVP, we use a single vertical interrupt to start the + * microschedule for both SubVP pipes. In order for this to work correctly, the + * MALL REGION of both SubVP pipes must start at the same time. This function + * lengthens the prefetch end to mall start delay of the SubVP pipe that has + * the shorter prefetch so that both MALL REGION's will start at the same time. */ static void update_subvp_prefetch_end_to_mall_start(struct dc *dc, struct dc_state *context, @@ -608,22 +595,17 @@ static void update_subvp_prefetch_end_to_mall_start(struct dc *dc, } /** - * *************************************************************************************** - * setup_subvp_dmub_command: Helper to populate the SubVP pipe info for the DMUB subvp command + * setup_subvp_dmub_command - Helper to populate the SubVP pipe info for the DMUB subvp command * - * Populate the DMCUB SubVP command with SubVP pipe info. All the information required to - * calculate the microschedule for the SubVP pipe is stored in the pipe_data of the DMCUB - * SubVP command. + * @dc: [in] current dc state + * @context: [in] new dc state + * @cmd: [in] DMUB cmd to be populated with SubVP info + * @subvp_pipe: [in] pipe_ctx for the SubVP pipe + * @cmd_pipe_index: [in] index for the pipe array in DMCUB SubVP cmd * - * @param [in] dc: current dc state - * @param [in] context: new dc state - * @param [in] cmd: DMUB cmd to be populated with SubVP info - * @param [in] subvp_pipe: pipe_ctx for the SubVP pipe - * @param [in] cmd_pipe_index: index for the pipe array in DMCUB SubVP cmd - * - * @return: void - * - * *************************************************************************************** + * Populate the DMCUB SubVP command with SubVP pipe info. All the information + * required to calculate the microschedule for the SubVP pipe is stored in the + * pipe_data of the DMCUB SubVP command. */ static void populate_subvp_cmd_pipe_info(struct dc *dc, struct dc_state *context, @@ -703,19 +685,14 @@ static void populate_subvp_cmd_pipe_info(struct dc *dc, } /** - * *************************************************************************************** - * dc_dmub_setup_subvp_dmub_command: Populate the DMCUB SubVP command - * - * This function loops through each pipe and populates the DMUB - * SubVP CMD info based on the pipe (e.g. SubVP, VBLANK). - * - * @param [in] dc: current dc state - * @param [in] context: new dc state - * @param [in] cmd: DMUB cmd to be populated with SubVP info + * dc_dmub_setup_subvp_dmub_command - Populate the DMCUB SubVP command * - * @return: void + * @dc: [in] current dc state + * @context: [in] new dc state + * @cmd: [in] DMUB cmd to be populated with SubVP info * - * *************************************************************************************** + * This function loops through each pipe and populates the DMUB SubVP CMD info + * based on the pipe (e.g. SubVP, VBLANK). */ void dc_dmub_setup_subvp_dmub_command(struct dc *dc, struct dc_state *context, @@ -962,19 +939,14 @@ static void dc_build_cursor_attribute_update_payload1( } /** - * *************************************************************************************** - * dc_send_update_cursor_info_to_dmu: Populate the DMCUB Cursor update info command + * dc_send_update_cursor_info_to_dmu - Populate the DMCUB Cursor update info command * - * This function would store the cursor related information and pass it into dmub + * @pCtx: [in] pipe context + * @pipe_idx: [in] pipe index * - * @param [in] pCtx: pipe context - * @param [in] pipe_idx: pipe index - * - * @return: void - * - * *************************************************************************************** + * This function would store the cursor related information and pass it into + * dmub */ - void dc_send_update_cursor_info_to_dmu( struct pipe_ctx *pCtx, uint8_t pipe_idx) { -- cgit From f1943a51f0f9ce732e344fffb576b54f3e230a4d Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira Date: Thu, 20 Oct 2022 11:46:38 -0400 Subject: drm/amd/display: Add events log to trace OPTC lock and unlock As an attempt to offer more DCN debug tools for cases where the OPTC can hang, this commit introduces a trace event responsible for showing OPTC status when it requests lock and unlock. Tested-by: Mark Broadworth Reviewed-by: Aurabindo Pillai Acked-by: Rodrigo Siqueira Signed-off-by: Rodrigo Siqueira Signed-off-by: Alex Deucher --- .../drm/amd/display/amdgpu_dm/amdgpu_dm_trace.h | 64 ++++++++++++++++++++++ drivers/gpu/drm/amd/display/dc/dc_trace.h | 2 + drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c | 5 ++ drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c | 9 +++ 4 files changed, 80 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_trace.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_trace.h index d3bc9dc21771..0f580ea37576 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_trace.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_trace.h @@ -37,6 +37,7 @@ #include #include #include +#include "dcn10/dcn10_optc.h" #include "dc/inc/core_types.h" @@ -662,6 +663,69 @@ TRACE_EVENT(dcn_fpu, ) ); +TRACE_EVENT(dcn_optc_lock_unlock_state, + TP_PROTO(const struct optc *optc_state, int instance, bool lock, const char *function, const int line), + TP_ARGS(optc_state, instance, lock, function, line), + + TP_STRUCT__entry( + __field(const char *, function) + __field(int, instance) + __field(bool, lock) + __field(int, line) + __field(int, opp_count) + __field(int, max_h_total) + __field(int, max_v_total) + __field(int, min_h_blank) + __field(int, min_h_sync_width) + __field(int, min_v_sync_width) + __field(int, min_v_blank) + __field(int, min_v_blank_interlace) + __field(int, vstartup_start) + __field(int, vupdate_offset) + __field(int, vupdate_width) + __field(int, vready_offset) + ), + TP_fast_assign( + __entry->function = function; + __entry->instance = instance; + __entry->lock = lock; + __entry->line = line; + __entry->opp_count = optc_state->opp_count; + __entry->max_h_total = optc_state->max_h_total; + __entry->max_v_total = optc_state->max_v_total; + __entry->min_h_blank = optc_state->min_h_blank; + __entry->min_h_sync_width = optc_state->min_h_sync_width; + __entry->min_v_sync_width = optc_state->min_v_sync_width; + __entry->min_v_blank = optc_state->min_v_blank; + __entry->min_v_blank_interlace = optc_state->min_v_blank_interlace; + __entry->vstartup_start = optc_state->vstartup_start; + __entry->vupdate_offset = optc_state->vupdate_offset; + __entry->vupdate_width = optc_state->vupdate_width; + __entry->vready_offset = optc_state->vupdate_offset; + ), + TP_printk("%s: %s()+%d: optc_instance=%d opp_count=%d max_h_total=%d max_v_total=%d " + "min_h_blank=%d min_h_sync_width=%d min_v_sync_width=%d min_v_blank=%d " + "min_v_blank_interlace=%d vstartup_start=%d vupdate_offset=%d vupdate_width=%d " + "vready_offset=%d", + __entry->lock ? "Lock" : "Unlock", + __entry->function, + __entry->line, + __entry->instance, + __entry->opp_count, + __entry->max_h_total, + __entry->max_v_total, + __entry->min_h_blank, + __entry->min_h_sync_width, + __entry->min_v_sync_width, + __entry->min_v_blank, + __entry->min_v_blank_interlace, + __entry->vstartup_start, + __entry->vupdate_offset, + __entry->vupdate_width, + __entry->vready_offset + ) +); + #endif /* _AMDGPU_DM_TRACE_H_ */ #undef TRACE_INCLUDE_PATH diff --git a/drivers/gpu/drm/amd/display/dc/dc_trace.h b/drivers/gpu/drm/amd/display/dc/dc_trace.h index c711797e5c9e..bbec308a3a5e 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_trace.h +++ b/drivers/gpu/drm/amd/display/dc/dc_trace.h @@ -40,3 +40,5 @@ #define TRACE_DCN_FPU(begin, function, line, ref_count) \ trace_dcn_fpu(begin, function, line, ref_count) +#define TRACE_OPTC_LOCK_UNLOCK_STATE(optc, inst, lock) \ + trace_dcn_optc_lock_unlock_state(optc, inst, lock, __func__, __LINE__) diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c index 33d780218790..c9e53dc49c92 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c @@ -27,6 +27,7 @@ #include "reg_helper.h" #include "dcn10_optc.h" #include "dc.h" +#include "dc_trace.h" #define REG(reg)\ optc1->tg_regs->reg @@ -657,6 +658,8 @@ void optc1_lock(struct timing_generator *optc) REG_WAIT(OTG_MASTER_UPDATE_LOCK, UPDATE_LOCK_STATUS, 1, 1, 10); + + TRACE_OPTC_LOCK_UNLOCK_STATE(optc1, optc->inst, true); } void optc1_unlock(struct timing_generator *optc) @@ -665,6 +668,8 @@ void optc1_unlock(struct timing_generator *optc) REG_SET(OTG_MASTER_UPDATE_LOCK, 0, OTG_MASTER_UPDATE_LOCK, 0); + + TRACE_OPTC_LOCK_UNLOCK_STATE(optc1, optc->inst, false); } void optc1_get_position(struct timing_generator *optc, diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c index 892d3c4d01a1..867d60151aeb 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c @@ -30,6 +30,7 @@ #include "dc_dmub_srv.h" #include "dml/dcn30/dcn30_fpu.h" +#include "dc_trace.h" #define REG(reg)\ optc1->tg_regs->reg @@ -58,6 +59,8 @@ void optc3_triplebuffer_lock(struct timing_generator *optc) REG_WAIT(OTG_MASTER_UPDATE_LOCK, UPDATE_LOCK_STATUS, 1, 1, 10); + + TRACE_OPTC_LOCK_UNLOCK_STATE(optc1, optc->inst, true); } void optc3_lock_doublebuffer_enable(struct timing_generator *optc) @@ -93,6 +96,8 @@ void optc3_lock_doublebuffer_enable(struct timing_generator *optc) MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_START_OFFSET, 0, MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_END_OFFSET, 100, OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, 1); + + TRACE_OPTC_LOCK_UNLOCK_STATE(optc1, optc->inst, true); } void optc3_lock_doublebuffer_disable(struct timing_generator *optc) @@ -108,6 +113,8 @@ void optc3_lock_doublebuffer_disable(struct timing_generator *optc) REG_UPDATE(OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, 0); REG_UPDATE(OTG_GLOBAL_CONTROL0, MASTER_UPDATE_LOCK_DB_EN, 0); + + TRACE_OPTC_LOCK_UNLOCK_STATE(optc1, optc->inst, true); } void optc3_lock(struct timing_generator *optc) @@ -122,6 +129,8 @@ void optc3_lock(struct timing_generator *optc) REG_WAIT(OTG_MASTER_UPDATE_LOCK, UPDATE_LOCK_STATUS, 1, 1, 10); + + TRACE_OPTC_LOCK_UNLOCK_STATE(optc1, optc->inst, true); } void optc3_set_out_mux(struct timing_generator *optc, enum otg_out_mux_dest dest) -- cgit From b473bd5fc333ab02479444dd4a51be5f5e324d97 Mon Sep 17 00:00:00 2001 From: Lewis Huang Date: Thu, 20 Oct 2022 11:46:39 -0400 Subject: drm/amd/display: refine wake up aux in retrieve link caps [Why] Read set_power_state dpcd after HPD cause USB4 CTS 4.2.1.1 [How] Read LTTPR caps first. If aux channel not ready, wake up aux channel. If wake up aux channel return pass, retrieve lttpr caps again. If wake up aux channel return false, register a detection retry timer. Tested-by: Mark Broadworth Reviewed-by: Wenjing Liu Acked-by: Rodrigo Siqueira Signed-off-by: Lewis Huang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c | 148 ++++++----------------- drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h | 2 +- 2 files changed, 41 insertions(+), 109 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c index bd4cbe02d353..420119efcf5f 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -5031,7 +5031,7 @@ static bool dpcd_read_sink_ext_caps(struct dc_link *link) return true; } -bool dp_retrieve_lttpr_cap(struct dc_link *link) +enum dc_status dp_retrieve_lttpr_cap(struct dc_link *link) { uint8_t lttpr_dpcd_data[8]; enum dc_status status = DC_ERROR_UNEXPECTED; @@ -5099,7 +5099,7 @@ bool dp_retrieve_lttpr_cap(struct dc_link *link) CONN_DATA_DETECT(link, lttpr_dpcd_data, sizeof(lttpr_dpcd_data), "LTTPR Caps: "); DC_LOG_DC("is_lttpr_present = %d\n", is_lttpr_present); - return is_lttpr_present; + return status; } bool dp_is_lttpr_present(struct dc_link *link) @@ -5227,76 +5227,45 @@ static void retrieve_cable_id(struct dc_link *link) &link->dpcd_caps.cable_id, &usbc_cable_id); } -/* DPRX may take some time to respond to AUX messages after HPD asserted. - * If AUX read unsuccessful, try to wake unresponsive DPRX by toggling DPCD SET_POWER (0x600). - */ -static enum dc_status wa_try_to_wake_dprx(struct dc_link *link, uint64_t timeout_ms) +enum dc_status wake_up_aux_channel(struct dc_link *link) { enum dc_status status = DC_ERROR_UNEXPECTED; - uint8_t dpcd_data = 0; - uint64_t start_ts = 0; - uint64_t current_ts = 0; - uint64_t time_taken_ms = 0; - enum dc_connection_type type = dc_connection_none; - bool lttpr_present; - bool vbios_lttpr_interop = link->dc->caps.vbios_lttpr_aware; + uint32_t aux_channel_retry_cnt = 0; + uint8_t dpcd_power_state = '\0'; - lttpr_present = dp_is_lttpr_present(link) || - (!vbios_lttpr_interop || !link->dc->caps.extended_aux_timeout_support); - DC_LOG_DC("lttpr_present = %d.\n", lttpr_present ? 1 : 0); + while (status != DC_OK && aux_channel_retry_cnt < 10) { + status = core_link_read_dpcd(link, DP_SET_POWER, + &dpcd_power_state, sizeof(dpcd_power_state)); - /* Issue an AUX read to test DPRX responsiveness. If LTTPR is supported the first read is expected to - * be to determine LTTPR capabilities. Otherwise trying to read power state should be an innocuous AUX read. - */ - if (lttpr_present) - status = core_link_read_dpcd( - link, - DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV, - &dpcd_data, - sizeof(dpcd_data)); - else - status = core_link_read_dpcd( - link, - DP_SET_POWER, - &dpcd_data, - sizeof(dpcd_data)); + /* Delay 1 ms if AUX CH is in power down state. Based on spec + * section 2.3.1.2, if AUX CH may be powered down due to + * write to DPCD 600h = 2. Sink AUX CH is monitoring differential + * signal and may need up to 1 ms before being able to reply. + */ + if (status != DC_OK || dpcd_power_state == DP_SET_POWER_D3) { + udelay(1000); + aux_channel_retry_cnt++; + } + } if (status != DC_OK) { - DC_LOG_WARNING("%s: Read DPCD LTTPR_CAP failed - try to toggle DPCD SET_POWER for %lld ms.", - __func__, - timeout_ms); - start_ts = dm_get_timestamp(link->ctx); - - do { - if (!dc_link_detect_sink(link, &type) || type == dc_connection_none) - break; - - dpcd_data = DP_SET_POWER_D3; - status = core_link_write_dpcd( - link, - DP_SET_POWER, - &dpcd_data, - sizeof(dpcd_data)); - - dpcd_data = DP_SET_POWER_D0; - status = core_link_write_dpcd( - link, - DP_SET_POWER, - &dpcd_data, - sizeof(dpcd_data)); - - current_ts = dm_get_timestamp(link->ctx); - time_taken_ms = div_u64(dm_get_elapse_time_in_ns(link->ctx, current_ts, start_ts), 1000000); - } while (status != DC_OK && time_taken_ms < timeout_ms); + dpcd_power_state = DP_SET_POWER_D0; + status = core_link_write_dpcd( + link, + DP_SET_POWER, + &dpcd_power_state, + sizeof(dpcd_power_state)); - DC_LOG_WARNING("%s: DPCD SET_POWER %s after %lld ms%s", - __func__, - (status == DC_OK) ? "succeeded" : "failed", - time_taken_ms, - (type == dc_connection_none) ? ". Unplugged." : "."); + dpcd_power_state = DP_SET_POWER_D3; + status = core_link_write_dpcd( + link, + DP_SET_POWER, + &dpcd_power_state, + sizeof(dpcd_power_state)); + return DC_ERROR_UNEXPECTED; } - return status; + return DC_OK; } static bool retrieve_link_cap(struct dc_link *link) @@ -5308,7 +5277,6 @@ static bool retrieve_link_cap(struct dc_link *link) /*Only need to read 1 byte starting from DP_DPRX_FEATURE_ENUMERATION_LIST. */ uint8_t dpcd_dprx_data = '\0'; - uint8_t dpcd_power_state = '\0'; struct dp_device_vendor_id sink_id; union down_stream_port_count down_strm_port_count; @@ -5316,11 +5284,9 @@ static bool retrieve_link_cap(struct dc_link *link) union dp_downstream_port_present ds_port = { 0 }; enum dc_status status = DC_ERROR_UNEXPECTED; uint32_t read_dpcd_retry_cnt = 3; - uint32_t aux_channel_retry_cnt = 0; int i; struct dp_sink_hw_fw_revision dp_hw_fw_revision; const uint32_t post_oui_delay = 30; // 30ms - bool is_lttpr_present = false; memset(dpcd_data, '\0', sizeof(dpcd_data)); memset(&down_strm_port_count, @@ -5335,51 +5301,17 @@ static bool retrieve_link_cap(struct dc_link *link) dc_link_aux_try_to_configure_timeout(link->ddc, LINK_AUX_DEFAULT_LTTPR_TIMEOUT_PERIOD); - /* Try to ensure AUX channel active before proceeding. */ - if (link->dc->debug.aux_wake_wa.bits.enable_wa) { - uint64_t timeout_ms = link->dc->debug.aux_wake_wa.bits.timeout_ms; - - if (link->dc->debug.aux_wake_wa.bits.use_default_timeout) - timeout_ms = LINK_AUX_WAKE_TIMEOUT_MS; - status = wa_try_to_wake_dprx(link, timeout_ms); - } - - while (status != DC_OK && aux_channel_retry_cnt < 10) { - status = core_link_read_dpcd(link, DP_SET_POWER, - &dpcd_power_state, sizeof(dpcd_power_state)); - - /* Delay 1 ms if AUX CH is in power down state. Based on spec - * section 2.3.1.2, if AUX CH may be powered down due to - * write to DPCD 600h = 2. Sink AUX CH is monitoring differential - * signal and may need up to 1 ms before being able to reply. - */ - if (status != DC_OK || dpcd_power_state == DP_SET_POWER_D3) { - udelay(1000); - aux_channel_retry_cnt++; - } - } + status = dp_retrieve_lttpr_cap(link); - /* If aux channel is not active, return false and trigger another detect*/ if (status != DC_OK) { - dpcd_power_state = DP_SET_POWER_D0; - status = core_link_write_dpcd( - link, - DP_SET_POWER, - &dpcd_power_state, - sizeof(dpcd_power_state)); - - dpcd_power_state = DP_SET_POWER_D3; - status = core_link_write_dpcd( - link, - DP_SET_POWER, - &dpcd_power_state, - sizeof(dpcd_power_state)); - return false; + status = wake_up_aux_channel(link); + if (status == DC_OK) + dp_retrieve_lttpr_cap(link); + else + return false; } - is_lttpr_present = dp_retrieve_lttpr_cap(link); - - if (is_lttpr_present) + if (dp_is_lttpr_present(link)) configure_lttpr_mode_transparent(link); /* Read DP tunneling information. */ @@ -5406,7 +5338,7 @@ static bool retrieve_link_cap(struct dc_link *link) return false; } - if (!is_lttpr_present) + if (!dp_is_lttpr_present(link)) dc_link_aux_try_to_configure_timeout(link->ddc, LINK_AUX_DEFAULT_TIMEOUT_PERIOD); { diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h index b304d450b038..e8d8c5cb1309 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h @@ -193,7 +193,7 @@ enum dc_status dpcd_configure_lttpr_mode( struct link_training_settings *lt_settings); enum dp_link_encoding dp_get_link_encoding_format(const struct dc_link_settings *link_settings); -bool dp_retrieve_lttpr_cap(struct dc_link *link); +enum dc_status dp_retrieve_lttpr_cap(struct dc_link *link); bool dp_is_lttpr_present(struct dc_link *link); enum lttpr_mode dp_decide_lttpr_mode(struct dc_link *link, struct dc_link_settings *link_setting); void dp_get_lttpr_mode_override(struct dc_link *link, enum lttpr_mode *override); -- cgit From 12024b17617af9b953cf8801a6a3d3c769ebd06f Mon Sep 17 00:00:00 2001 From: wangjianli Date: Sat, 22 Oct 2022 14:01:55 +0800 Subject: amd/amdgpu: fix repeated words in comments Delete the redundant word 'the'. Signed-off-by: wangjianli Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index ddaecb2610c9..6f958603c8cc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -1568,7 +1568,7 @@ static int amdgpu_device_check_arguments(struct amdgpu_device *adev) * @pdev: pci dev pointer * @state: vga_switcheroo state * - * Callback for the switcheroo driver. Suspends or resumes the + * Callback for the switcheroo driver. Suspends or resumes * the asics before or after it is powered up using ACPI methods. */ static void amdgpu_switcheroo_set_state(struct pci_dev *pdev, -- cgit From 31bc2485e88537009fad9246bf48319fc9172230 Mon Sep 17 00:00:00 2001 From: wangjianli Date: Sat, 22 Oct 2022 14:04:17 +0800 Subject: drm/radeon: fix repeated words in comments Delete the redundant word 'the'. Signed-off-by: wangjianli Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index a556b6be1137..262e2bcb30c3 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1207,7 +1207,7 @@ static void radeon_check_arguments(struct radeon_device *rdev) * @pdev: pci dev pointer * @state: vga_switcheroo state * - * Callback for the switcheroo driver. Suspends or resumes the + * Callback for the switcheroo driver. Suspends or resumes * the asics before or after it is powered up using ACPI methods. */ static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_state state) -- cgit From 93e28cf81406519622383ae51d6fd183b744ac46 Mon Sep 17 00:00:00 2001 From: Joaquín Ignacio Aramendía Date: Mon, 24 Oct 2022 08:33:59 -0300 Subject: drm/amd/display: Revert logic for plane modifiers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This file was split in commit 5d945cbcd4b16a29d6470a80dfb19738f9a4319f ("drm/amd/display: Create a file dedicated to planes") and the logic in dm_plane_format_mod_supported() function got changed by a switch logic. That change broke drm_plane modifiers setting on series 5000 APUs (tested on OXP mini AMD 5800U and HP Dev One 5850U PRO) leading to Gamescope not working as reported on GitHub[1] To reproduce the issue, enter a TTY and run: $ gamescope -- vkcube With said commit applied it will abort. This one restores the old logic, fixing the issue that affects Gamescope. [1](https://github.com/Plagman/gamescope/issues/624) Cc: # 6.0.x Signed-off-by: Joaquín Ignacio Aramendía Reviewed-by: Bas Nieuwenhuizen Signed-off-by: Alex Deucher --- .../drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c | 50 +++------------------- 1 file changed, 7 insertions(+), 43 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c index dfd3be49eac8..e6854f7270a6 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c @@ -1369,7 +1369,7 @@ static bool dm_plane_format_mod_supported(struct drm_plane *plane, { struct amdgpu_device *adev = drm_to_adev(plane->dev); const struct drm_format_info *info = drm_format_info(format); - struct hw_asic_id asic_id = adev->dm.dc->ctx->asic_id; + int i; enum dm_micro_swizzle microtile = modifier_gfx9_swizzle_mode(modifier) & 3; @@ -1386,49 +1386,13 @@ static bool dm_plane_format_mod_supported(struct drm_plane *plane, return true; } - /* check if swizzle mode is supported by this version of DCN */ - switch (asic_id.chip_family) { - case FAMILY_SI: - case FAMILY_CI: - case FAMILY_KV: - case FAMILY_CZ: - case FAMILY_VI: - /* asics before AI does not have modifier support */ - return false; - case FAMILY_AI: - case FAMILY_RV: - case FAMILY_NV: - case FAMILY_VGH: - case FAMILY_YELLOW_CARP: - case AMDGPU_FAMILY_GC_10_3_6: - case AMDGPU_FAMILY_GC_10_3_7: - switch (AMD_FMT_MOD_GET(TILE, modifier)) { - case AMD_FMT_MOD_TILE_GFX9_64K_R_X: - case AMD_FMT_MOD_TILE_GFX9_64K_D_X: - case AMD_FMT_MOD_TILE_GFX9_64K_S_X: - case AMD_FMT_MOD_TILE_GFX9_64K_D: - return true; - default: - return false; - } - break; - case AMDGPU_FAMILY_GC_11_0_0: - case AMDGPU_FAMILY_GC_11_0_1: - switch (AMD_FMT_MOD_GET(TILE, modifier)) { - case AMD_FMT_MOD_TILE_GFX11_256K_R_X: - case AMD_FMT_MOD_TILE_GFX9_64K_R_X: - case AMD_FMT_MOD_TILE_GFX9_64K_D_X: - case AMD_FMT_MOD_TILE_GFX9_64K_S_X: - case AMD_FMT_MOD_TILE_GFX9_64K_D: - return true; - default: - return false; - } - break; - default: - ASSERT(0); /* Unknown asic */ - break; + /* Check that the modifier is on the list of the plane's supported modifiers. */ + for (i = 0; i < plane->modifier_count; i++) { + if (modifier == plane->modifiers[i]) + break; } + if (i == plane->modifier_count) + return false; /* * For D swizzle the canonical modifier depends on the bpp, so check -- cgit From 27b2ae654370e1a8e446b0e48c4e406abed12ca1 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Fri, 21 Oct 2022 00:33:35 +0300 Subject: drm/client: Switch drm_client_buffer_delete() to unlocked drm_gem_vunmap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The drm_client_buffer_delete() wasn't switched to unlocked GEM vunmapping by accident when rest of drm_client code transitioned to the unlocked variants of the vmapping functions. Make drm_client_buffer_delete() use the unlocked variant. This fixes lockdep warning splat about missing reservation lock when framebuffer is released. Reported-by: kernel test robot Link: https://lore.kernel.org/dri-devel/890f70db-68b0-8456-ca3c-c5496ef90517@collabora.com/T/ Fixes: 79e2cf2e7a19 ("drm/gem: Take reservation lock for vmap/vunmap operations") Signed-off-by: Dmitry Osipenko Acked-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20221020213335.309092-1-dmitry.osipenko@collabora.com --- drivers/gpu/drm/drm_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c index fbcb1e995384..38e1be991caa 100644 --- a/drivers/gpu/drm/drm_client.c +++ b/drivers/gpu/drm/drm_client.c @@ -235,7 +235,7 @@ static void drm_client_buffer_delete(struct drm_client_buffer *buffer) { struct drm_device *dev = buffer->client->dev; - drm_gem_vunmap(buffer->gem, &buffer->map); + drm_gem_vunmap_unlocked(buffer->gem, &buffer->map); if (buffer->gem) drm_gem_object_put(buffer->gem); -- cgit From 568944af44e7538ed5d1389dabf56e938afdaf4f Mon Sep 17 00:00:00 2001 From: John Harrison Date: Thu, 6 Oct 2022 14:38:10 -0700 Subject: drm/i915/guc: Limit scheduling properties to avoid overflow GuC converts the pre-emption timeout and timeslice quantum values into clock ticks internally. That significantly reduces the point of 32bit overflow. On current platforms, worst case scenario is approximately 110 seconds. Rather than allowing the user to set higher values and then get confused by early timeouts, add limits when setting these values. v2: Add helper functions for clamping (review feedback from Tvrtko). v3: Add a bunch of BUG_ON range checks in addition to the checks already in the clamping functions (Tvrtko) Signed-off-by: John Harrison Reviewed-by: Daniele Ceraolo Spurio Acked-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20221006213813.1563435-2-John.C.Harrison@Intel.com --- drivers/gpu/drm/i915/gt/intel_engine.h | 6 ++ drivers/gpu/drm/i915/gt/intel_engine_cs.c | 69 +++++++++++++++++++++++ drivers/gpu/drm/i915/gt/sysfs_engines.c | 25 ++++---- drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h | 21 +++++++ drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c | 8 +++ 5 files changed, 119 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_engine.h b/drivers/gpu/drm/i915/gt/intel_engine.h index 04e435bce79b..cbc8b857d5f7 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine.h +++ b/drivers/gpu/drm/i915/gt/intel_engine.h @@ -348,4 +348,10 @@ intel_engine_get_hung_context(struct intel_engine_cs *engine) return engine->hung_ce; } +u64 intel_clamp_heartbeat_interval_ms(struct intel_engine_cs *engine, u64 value); +u64 intel_clamp_max_busywait_duration_ns(struct intel_engine_cs *engine, u64 value); +u64 intel_clamp_preempt_timeout_ms(struct intel_engine_cs *engine, u64 value); +u64 intel_clamp_stop_timeout_ms(struct intel_engine_cs *engine, u64 value); +u64 intel_clamp_timeslice_duration_ms(struct intel_engine_cs *engine, u64 value); + #endif /* _INTEL_RINGBUFFER_H_ */ diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c index c408bac3c533..b1c16aac2a9b 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c @@ -512,6 +512,26 @@ static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id, engine->flags |= I915_ENGINE_HAS_EU_PRIORITY; } + /* Cap properties according to any system limits */ +#define CLAMP_PROP(field) \ + do { \ + u64 clamp = intel_clamp_##field(engine, engine->props.field); \ + if (clamp != engine->props.field) { \ + drm_notice(&engine->i915->drm, \ + "Warning, clamping %s to %lld to prevent overflow\n", \ + #field, clamp); \ + engine->props.field = clamp; \ + } \ + } while (0) + + CLAMP_PROP(heartbeat_interval_ms); + CLAMP_PROP(max_busywait_duration_ns); + CLAMP_PROP(preempt_timeout_ms); + CLAMP_PROP(stop_timeout_ms); + CLAMP_PROP(timeslice_duration_ms); + +#undef CLAMP_PROP + engine->defaults = engine->props; /* never to change again */ engine->context_size = intel_engine_context_size(gt, engine->class); @@ -534,6 +554,55 @@ static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id, return 0; } +u64 intel_clamp_heartbeat_interval_ms(struct intel_engine_cs *engine, u64 value) +{ + value = min_t(u64, value, jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT)); + + return value; +} + +u64 intel_clamp_max_busywait_duration_ns(struct intel_engine_cs *engine, u64 value) +{ + value = min(value, jiffies_to_nsecs(2)); + + return value; +} + +u64 intel_clamp_preempt_timeout_ms(struct intel_engine_cs *engine, u64 value) +{ + /* + * NB: The GuC API only supports 32bit values. However, the limit is further + * reduced due to internal calculations which would otherwise overflow. + */ + if (intel_guc_submission_is_wanted(&engine->gt->uc.guc)) + value = min_t(u64, value, guc_policy_max_preempt_timeout_ms()); + + value = min_t(u64, value, jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT)); + + return value; +} + +u64 intel_clamp_stop_timeout_ms(struct intel_engine_cs *engine, u64 value) +{ + value = min_t(u64, value, jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT)); + + return value; +} + +u64 intel_clamp_timeslice_duration_ms(struct intel_engine_cs *engine, u64 value) +{ + /* + * NB: The GuC API only supports 32bit values. However, the limit is further + * reduced due to internal calculations which would otherwise overflow. + */ + if (intel_guc_submission_is_wanted(&engine->gt->uc.guc)) + value = min_t(u64, value, guc_policy_max_exec_quantum_ms()); + + value = min_t(u64, value, jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT)); + + return value; +} + static void __setup_engine_capabilities(struct intel_engine_cs *engine) { struct drm_i915_private *i915 = engine->i915; diff --git a/drivers/gpu/drm/i915/gt/sysfs_engines.c b/drivers/gpu/drm/i915/gt/sysfs_engines.c index 967031056202..f2d9858d827c 100644 --- a/drivers/gpu/drm/i915/gt/sysfs_engines.c +++ b/drivers/gpu/drm/i915/gt/sysfs_engines.c @@ -144,7 +144,7 @@ max_spin_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { struct intel_engine_cs *engine = kobj_to_engine(kobj); - unsigned long long duration; + unsigned long long duration, clamped; int err; /* @@ -168,7 +168,8 @@ max_spin_store(struct kobject *kobj, struct kobj_attribute *attr, if (err) return err; - if (duration > jiffies_to_nsecs(2)) + clamped = intel_clamp_max_busywait_duration_ns(engine, duration); + if (duration != clamped) return -EINVAL; WRITE_ONCE(engine->props.max_busywait_duration_ns, duration); @@ -203,7 +204,7 @@ timeslice_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { struct intel_engine_cs *engine = kobj_to_engine(kobj); - unsigned long long duration; + unsigned long long duration, clamped; int err; /* @@ -218,7 +219,8 @@ timeslice_store(struct kobject *kobj, struct kobj_attribute *attr, if (err) return err; - if (duration > jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT)) + clamped = intel_clamp_timeslice_duration_ms(engine, duration); + if (duration != clamped) return -EINVAL; WRITE_ONCE(engine->props.timeslice_duration_ms, duration); @@ -256,7 +258,7 @@ stop_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { struct intel_engine_cs *engine = kobj_to_engine(kobj); - unsigned long long duration; + unsigned long long duration, clamped; int err; /* @@ -272,7 +274,8 @@ stop_store(struct kobject *kobj, struct kobj_attribute *attr, if (err) return err; - if (duration > jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT)) + clamped = intel_clamp_stop_timeout_ms(engine, duration); + if (duration != clamped) return -EINVAL; WRITE_ONCE(engine->props.stop_timeout_ms, duration); @@ -306,7 +309,7 @@ preempt_timeout_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { struct intel_engine_cs *engine = kobj_to_engine(kobj); - unsigned long long timeout; + unsigned long long timeout, clamped; int err; /* @@ -322,7 +325,8 @@ preempt_timeout_store(struct kobject *kobj, struct kobj_attribute *attr, if (err) return err; - if (timeout > jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT)) + clamped = intel_clamp_preempt_timeout_ms(engine, timeout); + if (timeout != clamped) return -EINVAL; WRITE_ONCE(engine->props.preempt_timeout_ms, timeout); @@ -362,7 +366,7 @@ heartbeat_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { struct intel_engine_cs *engine = kobj_to_engine(kobj); - unsigned long long delay; + unsigned long long delay, clamped; int err; /* @@ -379,7 +383,8 @@ heartbeat_store(struct kobject *kobj, struct kobj_attribute *attr, if (err) return err; - if (delay >= jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT)) + clamped = intel_clamp_heartbeat_interval_ms(engine, delay); + if (delay != clamped) return -EINVAL; err = intel_engine_set_heartbeat(engine, delay); diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h index e7a7fb450f44..968ebd79dce7 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h @@ -327,6 +327,27 @@ struct guc_update_scheduling_policy { #define GLOBAL_POLICY_DEFAULT_DPC_PROMOTE_TIME_US 500000 +/* + * GuC converts the timeout to clock ticks internally. Different platforms have + * different GuC clocks. Thus, the maximum value before overflow is platform + * dependent. Current worst case scenario is about 110s. So, the spec says to + * limit to 100s to be safe. + */ +#define GUC_POLICY_MAX_EXEC_QUANTUM_US (100 * 1000 * 1000UL) +#define GUC_POLICY_MAX_PREEMPT_TIMEOUT_US (100 * 1000 * 1000UL) + +static inline u32 guc_policy_max_exec_quantum_ms(void) +{ + BUILD_BUG_ON(GUC_POLICY_MAX_EXEC_QUANTUM_US >= UINT_MAX); + return GUC_POLICY_MAX_EXEC_QUANTUM_US / 1000; +} + +static inline u32 guc_policy_max_preempt_timeout_ms(void) +{ + BUILD_BUG_ON(GUC_POLICY_MAX_PREEMPT_TIMEOUT_US >= UINT_MAX); + return GUC_POLICY_MAX_PREEMPT_TIMEOUT_US / 1000; +} + struct guc_policies { u32 submission_queue_depth[GUC_MAX_ENGINE_CLASSES]; /* In micro seconds. How much time to allow before DPC processing is diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index 693b07a97789..c433d35ae41a 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -2430,6 +2430,10 @@ static int guc_context_policy_init_v70(struct intel_context *ce, bool loop) int ret; /* NB: For both of these, zero means disabled. */ + GEM_BUG_ON(overflows_type(engine->props.timeslice_duration_ms * 1000, + execution_quantum)); + GEM_BUG_ON(overflows_type(engine->props.preempt_timeout_ms * 1000, + preemption_timeout)); execution_quantum = engine->props.timeslice_duration_ms * 1000; preemption_timeout = engine->props.preempt_timeout_ms * 1000; @@ -2463,6 +2467,10 @@ static void guc_context_policy_init_v69(struct intel_engine_cs *engine, desc->policy_flags |= CONTEXT_POLICY_FLAG_PREEMPT_TO_IDLE_V69; /* NB: For both of these, zero means disabled. */ + GEM_BUG_ON(overflows_type(engine->props.timeslice_duration_ms * 1000, + desc->execution_quantum)); + GEM_BUG_ON(overflows_type(engine->props.preempt_timeout_ms * 1000, + desc->preemption_timeout)); desc->execution_quantum = engine->props.timeslice_duration_ms * 1000; desc->preemption_timeout = engine->props.preempt_timeout_ms * 1000; } -- cgit From c3bd49cd9a1043b963331e7fd874b380bed3f2bd Mon Sep 17 00:00:00 2001 From: John Harrison Date: Thu, 6 Oct 2022 14:38:11 -0700 Subject: drm/i915: Fix compute pre-emption w/a to apply to compute engines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit An earlier patch added support for compute engines. However, it missed enabling the anti-pre-emption w/a for the new engine class. So move the 'compute capable' flag earlier and use it for the pre-emption w/a test. Fixes: c674c5b9342e ("drm/i915/xehp: CCS should use RCS setup functions") Cc: Tvrtko Ursulin Cc: Daniele Ceraolo Spurio Cc: Aravind Iddamsetty Cc: Matt Roper Cc: Tvrtko Ursulin Cc: Daniel Vetter Cc: Maarten Lankhorst Cc: Lucas De Marchi Cc: John Harrison Cc: Jason Ekstrand Cc: "Michał Winiarski" Cc: Matthew Brost Cc: Chris Wilson Cc: Tejas Upadhyay Cc: Umesh Nerlige Ramappa Cc: "Thomas Hellström" Cc: Stuart Summers Cc: Matthew Auld Cc: Jani Nikula Cc: Ramalingam C Cc: Akeem G Abodunrin Signed-off-by: John Harrison Reviewed-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20221006213813.1563435-3-John.C.Harrison@Intel.com --- drivers/gpu/drm/i915/gt/intel_engine_cs.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c index b1c16aac2a9b..7c5b33ccedd0 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c @@ -486,6 +486,17 @@ static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id, engine->logical_mask = BIT(logical_instance); __sprint_engine_name(engine); + if ((engine->class == COMPUTE_CLASS && !RCS_MASK(engine->gt) && + __ffs(CCS_MASK(engine->gt)) == engine->instance) || + engine->class == RENDER_CLASS) + engine->flags |= I915_ENGINE_FIRST_RENDER_COMPUTE; + + /* features common between engines sharing EUs */ + if (engine->class == RENDER_CLASS || engine->class == COMPUTE_CLASS) { + engine->flags |= I915_ENGINE_HAS_RCS_REG_STATE; + engine->flags |= I915_ENGINE_HAS_EU_PRIORITY; + } + engine->props.heartbeat_interval_ms = CONFIG_DRM_I915_HEARTBEAT_INTERVAL; engine->props.max_busywait_duration_ns = @@ -498,20 +509,9 @@ static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id, CONFIG_DRM_I915_TIMESLICE_DURATION; /* Override to uninterruptible for OpenCL workloads. */ - if (GRAPHICS_VER(i915) == 12 && engine->class == RENDER_CLASS) + if (GRAPHICS_VER(i915) == 12 && (engine->flags & I915_ENGINE_HAS_RCS_REG_STATE)) engine->props.preempt_timeout_ms = 0; - if ((engine->class == COMPUTE_CLASS && !RCS_MASK(engine->gt) && - __ffs(CCS_MASK(engine->gt)) == engine->instance) || - engine->class == RENDER_CLASS) - engine->flags |= I915_ENGINE_FIRST_RENDER_COMPUTE; - - /* features common between engines sharing EUs */ - if (engine->class == RENDER_CLASS || engine->class == COMPUTE_CLASS) { - engine->flags |= I915_ENGINE_HAS_RCS_REG_STATE; - engine->flags |= I915_ENGINE_HAS_EU_PRIORITY; - } - /* Cap properties according to any system limits */ #define CLAMP_PROP(field) \ do { \ -- cgit From 47daf84a8bfbc0ff7342b75fa2175591b64ef8d7 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Thu, 6 Oct 2022 14:38:12 -0700 Subject: drm/i915: Make the heartbeat play nice with long pre-emption timeouts Compute workloads are inherently not pre-emptible for long periods on current hardware. As a workaround for this, the pre-emption timeout for compute capable engines was disabled. This is undesirable with GuC submission as it prevents per engine reset of hung contexts. Hence the next patch will re-enable the timeout but bumped up by an order of magnitude. However, the heartbeat might not respect that. Depending upon current activity, a pre-emption to the heartbeat pulse might not even be attempted until the last heartbeat period. Which means that only one period is granted for the pre-emption to occur. With the aforesaid bump, the pre-emption timeout could be significantly larger than this heartbeat period. So adjust the heartbeat code to take the pre-emption timeout into account. When it reaches the final (high priority) period, it now ensures the delay before hitting reset is bigger than the pre-emption timeout. v2: Fix for selftests which adjust the heartbeat period manually. v3: Add FIXME comment about selftests. Add extra FIXME comment and drm_notices when setting heartbeat to a non-default value (review feedback from Tvrtko) Signed-off-by: John Harrison Reviewed-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20221006213813.1563435-4-John.C.Harrison@Intel.com --- drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c | 39 ++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c b/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c index a3698f611f45..9a527e1f5be6 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c @@ -22,9 +22,37 @@ static bool next_heartbeat(struct intel_engine_cs *engine) { + struct i915_request *rq; long delay; delay = READ_ONCE(engine->props.heartbeat_interval_ms); + + rq = engine->heartbeat.systole; + + /* + * FIXME: The final period extension is disabled if the period has been + * modified from the default. This is to prevent issues with certain + * selftests which override the value and expect specific behaviour. + * Once the selftests have been updated to either cope with variable + * heartbeat periods (or to override the pre-emption timeout as well, + * or just to add a selftest specific override of the extension), the + * generic override can be removed. + */ + if (rq && rq->sched.attr.priority >= I915_PRIORITY_BARRIER && + delay == engine->defaults.heartbeat_interval_ms) { + long longer; + + /* + * The final try is at the highest priority possible. Up until now + * a pre-emption might not even have been attempted. So make sure + * this last attempt allows enough time for a pre-emption to occur. + */ + longer = READ_ONCE(engine->props.preempt_timeout_ms) * 2; + longer = intel_clamp_heartbeat_interval_ms(engine, longer); + if (longer > delay) + delay = longer; + } + if (!delay) return false; @@ -288,6 +316,17 @@ int intel_engine_set_heartbeat(struct intel_engine_cs *engine, if (!delay && !intel_engine_has_preempt_reset(engine)) return -ENODEV; + /* FIXME: Remove together with equally marked hack in next_heartbeat. */ + if (delay != engine->defaults.heartbeat_interval_ms && + delay < 2 * engine->props.preempt_timeout_ms) { + if (intel_engine_uses_guc(engine)) + drm_notice(&engine->i915->drm, "%s heartbeat interval adjusted to a non-default value which may downgrade individual engine resets to full GPU resets!\n", + engine->name); + else + drm_notice(&engine->i915->drm, "%s heartbeat interval adjusted to a non-default value which may cause engine resets to target innocent contexts!\n", + engine->name); + } + intel_engine_pm_get(engine); err = mutex_lock_interruptible(&ce->timeline->mutex); -- cgit From d7a8680ec9fb217987a9569aba1abeed886805f0 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Thu, 6 Oct 2022 14:38:13 -0700 Subject: drm/i915: Improve long running compute w/a for GuC submission A workaround was added to the driver to allow compute workloads to run 'forever' by disabling pre-emption on the RCS engine for Gen12. It is not totally unbound as the heartbeat will kick in eventually and cause a reset of the hung engine. However, this does not work well in GuC submission mode. In GuC mode, the pre-emption timeout is how GuC detects hung contexts and triggers a per engine reset. Thus, disabling the timeout means also losing all per engine reset ability. A full GT reset will still occur when the heartbeat finally expires, but that is a much more destructive and undesirable mechanism. The purpose of the workaround is actually to give compute tasks longer to reach a pre-emption point after a pre-emption request has been issued. This is necessary because Gen12 does not support mid-thread pre-emption and compute tasks can have long running threads. So, rather than disabling the timeout completely, just set it to a 'long' value. v2: Review feedback from Tvrtko - must hard code the 'long' value instead of determining it algorithmically. So make it an extra CONFIG definition. Also, remove the execlist centric comment from the existing pre-emption timeout CONFIG option given that it applies to more than just execlists. Signed-off-by: John Harrison Reviewed-by: Daniele Ceraolo Spurio Acked-by: Michal Mrozek Acked-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20221006213813.1563435-5-John.C.Harrison@Intel.com --- drivers/gpu/drm/i915/Kconfig.profile | 26 ++++++++++++++++++++++---- drivers/gpu/drm/i915/gt/intel_engine_cs.c | 9 +++++++-- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/Kconfig.profile b/drivers/gpu/drm/i915/Kconfig.profile index 39328567c200..7cc38d25ee5c 100644 --- a/drivers/gpu/drm/i915/Kconfig.profile +++ b/drivers/gpu/drm/i915/Kconfig.profile @@ -57,10 +57,28 @@ config DRM_I915_PREEMPT_TIMEOUT default 640 # milliseconds help How long to wait (in milliseconds) for a preemption event to occur - when submitting a new context via execlists. If the current context - does not hit an arbitration point and yield to HW before the timer - expires, the HW will be reset to allow the more important context - to execute. + when submitting a new context. If the current context does not hit + an arbitration point and yield to HW before the timer expires, the + HW will be reset to allow the more important context to execute. + + This is adjustable via + /sys/class/drm/card?/engine/*/preempt_timeout_ms + + May be 0 to disable the timeout. + + The compiled in default may get overridden at driver probe time on + certain platforms and certain engines which will be reflected in the + sysfs control. + +config DRM_I915_PREEMPT_TIMEOUT_COMPUTE + int "Preempt timeout for compute engines (ms, jiffy granularity)" + default 7500 # milliseconds + help + How long to wait (in milliseconds) for a preemption event to occur + when submitting a new context to a compute capable engine. If the + current context does not hit an arbitration point and yield to HW + before the timer expires, the HW will be reset to allow the more + important context to execute. This is adjustable via /sys/class/drm/card?/engine/*/preempt_timeout_ms diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c index 7c5b33ccedd0..3b7d750ad054 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c @@ -508,9 +508,14 @@ static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id, engine->props.timeslice_duration_ms = CONFIG_DRM_I915_TIMESLICE_DURATION; - /* Override to uninterruptible for OpenCL workloads. */ + /* + * Mid-thread pre-emption is not available in Gen12. Unfortunately, + * some compute workloads run quite long threads. That means they get + * reset due to not pre-empting in a timely manner. So, bump the + * pre-emption timeout value to be much higher for compute engines. + */ if (GRAPHICS_VER(i915) == 12 && (engine->flags & I915_ENGINE_HAS_RCS_REG_STATE)) - engine->props.preempt_timeout_ms = 0; + engine->props.preempt_timeout_ms = CONFIG_DRM_I915_PREEMPT_TIMEOUT_COMPUTE; /* Cap properties according to any system limits */ #define CLAMP_PROP(field) \ -- cgit From a894077890ad118de88c97c03f67a611ca60882a Mon Sep 17 00:00:00 2001 From: Alan Previn Date: Wed, 19 Oct 2022 00:29:29 -0700 Subject: drm/i915/guc: Add error-capture init warnings when needed If GuC is being used and we initialized GuC-error-capture, we need to be warning if we don't provide an error-capture register list in the firmware ADS, for valid GT engines. A warning makes sense as this would impact debugability without realizing why a reglist wasn't retrieved and reported by GuC. However, depending on the platform, we might have certain engines that have a register list for engine instance error state but not for engine class. Thus, add a check only to warn if the register list was non existent vs an empty list (use the empty lists to skip the warning). NOTE: if a future platform were to introduce new registers in place of what was an empty list on existing / legacy hardware engines no warning is provided as the empty list is meant to be used intentionally. As an example, if a future hardware were to add blitter engine-class-registers (new) on top of the legacy blitter engine-instance-register (HEAD, TAIL, etc.), no warning is generated. Signed-off-by: Alan Previn Reviewed-by: John Harrison Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20221019072930.17755-2-alan.previn.teres.alexis@intel.com --- drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c | 78 +++++++++++++++++++++++--- 1 file changed, 69 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c index d5c03e7a7843..abf6e5eb711e 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c @@ -419,6 +419,44 @@ guc_capture_get_device_reglist(struct intel_guc *guc) return default_lists; } +static const char * +__stringify_type(u32 type) +{ + switch (type) { + case GUC_CAPTURE_LIST_TYPE_GLOBAL: + return "Global"; + case GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS: + return "Class"; + case GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE: + return "Instance"; + default: + break; + } + + return "unknown"; +} + +static const char * +__stringify_engclass(u32 class) +{ + switch (class) { + case GUC_RENDER_CLASS: + return "Render"; + case GUC_VIDEO_CLASS: + return "Video"; + case GUC_VIDEOENHANCE_CLASS: + return "VideoEnhance"; + case GUC_BLITTER_CLASS: + return "Blitter"; + case GUC_COMPUTE_CLASS: + return "Compute"; + default: + break; + } + + return "unknown"; +} + static int guc_capture_list_init(struct intel_guc *guc, u32 owner, u32 type, u32 classid, struct guc_mmio_reg *ptr, u16 num_entries) @@ -482,23 +520,38 @@ guc_cap_list_num_regs(struct intel_guc_state_capture *gc, u32 owner, u32 type, u return num_regs; } -int -intel_guc_capture_getlistsize(struct intel_guc *guc, u32 owner, u32 type, u32 classid, - size_t *size) +static int +guc_capture_getlistsize(struct intel_guc *guc, u32 owner, u32 type, u32 classid, + size_t *size, bool is_purpose_est) { struct intel_guc_state_capture *gc = guc->capture; + struct drm_i915_private *i915 = guc_to_gt(guc)->i915; struct __guc_capture_ads_cache *cache = &gc->ads_cache[owner][type][classid]; int num_regs; - if (!gc->reglists) + if (!gc->reglists) { + drm_warn(&i915->drm, "GuC-capture: No reglist on this device\n"); return -ENODEV; + } if (cache->is_valid) { *size = cache->size; return cache->status; } + if (!is_purpose_est && owner == GUC_CAPTURE_LIST_INDEX_PF && + !guc_capture_get_one_list(gc->reglists, owner, type, classid)) { + if (type == GUC_CAPTURE_LIST_TYPE_GLOBAL) + drm_warn(&i915->drm, "Missing GuC-Err-Cap reglist Global!\n"); + else + drm_warn(&i915->drm, "Missing GuC-Err-Cap reglist %s(%u):%s(%u)!\n", + __stringify_type(type), type, + __stringify_engclass(classid), classid); + return -ENODATA; + } + num_regs = guc_cap_list_num_regs(gc, owner, type, classid); + /* intentional empty lists can exist depending on hw config */ if (!num_regs) return -ENODATA; @@ -508,6 +561,13 @@ intel_guc_capture_getlistsize(struct intel_guc *guc, u32 owner, u32 type, u32 cl return 0; } +int +intel_guc_capture_getlistsize(struct intel_guc *guc, u32 owner, u32 type, u32 classid, + size_t *size) +{ + return guc_capture_getlistsize(guc, owner, type, classid, size, false); +} + static void guc_capture_create_prealloc_nodes(struct intel_guc *guc); int @@ -627,15 +687,15 @@ guc_capture_output_min_size_est(struct intel_guc *guc) worst_min_size += sizeof(struct guc_state_capture_group_header_t) + (3 * sizeof(struct guc_state_capture_header_t)); - if (!intel_guc_capture_getlistsize(guc, 0, GUC_CAPTURE_LIST_TYPE_GLOBAL, 0, &tmp)) + if (!guc_capture_getlistsize(guc, 0, GUC_CAPTURE_LIST_TYPE_GLOBAL, 0, &tmp, true)) num_regs += tmp; - if (!intel_guc_capture_getlistsize(guc, 0, GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS, - engine->class, &tmp)) { + if (!guc_capture_getlistsize(guc, 0, GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS, + engine->class, &tmp, true)) { num_regs += tmp; } - if (!intel_guc_capture_getlistsize(guc, 0, GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE, - engine->class, &tmp)) { + if (!guc_capture_getlistsize(guc, 0, GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE, + engine->class, &tmp, true)) { num_regs += tmp; } } -- cgit From 5f8a3f65fc55272e5915d0edea9c691743a02e15 Mon Sep 17 00:00:00 2001 From: Alan Previn Date: Wed, 19 Oct 2022 00:29:30 -0700 Subject: drm/i915/guc: Add compute reglist for guc err capture We missed this at initial upstream because at that time none of the GuC enabled platforms had a compute engine. Add this now. Signed-off-by: Alan Previn Reviewed-by: John Harrison Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20221019072930.17755-3-alan.previn.teres.alexis@intel.com --- drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c index abf6e5eb711e..c4bee3bc15a9 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c @@ -169,6 +169,8 @@ static struct __guc_mmio_reg_descr_group default_lists[] = { MAKE_REGLIST(default_global_regs, PF, GLOBAL, 0), MAKE_REGLIST(default_rc_class_regs, PF, ENGINE_CLASS, GUC_RENDER_CLASS), MAKE_REGLIST(xe_lpd_rc_inst_regs, PF, ENGINE_INSTANCE, GUC_RENDER_CLASS), + MAKE_REGLIST(default_rc_class_regs, PF, ENGINE_CLASS, GUC_COMPUTE_CLASS), + MAKE_REGLIST(xe_lpd_rc_inst_regs, PF, ENGINE_INSTANCE, GUC_COMPUTE_CLASS), MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_VIDEO_CLASS), MAKE_REGLIST(xe_lpd_vd_inst_regs, PF, ENGINE_INSTANCE, GUC_VIDEO_CLASS), MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_VIDEOENHANCE_CLASS), @@ -182,6 +184,8 @@ static const struct __guc_mmio_reg_descr_group xe_lpd_lists[] = { MAKE_REGLIST(xe_lpd_global_regs, PF, GLOBAL, 0), MAKE_REGLIST(xe_lpd_rc_class_regs, PF, ENGINE_CLASS, GUC_RENDER_CLASS), MAKE_REGLIST(xe_lpd_rc_inst_regs, PF, ENGINE_INSTANCE, GUC_RENDER_CLASS), + MAKE_REGLIST(xe_lpd_rc_class_regs, PF, ENGINE_CLASS, GUC_COMPUTE_CLASS), + MAKE_REGLIST(xe_lpd_rc_inst_regs, PF, ENGINE_INSTANCE, GUC_COMPUTE_CLASS), MAKE_REGLIST(empty_regs_list, PF, ENGINE_CLASS, GUC_VIDEO_CLASS), MAKE_REGLIST(xe_lpd_vd_inst_regs, PF, ENGINE_INSTANCE, GUC_VIDEO_CLASS), MAKE_REGLIST(xe_lpd_vec_class_regs, PF, ENGINE_CLASS, GUC_VIDEOENHANCE_CLASS), -- cgit From 754c2a528fb974d0a6b310b51e2b3e64a1cf4ab0 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 17 Oct 2022 15:31:57 +0000 Subject: Revert "drm: hide unregistered connectors from GETCONNECTOR IOCTL" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 981f09295687f856d5345e19c7084aca481c1395. It turns out this causes logically active but disconnected DP MST connectors to disappear from the KMS resources list, and Mutter then assumes the connector is already disabled. Later on Mutter tries to re-use the same CRTC but fails since on the kernel side it's still tied to the disconnected DP MST connector. Signed-off-by: Simon Ser Tested-by: Jonas Ådahl Reviewed-by: Lyude Paul Cc: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20221017153150.60675-1-contact@emersion.fr --- drivers/gpu/drm/drm_mode_config.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c index 939d621c9ad4..688c8afe0bf1 100644 --- a/drivers/gpu/drm/drm_mode_config.c +++ b/drivers/gpu/drm/drm_mode_config.c @@ -151,9 +151,6 @@ int drm_mode_getresources(struct drm_device *dev, void *data, count = 0; connector_id = u64_to_user_ptr(card_res->connector_id_ptr); drm_for_each_connector_iter(connector, &conn_iter) { - if (connector->registration_state != DRM_CONNECTOR_REGISTERED) - continue; - /* only expose writeback connectors if userspace understands them */ if (!file_priv->writeback_connectors && (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)) -- cgit From 6fdc2d490ea1369d17afd7e6eb66fecc5b7209bc Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 17 Oct 2022 15:32:01 +0000 Subject: drm/connector: send hotplug uevent on connector cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A typical DP-MST unplug removes a KMS connector. However care must be taken to properly synchronize with user-space. The expected sequence of events is the following: 1. The kernel notices that the DP-MST port is gone. 2. The kernel marks the connector as disconnected, then sends a uevent to make user-space re-scan the connector list. 3. User-space notices the connector goes from connected to disconnected, disables it. 4. Kernel handles the IOCTL disabling the connector. On success, the very last reference to the struct drm_connector is dropped and drm_connector_cleanup() is called. 5. The connector is removed from the list, and a uevent is sent to tell user-space that the connector disappeared. The very last step was missing. As a result, user-space thought the connector still existed and could try to disable it again. Since the kernel no longer knows about the connector, that would end up with EINVAL and confused user-space. Fix this by sending a hotplug uevent from drm_connector_cleanup(). Signed-off-by: Simon Ser Cc: stable@vger.kernel.org Cc: Daniel Vetter Cc: Lyude Paul Cc: Jonas Ådahl Tested-by: Jonas Ådahl Reviewed-by: Lyude Paul Link: https://patchwork.freedesktop.org/patch/msgid/20221017153150.60675-2-contact@emersion.fr --- drivers/gpu/drm/drm_connector.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index e3142c8142b3..90dad87e9ad0 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -582,6 +582,9 @@ void drm_connector_cleanup(struct drm_connector *connector) mutex_destroy(&connector->mutex); memset(connector, 0, sizeof(*connector)); + + if (dev->registered) + drm_sysfs_hotplug_event(dev); } EXPORT_SYMBOL(drm_connector_cleanup); -- cgit From 977d97f18b5b8efb7a94da84724113f15ae6cc2d Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Mon, 24 Oct 2022 17:26:34 -0400 Subject: drm/scheduler: Set the FIFO scheduling policy as the default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The currently default Round-Robin GPU scheduling can result in starvation of entities which have a large number of jobs, over entities which have a very small number of jobs (single digit). This can be illustrated in the following diagram, where jobs are alphabetized to show their chronological order of arrival, where job A is the oldest, B is the second oldest, and so on, to J, the most recent job to arrive. ---> entities j | H-F-----A--E--I-- o | --G-----B-----J-- b | --------C-------- s\/ --------D-------- WLOG, assuming all jobs are "ready", then a R-R scheduling will execute them in the following order (a slice off of the top of the entities' list), H, F, A, E, I, G, B, J, C, D. However, to mitigate job starvation, we'd rather execute C and D before E, and so on, given, of course, that they're all ready to be executed. So, if all jobs are ready at this instant, the order of execution for this and the next 9 instances of picking the next job to execute, should really be, A, B, C, D, E, F, G, H, I, J, which is their chronological order. The only reason for this order to be broken, is if an older job is not yet ready, but a younger job is ready, at an instant of picking a new job to execute. For instance if job C wasn't ready at time 2, but job D was ready, then we'd pick job D, like this: 0 +1 +2 ... A, B, D, ... And from then on, C would be preferred before all other jobs, if it is ready at the time when a new job for execution is picked. So, if C became ready two steps later, the execution order would look like this: ......0 +1 +2 ... A, B, D, E, C, F, G, H, I, J This is what the FIFO GPU scheduling algorithm achieves. It uses a Red-Black tree to keep jobs sorted in chronological order, where picking the oldest job is O(1) (we use the "cached" structure), and balancing the tree is O(log n). IOW, it picks the *oldest ready* job to execute now. The implementation is already in the kernel, and this commit only changes the default GPU scheduling algorithm to use. This was tested and achieves about 1% faster performance over the Round Robin algorithm. Cc: Christian König Cc: Alex Deucher Cc: Direct Rendering Infrastructure - Development Signed-off-by: Luben Tuikov Reviewed-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20221024212634.27230-1-luben.tuikov@amd.com Signed-off-by: Christian König --- drivers/gpu/drm/scheduler/sched_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index 2fab218d7082..d0ff9e11cb69 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -62,13 +62,13 @@ #define to_drm_sched_job(sched_job) \ container_of((sched_job), struct drm_sched_job, queue_node) -int drm_sched_policy = DRM_SCHED_POLICY_RR; +int drm_sched_policy = DRM_SCHED_POLICY_FIFO; /** * DOC: sched_policy (int) * Used to override default entities scheduling policy in a run queue. */ -MODULE_PARM_DESC(sched_policy, "Specify schedule policy for entities on a runqueue, " __stringify(DRM_SCHED_POLICY_RR) " = Round Robin (default), " __stringify(DRM_SCHED_POLICY_FIFO) " = use FIFO."); +MODULE_PARM_DESC(sched_policy, "Specify the scheduling policy for entities on a run-queue, " __stringify(DRM_SCHED_POLICY_RR) " = Round Robin, " __stringify(DRM_SCHED_POLICY_FIFO) " = FIFO (default)."); module_param_named(sched_policy, drm_sched_policy, int, 0444); static __always_inline bool drm_sched_entity_compare_before(struct rb_node *a, -- cgit From 7f4c33778686cc2d34cb4ef65b4265eea874c159 Mon Sep 17 00:00:00 2001 From: Zack Rusin Date: Sat, 22 Oct 2022 00:02:20 -0400 Subject: drm/vmwgfx: Write the driver id registers Driver id registers are a new mechanism in the svga device to hint to the device which driver is running. This should not change device behavior in any way, but might be convenient to work-around specific bugs in guest drivers. Signed-off-by: Zack Rusin Reviewed-by: Martin Krastev Reviewed-by: Maaz Mombasawala Link: https://patchwork.freedesktop.org/patch/msgid/20221022040236.616490-2-zack@kde.org --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 43 +++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index d7bd5eb1d3ac..45028e25d490 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -25,10 +25,13 @@ * **************************************************************************/ -#include -#include -#include -#include + +#include "vmwgfx_drv.h" + +#include "vmwgfx_devcaps.h" +#include "vmwgfx_mksstat.h" +#include "vmwgfx_binding.h" +#include "ttm_object.h" #include #include @@ -41,11 +44,11 @@ #include #include -#include "ttm_object.h" -#include "vmwgfx_binding.h" -#include "vmwgfx_devcaps.h" -#include "vmwgfx_drv.h" -#include "vmwgfx_mksstat.h" +#include +#include +#include +#include +#include #define VMWGFX_DRIVER_DESC "Linux drm driver for VMware graphics devices" @@ -806,6 +809,27 @@ static int vmw_detect_version(struct vmw_private *dev) return 0; } +static void vmw_write_driver_id(struct vmw_private *dev) +{ + if ((dev->capabilities2 & SVGA_CAP2_DX2) != 0) { + vmw_write(dev, SVGA_REG_GUEST_DRIVER_ID, + SVGA_REG_GUEST_DRIVER_ID_LINUX); + + vmw_write(dev, SVGA_REG_GUEST_DRIVER_VERSION1, + LINUX_VERSION_MAJOR << 24 | + LINUX_VERSION_PATCHLEVEL << 16 | + LINUX_VERSION_SUBLEVEL); + vmw_write(dev, SVGA_REG_GUEST_DRIVER_VERSION2, + VMWGFX_DRIVER_MAJOR << 24 | + VMWGFX_DRIVER_MINOR << 16 | + VMWGFX_DRIVER_PATCHLEVEL); + vmw_write(dev, SVGA_REG_GUEST_DRIVER_VERSION3, 0); + + vmw_write(dev, SVGA_REG_GUEST_DRIVER_ID, + SVGA_REG_GUEST_DRIVER_ID_SUBMIT); + } +} + static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) { int ret; @@ -1091,6 +1115,7 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) vmw_host_printf("vmwgfx: Module Version: %d.%d.%d (kernel: %s)", VMWGFX_DRIVER_MAJOR, VMWGFX_DRIVER_MINOR, VMWGFX_DRIVER_PATCHLEVEL, UTS_RELEASE); + vmw_write_driver_id(dev_priv); if (dev_priv->enable_fb) { vmw_fifo_resource_inc(dev_priv); -- cgit From 3280706369f636cc6fc959a9842df5707c7fd85f Mon Sep 17 00:00:00 2001 From: Martin Krastev Date: Sat, 22 Oct 2022 00:02:21 -0400 Subject: drm/vmwgfx: Fix frame-size warning in vmw_mksstat_add_ioctl Function vmw_mksstat_add_ioctl allocates three big arrays on stack. That triggers frame-size [-Wframe-larger-than=] warning. Refactor that function to use kmalloc_array instead. v2: Initialize page to null to avoid possible uninitialized use of it, spotted by the kernel test robot Signed-off-by: Martin Krastev Reviewed-by: Zack Rusin Reviewed-by: Maaz Mombasawala Signed-off-by: Zack Rusin Link: https://patchwork.freedesktop.org/patch/msgid/20221022040236.616490-3-zack@kde.org --- drivers/gpu/drm/vmwgfx/vmwgfx_msg.c | 43 +++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c index 089046fa21be..50d8b9bcd72a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c @@ -1014,8 +1014,6 @@ int vmw_mksstat_add_ioctl(struct drm_device *dev, void *data, struct vmw_private *const dev_priv = vmw_priv(dev); - struct page *page; - MKSGuestStatInstanceDescriptor *pdesc; const size_t num_pages_stat = PFN_UP(arg->stat_len); const size_t num_pages_info = PFN_UP(arg->info_len); const size_t num_pages_strs = PFN_UP(arg->strs_len); @@ -1023,10 +1021,13 @@ int vmw_mksstat_add_ioctl(struct drm_device *dev, void *data, long nr_pinned_stat; long nr_pinned_info; long nr_pinned_strs; - struct page *pages_stat[ARRAY_SIZE(pdesc->statPPNs)]; - struct page *pages_info[ARRAY_SIZE(pdesc->infoPPNs)]; - struct page *pages_strs[ARRAY_SIZE(pdesc->strsPPNs)]; + MKSGuestStatInstanceDescriptor *pdesc; + struct page *page = NULL; + struct page **pages_stat = NULL; + struct page **pages_info = NULL; + struct page **pages_strs = NULL; size_t i, slot; + int ret_err = -ENOMEM; arg->id = -1; @@ -1054,13 +1055,23 @@ int vmw_mksstat_add_ioctl(struct drm_device *dev, void *data, BUG_ON(dev_priv->mksstat_user_pages[slot]); + /* Allocate statically-sized temp arrays for pages -- too big to keep in frame */ + pages_stat = (struct page **)kmalloc_array( + ARRAY_SIZE(pdesc->statPPNs) + + ARRAY_SIZE(pdesc->infoPPNs) + + ARRAY_SIZE(pdesc->strsPPNs), sizeof(*pages_stat), GFP_KERNEL); + + if (!pages_stat) + goto err_nomem; + + pages_info = pages_stat + ARRAY_SIZE(pdesc->statPPNs); + pages_strs = pages_info + ARRAY_SIZE(pdesc->infoPPNs); + /* Allocate a page for the instance descriptor */ page = alloc_page(GFP_KERNEL | __GFP_ZERO); - if (!page) { - atomic_set(&dev_priv->mksstat_user_pids[slot], 0); - return -ENOMEM; - } + if (!page) + goto err_nomem; /* Set up the instance descriptor */ pdesc = page_address(page); @@ -1075,9 +1086,8 @@ int vmw_mksstat_add_ioctl(struct drm_device *dev, void *data, ARRAY_SIZE(pdesc->description) - 1); if (desc_len < 0) { - atomic_set(&dev_priv->mksstat_user_pids[slot], 0); - __free_page(page); - return -EFAULT; + ret_err = -EFAULT; + goto err_nomem; } reset_ppn_array(pdesc->statPPNs, ARRAY_SIZE(pdesc->statPPNs)); @@ -1118,6 +1128,7 @@ int vmw_mksstat_add_ioctl(struct drm_device *dev, void *data, DRM_DEV_INFO(dev->dev, "pid=%d arg.description='%.*s' id=%zu\n", current->pid, (int)desc_len, pdesc->description, slot); + kfree(pages_stat); return 0; err_pin_strs: @@ -1132,9 +1143,13 @@ err_pin_stat: if (nr_pinned_stat > 0) unpin_user_pages(pages_stat, nr_pinned_stat); +err_nomem: atomic_set(&dev_priv->mksstat_user_pids[slot], 0); - __free_page(page); - return -ENOMEM; + if (page) + __free_page(page); + kfree(pages_stat); + + return ret_err; } /** -- cgit From 43531dc661b7fb6be249c023bf25847b38215545 Mon Sep 17 00:00:00 2001 From: Maaz Mombasawala Date: Sat, 22 Oct 2022 00:02:22 -0400 Subject: drm/vmwgfx: Refactor resource manager's hashtable to use linux/hashtable implementation. Vmwgfx's hashtab implementation needs to be replaced with linux/hashtable to reduce maintenance burden. Refactor cmdbuf resource manager to use linux/hashtable.h implementation as part of this effort. Signed-off-by: Maaz Mombasawala Reviewed-by: Zack Rusin Reviewed-by: Martin Krastev Signed-off-by: Zack Rusin Link: https://patchwork.freedesktop.org/patch/msgid/20221022040236.616490-4-zack@kde.org --- drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c | 62 +++++++++++++----------------- 1 file changed, 26 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c index 82ef58ccdd42..142aef686fcd 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright 2014-2015 VMware, Inc., Palo Alto, CA., USA + * Copyright 2014-2022 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the @@ -28,6 +28,8 @@ #include "vmwgfx_drv.h" #include "vmwgfx_resource_priv.h" +#include + #define VMW_CMDBUF_RES_MAN_HT_ORDER 12 /** @@ -59,7 +61,7 @@ struct vmw_cmdbuf_res { * @resources and @list are protected by the cmdbuf mutex for now. */ struct vmw_cmdbuf_res_manager { - struct vmwgfx_open_hash resources; + DECLARE_HASHTABLE(resources, VMW_CMDBUF_RES_MAN_HT_ORDER); struct list_head list; struct vmw_private *dev_priv; }; @@ -82,14 +84,13 @@ vmw_cmdbuf_res_lookup(struct vmw_cmdbuf_res_manager *man, u32 user_key) { struct vmwgfx_hash_item *hash; - int ret; unsigned long key = user_key | (res_type << 24); - ret = vmwgfx_ht_find_item(&man->resources, key, &hash); - if (unlikely(ret != 0)) - return ERR_PTR(ret); - - return drm_hash_entry(hash, struct vmw_cmdbuf_res, hash)->res; + hash_for_each_possible_rcu(man->resources, hash, head, key) { + if (hash->key == key) + return drm_hash_entry(hash, struct vmw_cmdbuf_res, hash)->res; + } + return ERR_PTR(-EINVAL); } /** @@ -105,7 +106,7 @@ static void vmw_cmdbuf_res_free(struct vmw_cmdbuf_res_manager *man, struct vmw_cmdbuf_res *entry) { list_del(&entry->head); - WARN_ON(vmwgfx_ht_remove_item(&man->resources, &entry->hash)); + hash_del_rcu(&entry->hash.head); vmw_resource_unreference(&entry->res); kfree(entry); } @@ -159,7 +160,6 @@ void vmw_cmdbuf_res_commit(struct list_head *list) void vmw_cmdbuf_res_revert(struct list_head *list) { struct vmw_cmdbuf_res *entry, *next; - int ret; list_for_each_entry_safe(entry, next, list, head) { switch (entry->state) { @@ -167,8 +167,8 @@ void vmw_cmdbuf_res_revert(struct list_head *list) vmw_cmdbuf_res_free(entry->man, entry); break; case VMW_CMDBUF_RES_DEL: - ret = vmwgfx_ht_insert_item(&entry->man->resources, &entry->hash); - BUG_ON(ret); + hash_add_rcu(entry->man->resources, &entry->hash.head, + entry->hash.key); list_move_tail(&entry->head, &entry->man->list); entry->state = VMW_CMDBUF_RES_COMMITTED; break; @@ -199,26 +199,20 @@ int vmw_cmdbuf_res_add(struct vmw_cmdbuf_res_manager *man, struct list_head *list) { struct vmw_cmdbuf_res *cres; - int ret; cres = kzalloc(sizeof(*cres), GFP_KERNEL); if (unlikely(!cres)) return -ENOMEM; cres->hash.key = user_key | (res_type << 24); - ret = vmwgfx_ht_insert_item(&man->resources, &cres->hash); - if (unlikely(ret != 0)) { - kfree(cres); - goto out_invalid_key; - } + hash_add_rcu(man->resources, &cres->hash.head, cres->hash.key); cres->state = VMW_CMDBUF_RES_ADD; cres->res = vmw_resource_reference(res); cres->man = man; list_add_tail(&cres->head, list); -out_invalid_key: - return ret; + return 0; } /** @@ -243,24 +237,26 @@ int vmw_cmdbuf_res_remove(struct vmw_cmdbuf_res_manager *man, struct list_head *list, struct vmw_resource **res_p) { - struct vmw_cmdbuf_res *entry; + struct vmw_cmdbuf_res *entry = NULL; struct vmwgfx_hash_item *hash; - int ret; + unsigned long key = user_key | (res_type << 24); - ret = vmwgfx_ht_find_item(&man->resources, user_key | (res_type << 24), - &hash); - if (likely(ret != 0)) + hash_for_each_possible_rcu(man->resources, hash, head, key) { + if (hash->key == key) { + entry = drm_hash_entry(hash, struct vmw_cmdbuf_res, hash); + break; + } + } + if (unlikely(!entry)) return -EINVAL; - entry = drm_hash_entry(hash, struct vmw_cmdbuf_res, hash); - switch (entry->state) { case VMW_CMDBUF_RES_ADD: vmw_cmdbuf_res_free(man, entry); *res_p = NULL; break; case VMW_CMDBUF_RES_COMMITTED: - (void) vmwgfx_ht_remove_item(&man->resources, &entry->hash); + hash_del_rcu(&entry->hash.head); list_del(&entry->head); entry->state = VMW_CMDBUF_RES_DEL; list_add_tail(&entry->head, list); @@ -287,7 +283,6 @@ struct vmw_cmdbuf_res_manager * vmw_cmdbuf_res_man_create(struct vmw_private *dev_priv) { struct vmw_cmdbuf_res_manager *man; - int ret; man = kzalloc(sizeof(*man), GFP_KERNEL); if (!man) @@ -295,12 +290,8 @@ vmw_cmdbuf_res_man_create(struct vmw_private *dev_priv) man->dev_priv = dev_priv; INIT_LIST_HEAD(&man->list); - ret = vmwgfx_ht_create(&man->resources, VMW_CMDBUF_RES_MAN_HT_ORDER); - if (ret == 0) - return man; - - kfree(man); - return ERR_PTR(ret); + hash_init(man->resources); + return man; } /** @@ -320,7 +311,6 @@ void vmw_cmdbuf_res_man_destroy(struct vmw_cmdbuf_res_manager *man) list_for_each_entry_safe(entry, next, &man->list, head) vmw_cmdbuf_res_free(man, entry); - vmwgfx_ht_remove(&man->resources); kfree(man); } -- cgit From 931e09d8d5b4aa19bdae0234f2727049f1cd13d9 Mon Sep 17 00:00:00 2001 From: Maaz Mombasawala Date: Sat, 22 Oct 2022 00:02:23 -0400 Subject: drm/vmwgfx: Remove ttm object hashtable The object_hash hashtable for ttm objects is not being used. Remove it and perform refactoring in ttm_object init function. Signed-off-by: Maaz Mombasawala Reviewed-by: Zack Rusin Reviewed-by: Martin Krastev Signed-off-by: Zack Rusin Link: https://patchwork.freedesktop.org/patch/msgid/20221022040236.616490-5-zack@kde.org --- drivers/gpu/drm/vmwgfx/ttm_object.c | 24 ++++++------------------ drivers/gpu/drm/vmwgfx/ttm_object.h | 6 ++---- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 2 +- 3 files changed, 9 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/ttm_object.c b/drivers/gpu/drm/vmwgfx/ttm_object.c index 26a55fef1ab5..9546b121bc22 100644 --- a/drivers/gpu/drm/vmwgfx/ttm_object.c +++ b/drivers/gpu/drm/vmwgfx/ttm_object.c @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 OR MIT */ /************************************************************************** * - * Copyright (c) 2009-2013 VMware, Inc., Palo Alto, CA., USA + * Copyright (c) 2009-2022 VMware, Inc., Palo Alto, CA., USA * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -44,13 +44,14 @@ #define pr_fmt(fmt) "[TTM] " fmt +#include "ttm_object.h" +#include "vmwgfx_drv.h" + #include #include #include #include #include -#include "ttm_object.h" -#include "vmwgfx_drv.h" MODULE_IMPORT_NS(DMA_BUF); @@ -81,9 +82,7 @@ struct ttm_object_file { /* * struct ttm_object_device * - * @object_lock: lock that protects the object_hash hash table. - * - * @object_hash: hash table for fast lookup of object global names. + * @object_lock: lock that protects idr. * * @object_count: Per device object count. * @@ -92,7 +91,6 @@ struct ttm_object_file { struct ttm_object_device { spinlock_t object_lock; - struct vmwgfx_open_hash object_hash; atomic_t object_count; struct dma_buf_ops ops; void (*dmabuf_release)(struct dma_buf *dma_buf); @@ -449,20 +447,15 @@ out_err: } struct ttm_object_device * -ttm_object_device_init(unsigned int hash_order, - const struct dma_buf_ops *ops) +ttm_object_device_init(const struct dma_buf_ops *ops) { struct ttm_object_device *tdev = kmalloc(sizeof(*tdev), GFP_KERNEL); - int ret; if (unlikely(tdev == NULL)) return NULL; spin_lock_init(&tdev->object_lock); atomic_set(&tdev->object_count, 0); - ret = vmwgfx_ht_create(&tdev->object_hash, hash_order); - if (ret != 0) - goto out_no_object_hash; /* * Our base is at VMWGFX_NUM_MOB + 1 because we want to create @@ -477,10 +470,6 @@ ttm_object_device_init(unsigned int hash_order, tdev->dmabuf_release = tdev->ops.release; tdev->ops.release = ttm_prime_dmabuf_release; return tdev; - -out_no_object_hash: - kfree(tdev); - return NULL; } void ttm_object_device_release(struct ttm_object_device **p_tdev) @@ -491,7 +480,6 @@ void ttm_object_device_release(struct ttm_object_device **p_tdev) WARN_ON_ONCE(!idr_is_empty(&tdev->idr)); idr_destroy(&tdev->idr); - vmwgfx_ht_remove(&tdev->object_hash); kfree(tdev); } diff --git a/drivers/gpu/drm/vmwgfx/ttm_object.h b/drivers/gpu/drm/vmwgfx/ttm_object.h index 1a2fa0f83f5f..6870f951b677 100644 --- a/drivers/gpu/drm/vmwgfx/ttm_object.h +++ b/drivers/gpu/drm/vmwgfx/ttm_object.h @@ -1,6 +1,6 @@ /************************************************************************** * - * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA + * Copyright (c) 2006-2022 VMware, Inc., Palo Alto, CA., USA * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -262,7 +262,6 @@ extern void ttm_object_file_release(struct ttm_object_file **p_tfile); /** * ttm_object device init - initialize a struct ttm_object_device * - * @hash_order: Order of hash table used to hash the base objects. * @ops: DMA buf ops for prime objects of this device. * * This function is typically called on device initialization to prepare @@ -270,8 +269,7 @@ extern void ttm_object_file_release(struct ttm_object_file **p_tfile); */ extern struct ttm_object_device * -ttm_object_device_init(unsigned int hash_order, - const struct dma_buf_ops *ops); +ttm_object_device_init(const struct dma_buf_ops *ops); /** * ttm_object_device_release - release data held by a ttm_object_device diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 45028e25d490..13b90273eb77 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -994,7 +994,7 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) goto out_err0; } - dev_priv->tdev = ttm_object_device_init(12, &vmw_prime_dmabuf_ops); + dev_priv->tdev = ttm_object_device_init(&vmw_prime_dmabuf_ops); if (unlikely(dev_priv->tdev == NULL)) { drm_err(&dev_priv->drm, -- cgit From 9e931f2e09701e25744f3d186a4ba13b5342b136 Mon Sep 17 00:00:00 2001 From: Maaz Mombasawala Date: Sat, 22 Oct 2022 00:02:24 -0400 Subject: drm/vmwgfx: Refactor resource validation hashtable to use linux/hashtable implementation. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Vmwgfx's hashtab implementation needs to be replaced with linux/hashtable to reduce maintenence burden. As part of this effort, refactor the res_ht hashtable used for resource validation during execbuf execution to use linux/hashtable implementation. This also refactors vmw_validation_context to use vmw_sw_context as the container for the hashtable, whereas before it used a vmwgfx_open_hash directly. This makes vmw_validation_context less generic, but there is no functional change since res_ht is the only instance where validation context used a hashtable in vmwgfx driver. Signed-off-by: Maaz Mombasawala Reviewed-by: Thomas Hellström Signed-off-by: Zack Rusin Link: https://patchwork.freedesktop.org/patch/msgid/20221022040236.616490-6-zack@kde.org --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 24 ++++++++++--- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 5 +-- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 14 ++------ drivers/gpu/drm/vmwgfx/vmwgfx_validation.c | 55 +++++++++++++++--------------- drivers/gpu/drm/vmwgfx/vmwgfx_validation.h | 26 ++++---------- 5 files changed, 58 insertions(+), 66 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 13b90273eb77..8d77e79bd904 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -830,6 +830,22 @@ static void vmw_write_driver_id(struct vmw_private *dev) } } +static void vmw_sw_context_init(struct vmw_private *dev_priv) +{ + struct vmw_sw_context *sw_context = &dev_priv->ctx; + + hash_init(sw_context->res_ht); +} + +static void vmw_sw_context_fini(struct vmw_private *dev_priv) +{ + struct vmw_sw_context *sw_context = &dev_priv->ctx; + + vfree(sw_context->cmd_bounce); + if (sw_context->staged_bindings) + vmw_binding_state_free(sw_context->staged_bindings); +} + static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) { int ret; @@ -839,6 +855,8 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) dev_priv->drm.dev_private = dev_priv; + vmw_sw_context_init(dev_priv); + mutex_init(&dev_priv->cmdbuf_mutex); mutex_init(&dev_priv->binding_mutex); spin_lock_init(&dev_priv->resource_lock); @@ -1168,9 +1186,7 @@ static void vmw_driver_unload(struct drm_device *dev) unregister_pm_notifier(&dev_priv->pm_nb); - if (dev_priv->ctx.res_ht_initialized) - vmwgfx_ht_remove(&dev_priv->ctx.res_ht); - vfree(dev_priv->ctx.cmd_bounce); + vmw_sw_context_fini(dev_priv); if (dev_priv->enable_fb) { vmw_fb_off(dev_priv); vmw_fb_close(dev_priv); @@ -1198,8 +1214,6 @@ static void vmw_driver_unload(struct drm_device *dev) vmw_irq_uninstall(&dev_priv->drm); ttm_object_device_release(&dev_priv->tdev); - if (dev_priv->ctx.staged_bindings) - vmw_binding_state_free(dev_priv->ctx.staged_bindings); for (i = vmw_res_context; i < vmw_res_max; ++i) idr_destroy(&dev_priv->res_idr[i]); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 09e2d738aa87..d87aeedb78d0 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -93,6 +94,7 @@ #define VMW_RES_STREAM ttm_driver_type2 #define VMW_RES_FENCE ttm_driver_type3 #define VMW_RES_SHADER ttm_driver_type4 +#define VMW_RES_HT_ORDER 12 #define MKSSTAT_CAPACITY_LOG2 5U #define MKSSTAT_CAPACITY (1U << MKSSTAT_CAPACITY_LOG2) @@ -425,8 +427,7 @@ struct vmw_ctx_validation_info; * @ctx: The validation context */ struct vmw_sw_context{ - struct vmwgfx_open_hash res_ht; - bool res_ht_initialized; + DECLARE_HASHTABLE(res_ht, VMW_RES_HT_ORDER); bool kernel; struct vmw_fpriv *fp; struct drm_file *filp; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index f085dbd4736d..c943ab801ca7 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright 2009 - 2015 VMware, Inc., Palo Alto, CA., USA + * Copyright 2009 - 2022 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the @@ -25,6 +25,7 @@ * **************************************************************************/ #include +#include #include "vmwgfx_drv.h" #include "vmwgfx_reg.h" @@ -34,7 +35,6 @@ #include "vmwgfx_binding.h" #include "vmwgfx_mksstat.h" -#define VMW_RES_HT_ORDER 12 /* * Helper macro to get dx_ctx_node if available otherwise print an error @@ -4101,7 +4101,7 @@ int vmw_execbuf_process(struct drm_file *file_priv, int ret; int32_t out_fence_fd = -1; struct sync_file *sync_file = NULL; - DECLARE_VAL_CONTEXT(val_ctx, &sw_context->res_ht, 1); + DECLARE_VAL_CONTEXT(val_ctx, sw_context, 1); if (flags & DRM_VMW_EXECBUF_FLAG_EXPORT_FENCE_FD) { out_fence_fd = get_unused_fd_flags(O_CLOEXEC); @@ -4164,14 +4164,6 @@ int vmw_execbuf_process(struct drm_file *file_priv, if (sw_context->staged_bindings) vmw_binding_state_reset(sw_context->staged_bindings); - if (!sw_context->res_ht_initialized) { - ret = vmwgfx_ht_create(&sw_context->res_ht, VMW_RES_HT_ORDER); - if (unlikely(ret != 0)) - goto out_unlock; - - sw_context->res_ht_initialized = true; - } - INIT_LIST_HEAD(&sw_context->staged_cmd_res); sw_context->ctx = &val_ctx; ret = vmw_execbuf_tie_context(dev_priv, sw_context, dx_context_handle); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c b/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c index f46891012be3..f5c4a40fb16d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_validation.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright © 2018 VMware, Inc., Palo Alto, CA., USA + * Copyright © 2018 - 2022 VMware, Inc., Palo Alto, CA., USA * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -180,11 +180,16 @@ vmw_validation_find_bo_dup(struct vmw_validation_context *ctx, if (!ctx->merge_dups) return NULL; - if (ctx->ht) { + if (ctx->sw_context) { struct vmwgfx_hash_item *hash; + unsigned long key = (unsigned long) vbo; - if (!vmwgfx_ht_find_item(ctx->ht, (unsigned long) vbo, &hash)) - bo_node = container_of(hash, typeof(*bo_node), hash); + hash_for_each_possible_rcu(ctx->sw_context->res_ht, hash, head, key) { + if (hash->key == key) { + bo_node = container_of(hash, typeof(*bo_node), hash); + break; + } + } } else { struct vmw_validation_bo_node *entry; @@ -217,11 +222,16 @@ vmw_validation_find_res_dup(struct vmw_validation_context *ctx, if (!ctx->merge_dups) return NULL; - if (ctx->ht) { + if (ctx->sw_context) { struct vmwgfx_hash_item *hash; + unsigned long key = (unsigned long) res; - if (!vmwgfx_ht_find_item(ctx->ht, (unsigned long) res, &hash)) - res_node = container_of(hash, typeof(*res_node), hash); + hash_for_each_possible_rcu(ctx->sw_context->res_ht, hash, head, key) { + if (hash->key == key) { + res_node = container_of(hash, typeof(*res_node), hash); + break; + } + } } else { struct vmw_validation_res_node *entry; @@ -269,20 +279,15 @@ int vmw_validation_add_bo(struct vmw_validation_context *ctx, } } else { struct ttm_validate_buffer *val_buf; - int ret; bo_node = vmw_validation_mem_alloc(ctx, sizeof(*bo_node)); if (!bo_node) return -ENOMEM; - if (ctx->ht) { + if (ctx->sw_context) { bo_node->hash.key = (unsigned long) vbo; - ret = vmwgfx_ht_insert_item(ctx->ht, &bo_node->hash); - if (ret) { - DRM_ERROR("Failed to initialize a buffer " - "validation entry.\n"); - return ret; - } + hash_add_rcu(ctx->sw_context->res_ht, &bo_node->hash.head, + bo_node->hash.key); } val_buf = &bo_node->base; val_buf->bo = ttm_bo_get_unless_zero(&vbo->base); @@ -316,7 +321,6 @@ int vmw_validation_add_resource(struct vmw_validation_context *ctx, bool *first_usage) { struct vmw_validation_res_node *node; - int ret; node = vmw_validation_find_res_dup(ctx, res); if (node) { @@ -330,14 +334,9 @@ int vmw_validation_add_resource(struct vmw_validation_context *ctx, return -ENOMEM; } - if (ctx->ht) { + if (ctx->sw_context) { node->hash.key = (unsigned long) res; - ret = vmwgfx_ht_insert_item(ctx->ht, &node->hash); - if (ret) { - DRM_ERROR("Failed to initialize a resource validation " - "entry.\n"); - return ret; - } + hash_add_rcu(ctx->sw_context->res_ht, &node->hash.head, node->hash.key); } node->res = vmw_resource_reference_unless_doomed(res); if (!node->res) @@ -681,19 +680,19 @@ void vmw_validation_drop_ht(struct vmw_validation_context *ctx) struct vmw_validation_bo_node *entry; struct vmw_validation_res_node *val; - if (!ctx->ht) + if (!ctx->sw_context) return; list_for_each_entry(entry, &ctx->bo_list, base.head) - (void) vmwgfx_ht_remove_item(ctx->ht, &entry->hash); + hash_del_rcu(&entry->hash.head); list_for_each_entry(val, &ctx->resource_list, head) - (void) vmwgfx_ht_remove_item(ctx->ht, &val->hash); + hash_del_rcu(&val->hash.head); list_for_each_entry(val, &ctx->resource_ctx_list, head) - (void) vmwgfx_ht_remove_item(ctx->ht, &val->hash); + hash_del_rcu(&entry->hash.head); - ctx->ht = NULL; + ctx->sw_context = NULL; } /** diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_validation.h b/drivers/gpu/drm/vmwgfx/vmwgfx_validation.h index f21df053882b..ab9ec226f433 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_validation.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_validation.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 OR MIT */ /************************************************************************** * - * Copyright © 2018 VMware, Inc., Palo Alto, CA., USA + * Copyright © 2018 - 2022 VMware, Inc., Palo Alto, CA., USA * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -29,12 +29,11 @@ #define _VMWGFX_VALIDATION_H_ #include +#include #include #include -#include "vmwgfx_hashtab.h" - #define VMW_RES_DIRTY_NONE 0 #define VMW_RES_DIRTY_SET BIT(0) #define VMW_RES_DIRTY_CLEAR BIT(1) @@ -59,7 +58,7 @@ * @total_mem: Amount of reserved memory. */ struct vmw_validation_context { - struct vmwgfx_open_hash *ht; + struct vmw_sw_context *sw_context; struct list_head resource_list; struct list_head resource_ctx_list; struct list_head bo_list; @@ -82,16 +81,16 @@ struct vmw_fence_obj; /** * DECLARE_VAL_CONTEXT - Declare a validation context with initialization * @_name: The name of the variable - * @_ht: The hash table used to find dups or NULL if none + * @_sw_context: Contains the hash table used to find dups or NULL if none * @_merge_dups: Whether to merge duplicate buffer object- or resource * entries. If set to true, ideally a hash table pointer should be supplied * as well unless the number of resources and buffer objects per validation * is known to be very small */ #endif -#define DECLARE_VAL_CONTEXT(_name, _ht, _merge_dups) \ +#define DECLARE_VAL_CONTEXT(_name, _sw_context, _merge_dups) \ struct vmw_validation_context _name = \ - { .ht = _ht, \ + { .sw_context = _sw_context, \ .resource_list = LIST_HEAD_INIT((_name).resource_list), \ .resource_ctx_list = LIST_HEAD_INIT((_name).resource_ctx_list), \ .bo_list = LIST_HEAD_INIT((_name).bo_list), \ @@ -114,19 +113,6 @@ vmw_validation_has_bos(struct vmw_validation_context *ctx) return !list_empty(&ctx->bo_list); } -/** - * vmw_validation_set_ht - Register a hash table for duplicate finding - * @ctx: The validation context - * @ht: Pointer to a hash table to use for duplicate finding - * This function is intended to be used if the hash table wasn't - * available at validation context declaration time - */ -static inline void vmw_validation_set_ht(struct vmw_validation_context *ctx, - struct vmwgfx_open_hash *ht) -{ - ctx->ht = ht; -} - /** * vmw_validation_bo_reserve - Reserve buffer objects registered with a * validation context -- cgit From 53bc3f6fb6b3d401230bb2f8d3b6fe877c137b87 Mon Sep 17 00:00:00 2001 From: Michael Banack Date: Sat, 22 Oct 2022 00:02:25 -0400 Subject: drm/vmwgfx: Clean up cursor mobs Clean up the cursor mob path by moving ownership of the mobs into the plane_state, and just leaving a cache of unused mobs in the plane itself. Signed-off-by: Michael Banack Signed-off-by: Zack Rusin Link: https://patchwork.freedesktop.org/patch/msgid/20221022040236.616490-7-zack@kde.org --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 441 +++++++++++++++++++++--------------- drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 19 +- 2 files changed, 267 insertions(+), 193 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 214829c32ed8..07d55d610e4c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -53,33 +53,33 @@ void vmw_du_cleanup(struct vmw_display_unit *du) */ static void vmw_cursor_update_mob(struct vmw_private *dev_priv, - struct ttm_buffer_object *bo, - struct ttm_bo_kmap_obj *map, + struct vmw_plane_state *vps, u32 *image, u32 width, u32 height, u32 hotspotX, u32 hotspotY); +static int vmw_du_cursor_plane_unmap_cm(struct vmw_plane_state *vps); struct vmw_svga_fifo_cmd_define_cursor { u32 cmd; SVGAFifoCmdDefineAlphaCursor cursor; }; -static void vmw_cursor_update_image(struct vmw_private *dev_priv, - struct ttm_buffer_object *cm_bo, - struct ttm_bo_kmap_obj *cm_map, - u32 *image, u32 width, u32 height, - u32 hotspotX, u32 hotspotY) +/** + * vmw_send_define_cursor_cmd - queue a define cursor command + * @dev_priv: the private driver struct + * @image: buffer which holds the cursor image + * @width: width of the mouse cursor image + * @height: height of the mouse cursor image + * @hotspotX: the horizontal position of mouse hotspot + * @hotspotY: the vertical position of mouse hotspot + */ +static void vmw_send_define_cursor_cmd(struct vmw_private *dev_priv, + u32 *image, u32 width, u32 height, + u32 hotspotX, u32 hotspotY) { struct vmw_svga_fifo_cmd_define_cursor *cmd; const u32 image_size = width * height * sizeof(*image); const u32 cmd_size = sizeof(*cmd) + image_size; - if (cm_bo != NULL) { - vmw_cursor_update_mob(dev_priv, cm_bo, cm_map, image, - width, height, - hotspotX, hotspotY); - return; - } - /* Try to reserve fifocmd space and swallow any failures; such reservations cannot be left unconsumed for long under the risk of clogging other fifocmd users, so @@ -104,12 +104,39 @@ static void vmw_cursor_update_image(struct vmw_private *dev_priv, vmw_cmd_commit_flush(dev_priv, cmd_size); } +/** + * vmw_cursor_update_image - update the cursor image on the provided plane + * @dev_priv: the private driver struct + * @vps: the plane state of the cursor plane + * @image: buffer which holds the cursor image + * @width: width of the mouse cursor image + * @height: height of the mouse cursor image + * @hotspotX: the horizontal position of mouse hotspot + * @hotspotY: the vertical position of mouse hotspot + */ +static void vmw_cursor_update_image(struct vmw_private *dev_priv, + struct vmw_plane_state *vps, + u32 *image, u32 width, u32 height, + u32 hotspotX, u32 hotspotY) +{ + if (vps->cursor.bo != NULL) + vmw_cursor_update_mob(dev_priv, vps, image, + width, height, + hotspotX, hotspotY); + else + vmw_send_define_cursor_cmd(dev_priv, image, width, height, + hotspotX, hotspotY); +} + + /** * vmw_cursor_update_mob - Update cursor vis CursorMob mechanism * + * Called from inside vmw_du_cursor_plane_atomic_update to actually + * make the cursor-image live. + * * @dev_priv: device to work with - * @bo: BO for the MOB - * @map: kmap obj for the BO + * @vps: the plane state of the cursor plane * @image: cursor source data to fill the MOB with * @width: source data width * @height: source data height @@ -117,8 +144,7 @@ static void vmw_cursor_update_image(struct vmw_private *dev_priv, * @hotspotY: cursor hotspot Y */ static void vmw_cursor_update_mob(struct vmw_private *dev_priv, - struct ttm_buffer_object *bo, - struct ttm_bo_kmap_obj *map, + struct vmw_plane_state *vps, u32 *image, u32 width, u32 height, u32 hotspotX, u32 hotspotY) { @@ -127,11 +153,11 @@ static void vmw_cursor_update_mob(struct vmw_private *dev_priv, const u32 image_size = width * height * sizeof(*image); bool dummy; - BUG_ON(!image); - - header = (SVGAGBCursorHeader *)ttm_kmap_obj_virtual(map, &dummy); + header = ttm_kmap_obj_virtual(&vps->cursor.map, &dummy); alpha_header = &header->header.alphaHeader; + memset(header, 0, sizeof(*header)); + header->type = SVGA_ALPHA_CURSOR; header->sizeInBytes = image_size; @@ -141,102 +167,116 @@ static void vmw_cursor_update_mob(struct vmw_private *dev_priv, alpha_header->height = height; memcpy(header + 1, image, image_size); + vmw_write(dev_priv, SVGA_REG_CURSOR_MOBID, + vps->cursor.bo->resource->start); +} - vmw_write(dev_priv, SVGA_REG_CURSOR_MOBID, bo->resource->start); +static u32 vmw_du_cursor_mob_size(u32 w, u32 h) +{ + return w * h * sizeof(u32) + sizeof(SVGAGBCursorHeader); } -void vmw_du_destroy_cursor_mob_array(struct vmw_cursor_plane *vcp) +static void vmw_du_destroy_cursor_mob(struct ttm_buffer_object **bo) { - size_t i; + if (*bo == NULL) + return; - for (i = 0; i < ARRAY_SIZE(vcp->cursor_mob); i++) { - if (vcp->cursor_mob[i] != NULL) { - ttm_bo_unpin(vcp->cursor_mob[i]); - ttm_bo_put(vcp->cursor_mob[i]); - kfree(vcp->cursor_mob[i]); - vcp->cursor_mob[i] = NULL; - } - } + ttm_bo_unpin(*bo); + ttm_bo_put(*bo); + kfree(*bo); + *bo = NULL; } -#define CURSOR_MOB_SIZE(dimension) \ - ((dimension) * (dimension) * sizeof(u32) + sizeof(SVGAGBCursorHeader)) - -int vmw_du_create_cursor_mob_array(struct vmw_cursor_plane *cursor) +static void vmw_du_put_cursor_mob(struct vmw_cursor_plane *vcp, + struct vmw_plane_state *vps) { - struct vmw_private *dev_priv = cursor->base.dev->dev_private; - uint32_t cursor_max_dim, mob_max_size; - int ret = 0; - size_t i; - - if (!dev_priv->has_mob || (dev_priv->capabilities2 & SVGA_CAP2_CURSOR_MOB) == 0) - return -ENOSYS; + u32 i; - mob_max_size = vmw_read(dev_priv, SVGA_REG_MOB_MAX_SIZE); - cursor_max_dim = vmw_read(dev_priv, SVGA_REG_CURSOR_MAX_DIMENSION); + if (vps->cursor.bo == NULL) + return; - if (CURSOR_MOB_SIZE(cursor_max_dim) > mob_max_size) - cursor_max_dim = 64; /* Mandatorily-supported cursor dimension */ + vmw_du_cursor_plane_unmap_cm(vps); - for (i = 0; i < ARRAY_SIZE(cursor->cursor_mob); i++) { - struct ttm_buffer_object **const bo = &cursor->cursor_mob[i]; + /* Look for a free slot to return this mob to the cache. */ + for (i = 0; i < ARRAY_SIZE(vcp->cursor_mobs); i++) { + if (vcp->cursor_mobs[i] == NULL) { + vcp->cursor_mobs[i] = vps->cursor.bo; + vps->cursor.bo = NULL; + return; + } + } - ret = vmw_bo_create_kernel(dev_priv, - CURSOR_MOB_SIZE(cursor_max_dim), - &vmw_mob_placement, bo); + /* Cache is full: See if this mob is bigger than an existing mob. */ + for (i = 0; i < ARRAY_SIZE(vcp->cursor_mobs); i++) { + if (vcp->cursor_mobs[i]->base.size < + vps->cursor.bo->base.size) { + vmw_du_destroy_cursor_mob(&vcp->cursor_mobs[i]); + vcp->cursor_mobs[i] = vps->cursor.bo; + vps->cursor.bo = NULL; + return; + } + } - if (ret != 0) - goto teardown; + /* Destroy it if it's not worth caching. */ + vmw_du_destroy_cursor_mob(&vps->cursor.bo); +} - if ((*bo)->resource->mem_type != VMW_PL_MOB) { - DRM_ERROR("Obtained buffer object is not a MOB.\n"); - ret = -ENOSYS; - goto teardown; - } +static int vmw_du_get_cursor_mob(struct vmw_cursor_plane *vcp, + struct vmw_plane_state *vps) +{ + struct vmw_private *dev_priv = vcp->base.dev->dev_private; + u32 size = vmw_du_cursor_mob_size(vps->base.crtc_w, vps->base.crtc_h); + u32 i; + u32 cursor_max_dim, mob_max_size; + int ret; - /* Fence the mob creation so we are guarateed to have the mob */ - ret = ttm_bo_reserve(*bo, false, false, NULL); + if (!dev_priv->has_mob || + (dev_priv->capabilities2 & SVGA_CAP2_CURSOR_MOB) == 0) + return -EINVAL; - if (ret != 0) - goto teardown; + mob_max_size = vmw_read(dev_priv, SVGA_REG_MOB_MAX_SIZE); + cursor_max_dim = vmw_read(dev_priv, SVGA_REG_CURSOR_MAX_DIMENSION); - vmw_bo_fence_single(*bo, NULL); + if (size > mob_max_size || vps->base.crtc_w > cursor_max_dim || + vps->base.crtc_h > cursor_max_dim) + return -EINVAL; - ttm_bo_unreserve(*bo); + if (vps->cursor.bo != NULL) { + if (vps->cursor.bo->base.size >= size) + return 0; + vmw_du_put_cursor_mob(vcp, vps); + } - drm_info(&dev_priv->drm, "Using CursorMob mobid %lu, max dimension %u\n", - (*bo)->resource->start, cursor_max_dim); + /* Look for an unused mob in the cache. */ + for (i = 0; i < ARRAY_SIZE(vcp->cursor_mobs); i++) { + if (vcp->cursor_mobs[i] != NULL && + vcp->cursor_mobs[i]->base.size >= size) { + vps->cursor.bo = vcp->cursor_mobs[i]; + vcp->cursor_mobs[i] = NULL; + return 0; + } } + /* Create a new mob if we can't find an existing one. */ + ret = vmw_bo_create_kernel(dev_priv, size, &vmw_mob_placement, + &vps->cursor.bo); + + if (ret != 0) + return ret; + + /* Fence the mob creation so we are guarateed to have the mob */ + ret = ttm_bo_reserve(vps->cursor.bo, false, false, NULL); + if (ret != 0) + goto teardown; + vmw_bo_fence_single(vps->cursor.bo, NULL); + ttm_bo_unreserve(vps->cursor.bo); return 0; teardown: - vmw_du_destroy_cursor_mob_array(cursor); - + vmw_du_destroy_cursor_mob(&vps->cursor.bo); return ret; } -#undef CURSOR_MOB_SIZE - -static void vmw_cursor_update_bo(struct vmw_private *dev_priv, - struct ttm_buffer_object *cm_bo, - struct ttm_bo_kmap_obj *cm_map, - struct vmw_buffer_object *bo, - u32 width, u32 height, - u32 hotspotX, u32 hotspotY) -{ - void *virtual; - bool dummy; - - virtual = ttm_kmap_obj_virtual(&bo->map, &dummy); - if (virtual) { - vmw_cursor_update_image(dev_priv, cm_bo, cm_map, virtual, - width, height, - hotspotX, hotspotY); - atomic_dec(&bo->base_mapped_count); - } -} - static void vmw_cursor_update_position(struct vmw_private *dev_priv, bool show, int x, int y) @@ -391,11 +431,11 @@ void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv) continue; du->cursor_age = du->cursor_surface->snooper.age; - vmw_cursor_update_image(dev_priv, NULL, NULL, - du->cursor_surface->snooper.image, - 64, 64, - du->hotspot_x + du->core_hotspot_x, - du->hotspot_y + du->core_hotspot_y); + vmw_send_define_cursor_cmd(dev_priv, + du->cursor_surface->snooper.image, + 64, 64, + du->hotspot_x + du->core_hotspot_x, + du->hotspot_y + du->core_hotspot_y); } mutex_unlock(&dev->mode_config.mutex); @@ -404,8 +444,14 @@ void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv) void vmw_du_cursor_plane_destroy(struct drm_plane *plane) { + struct vmw_cursor_plane *vcp = vmw_plane_to_vcp(plane); + u32 i; + vmw_cursor_update_position(plane->dev->dev_private, false, 0, 0); - vmw_du_destroy_cursor_mob_array(vmw_plane_to_vcp(plane)); + + for (i = 0; i < ARRAY_SIZE(vcp->cursor_mobs); i++) + vmw_du_destroy_cursor_mob(&vcp->cursor_mobs[i]); + drm_plane_cleanup(plane); } @@ -462,6 +508,87 @@ vmw_du_plane_cleanup_fb(struct drm_plane *plane, } +/** + * vmw_du_cursor_plane_map_cm - Maps the cursor mobs. + * + * @vps: plane_state + * + * Returns 0 on success + */ + +static int +vmw_du_cursor_plane_map_cm(struct vmw_plane_state *vps) +{ + int ret; + u32 size = vmw_du_cursor_mob_size(vps->base.crtc_w, vps->base.crtc_h); + struct ttm_buffer_object *bo = vps->cursor.bo; + + if (bo == NULL) + return -EINVAL; + + if (bo->base.size < size) + return -EINVAL; + + if (vps->cursor.mapped) + return 0; + + ret = ttm_bo_reserve(bo, false, false, NULL); + + if (unlikely(ret != 0)) + return -ENOMEM; + + ret = ttm_bo_kmap(bo, 0, PFN_UP(size), &vps->cursor.map); + + /* + * We just want to try to get mob bind to finish + * so that the first write to SVGA_REG_CURSOR_MOBID + * is done with a buffer that the device has already + * seen + */ + (void) ttm_bo_wait(bo, false, false); + + ttm_bo_unreserve(bo); + + if (unlikely(ret != 0)) + return -ENOMEM; + + vps->cursor.mapped = true; + + return 0; +} + + +/** + * vmw_du_cursor_plane_unmap_cm - Unmaps the cursor mobs. + * + * @vps: state of the cursor plane + * + * Returns 0 on success + */ + +static int +vmw_du_cursor_plane_unmap_cm(struct vmw_plane_state *vps) +{ + int ret = 0; + struct ttm_buffer_object *bo = vps->cursor.bo; + + if (!vps->cursor.mapped) + return 0; + + if (bo == NULL) + return 0; + + ret = ttm_bo_reserve(bo, true, false, NULL); + if (likely(ret == 0)) { + ttm_bo_kunmap(&vps->cursor.map); + ttm_bo_unreserve(bo); + vps->cursor.mapped = false; + } + + return ret; +} + + /** * vmw_du_cursor_plane_cleanup_fb - Unpins the plane surface * @@ -476,6 +603,7 @@ void vmw_du_cursor_plane_cleanup_fb(struct drm_plane *plane, struct drm_plane_state *old_state) { + struct vmw_cursor_plane *vcp = vmw_plane_to_vcp(plane); struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state); bool dummy; @@ -489,28 +617,23 @@ vmw_du_cursor_plane_cleanup_fb(struct drm_plane *plane, } } - if (vps->cm_bo != NULL && ttm_kmap_obj_virtual(&vps->cm_map, &dummy) != NULL) { - const int ret = ttm_bo_reserve(vps->cm_bo, true, false, NULL); - - if (likely(ret == 0)) { - ttm_bo_kunmap(&vps->cm_map); - ttm_bo_unreserve(vps->cm_bo); - } - } + vmw_du_cursor_plane_unmap_cm(vps); + vmw_du_put_cursor_mob(vcp, vps); vmw_du_plane_unpin_surf(vps, false); - if (vps->surf) { + if (vps->surf != NULL) { vmw_surface_unreference(&vps->surf); vps->surf = NULL; } - if (vps->bo) { + if (vps->bo != NULL) { vmw_bo_unreference(&vps->bo); vps->bo = NULL; } } + /** * vmw_du_cursor_plane_prepare_fb - Readies the cursor by referencing it * @@ -526,8 +649,6 @@ vmw_du_cursor_plane_prepare_fb(struct drm_plane *plane, struct drm_framebuffer *fb = new_state->fb; struct vmw_cursor_plane *vcp = vmw_plane_to_vcp(plane); struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state); - struct ttm_buffer_object *cm_bo = NULL; - bool dummy; int ret = 0; if (vps->surf) { @@ -550,13 +671,14 @@ vmw_du_cursor_plane_prepare_fb(struct drm_plane *plane, } } - vps->cm_bo = NULL; - if (vps->surf == NULL && vps->bo != NULL) { const u32 size = new_state->crtc_w * new_state->crtc_h * sizeof(u32); - /* Not using vmw_bo_map_and_cache() helper here as we need to reserve - the ttm_buffer_object first which wmw_bo_map_and_cache() omits. */ + /* + * Not using vmw_bo_map_and_cache() helper here as we need to + * reserve the ttm_buffer_object first which + * vmw_bo_map_and_cache() omits. + */ ret = ttm_bo_reserve(&vps->bo->base, true, false, NULL); if (unlikely(ret != 0)) @@ -573,67 +695,12 @@ vmw_du_cursor_plane_prepare_fb(struct drm_plane *plane, return -ENOMEM; } - if (vps->surf || vps->bo) { - unsigned cursor_mob_idx = vps->cursor_mob_idx; - - /* Lazily set up cursor MOBs just once -- no reattempts. */ - if (cursor_mob_idx == 0 && vcp->cursor_mob[0] == NULL) - if (vmw_du_create_cursor_mob_array(vcp) != 0) - vps->cursor_mob_idx = cursor_mob_idx = -1U; - - if (cursor_mob_idx < ARRAY_SIZE(vcp->cursor_mob)) { - const u32 size = sizeof(SVGAGBCursorHeader) + - new_state->crtc_w * new_state->crtc_h * sizeof(u32); - - cm_bo = vcp->cursor_mob[cursor_mob_idx]; - - if (cm_bo->resource->num_pages * PAGE_SIZE < size) { - ret = -EINVAL; - goto error_bo_unmap; - } - - ret = ttm_bo_reserve(cm_bo, false, false, NULL); - - if (unlikely(ret != 0)) { - ret = -ENOMEM; - goto error_bo_unmap; - } - - ret = ttm_bo_kmap(cm_bo, 0, PFN_UP(size), &vps->cm_map); - - /* - * We just want to try to get mob bind to finish - * so that the first write to SVGA_REG_CURSOR_MOBID - * is done with a buffer that the device has already - * seen - */ - (void) ttm_bo_wait(cm_bo, false, false); - - ttm_bo_unreserve(cm_bo); - - if (unlikely(ret != 0)) { - ret = -ENOMEM; - goto error_bo_unmap; - } - - vps->cursor_mob_idx = cursor_mob_idx ^ 1; - vps->cm_bo = cm_bo; - } + if (vps->surf != NULL || vps->bo != NULL) { + vmw_du_get_cursor_mob(vcp, vps); + vmw_du_cursor_plane_map_cm(vps); } return 0; - -error_bo_unmap: - if (vps->bo != NULL && ttm_kmap_obj_virtual(&vps->bo->map, &dummy) != NULL) { - const int ret = ttm_bo_reserve(&vps->bo->base, true, false, NULL); - if (likely(ret == 0)) { - atomic_dec(&vps->bo->base_mapped_count); - ttm_bo_kunmap(&vps->bo->map); - ttm_bo_unreserve(&vps->bo->base); - } - } - - return ret; } @@ -650,6 +717,8 @@ vmw_du_cursor_plane_atomic_update(struct drm_plane *plane, struct vmw_display_unit *du = vmw_crtc_to_du(crtc); struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state); s32 hotspot_x, hotspot_y; + void *virtual; + bool dummy; hotspot_x = du->hotspot_x; hotspot_y = du->hotspot_y; @@ -662,23 +731,29 @@ vmw_du_cursor_plane_atomic_update(struct drm_plane *plane, du->cursor_surface = vps->surf; du->cursor_bo = vps->bo; - if (vps->surf) { + if (vps->surf == NULL && vps->bo == NULL) { + vmw_cursor_update_position(dev_priv, false, 0, 0); + return; + } + + if (vps->surf != NULL) { du->cursor_age = du->cursor_surface->snooper.age; - vmw_cursor_update_image(dev_priv, vps->cm_bo, &vps->cm_map, + vmw_cursor_update_image(dev_priv, vps, vps->surf->snooper.image, new_state->crtc_w, new_state->crtc_h, hotspot_x, hotspot_y); - } else if (vps->bo) { - vmw_cursor_update_bo(dev_priv, vps->cm_bo, &vps->cm_map, - vps->bo, - new_state->crtc_w, - new_state->crtc_h, - hotspot_x, hotspot_y); } else { - vmw_cursor_update_position(dev_priv, false, 0, 0); - return; + + virtual = ttm_kmap_obj_virtual(&vps->bo->map, &dummy); + if (virtual) { + vmw_cursor_update_image(dev_priv, vps, virtual, + new_state->crtc_w, + new_state->crtc_h, + hotspot_x, hotspot_y); + atomic_dec(&vps->bo->base_mapped_count); + } } du->cursor_x = new_state->crtc_x + du->set_gui_x; @@ -943,11 +1018,13 @@ vmw_du_plane_duplicate_state(struct drm_plane *plane) vps->pinned = 0; vps->cpp = 0; + memset(&vps->cursor, 0, sizeof(vps->cursor)); + /* Each ref counted resource needs to be acquired again */ - if (vps->surf) + if (vps->surf != NULL) (void) vmw_surface_reference(vps->surf); - if (vps->bo) + if (vps->bo != NULL) (void) vmw_bo_reference(vps->bo); state = &vps->base; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index 85f86faa3243..a9bcc91f978b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -295,13 +295,11 @@ struct vmw_plane_state { /* For CPU Blit */ unsigned int cpp; - /* CursorMob flipping index; -1 if cursor mobs not used */ - unsigned int cursor_mob_idx; - /* Currently-active CursorMob */ - struct ttm_buffer_object *cm_bo; - /* CursorMob kmap_obj; expected valid at cursor_plane_atomic_update - IFF currently-active CursorMob above is valid */ - struct ttm_bo_kmap_obj cm_map; + struct { + struct ttm_buffer_object *bo; + struct ttm_bo_kmap_obj map; + bool mapped; + } cursor; }; @@ -338,11 +336,12 @@ struct vmw_connector_state { * Derived class for cursor plane object * * @base DRM plane object - * @cursor_mob array of two MOBs for CursorMob flipping + * @cursor.cursor_mobs Cursor mobs available for re-use */ struct vmw_cursor_plane { struct drm_plane base; - struct ttm_buffer_object *cursor_mob[2]; + + struct ttm_buffer_object *cursor_mobs[3]; }; /** @@ -472,8 +471,6 @@ void vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv); /* Universal Plane Helpers */ void vmw_du_primary_plane_destroy(struct drm_plane *plane); void vmw_du_cursor_plane_destroy(struct drm_plane *plane); -int vmw_du_create_cursor_mob_array(struct vmw_cursor_plane *vcp); -void vmw_du_destroy_cursor_mob_array(struct vmw_cursor_plane *vcp); /* Atomic Helpers */ int vmw_du_primary_plane_atomic_check(struct drm_plane *plane, -- cgit From 40f9e40b20491e54ea1006faecd31b6b72caf052 Mon Sep 17 00:00:00 2001 From: Michael Banack Date: Sat, 22 Oct 2022 00:02:26 -0400 Subject: drm/vmwgfx: Start diffing new mob cursors against old ones Avoid making the SVGA device do extra work if the new cursor image matches the old one. Signed-off-by: Michael Banack Signed-off-by: Zack Rusin Link: https://patchwork.freedesktop.org/patch/msgid/20221022040236.616490-8-zack@kde.org --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 95 +++++++++++++++++++++++++++++-------- drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 12 +++-- 2 files changed, 81 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 07d55d610e4c..464d7c8cd1d6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -52,11 +52,9 @@ void vmw_du_cleanup(struct vmw_display_unit *du) * Display Unit Cursor functions */ -static void vmw_cursor_update_mob(struct vmw_private *dev_priv, - struct vmw_plane_state *vps, - u32 *image, u32 width, u32 height, - u32 hotspotX, u32 hotspotY); static int vmw_du_cursor_plane_unmap_cm(struct vmw_plane_state *vps); +static void vmw_cursor_write_mobid(struct vmw_private *dev_priv, + struct vmw_plane_state *vps); struct vmw_svga_fifo_cmd_define_cursor { u32 cmd; @@ -120,9 +118,7 @@ static void vmw_cursor_update_image(struct vmw_private *dev_priv, u32 hotspotX, u32 hotspotY) { if (vps->cursor.bo != NULL) - vmw_cursor_update_mob(dev_priv, vps, image, - width, height, - hotspotX, hotspotY); + vmw_cursor_write_mobid(dev_priv, vps); else vmw_send_define_cursor_cmd(dev_priv, image, width, height, hotspotX, hotspotY); @@ -167,6 +163,21 @@ static void vmw_cursor_update_mob(struct vmw_private *dev_priv, alpha_header->height = height; memcpy(header + 1, image, image_size); +} + + +/** + * vmw_cursor_write_mobid - Update cursor via CursorMob mechanism + * + * Called from inside vmw_du_cursor_plane_atomic_update to actually + * make the cursor-image live. + * + * @dev_priv: device to work with + * @vps: DRM plane_state + */ +static void vmw_cursor_write_mobid(struct vmw_private *dev_priv, + struct vmw_plane_state *vps) +{ vmw_write(dev_priv, SVGA_REG_CURSOR_MOBID, vps->cursor.bo->resource->start); } @@ -176,6 +187,39 @@ static u32 vmw_du_cursor_mob_size(u32 w, u32 h) return w * h * sizeof(u32) + sizeof(SVGAGBCursorHeader); } + +static bool vmw_du_cursor_plane_mob_has_changed(struct vmw_plane_state *old_vps, + struct vmw_plane_state *new_vps) +{ + void *old_mob; + void *new_mob; + bool dummy; + u32 size; + + // If either of them aren't using CursorMobs, assume changed. + if (old_vps->cursor.bo == NULL || new_vps->cursor.bo == NULL) + return true; + + // If either of them failed to map, assume changed. + if (!old_vps->cursor.mapped || !new_vps->cursor.mapped) + return true; + + if (old_vps->base.crtc_w != new_vps->base.crtc_w || + old_vps->base.crtc_h != new_vps->base.crtc_h) + return true; + + size = vmw_du_cursor_mob_size(new_vps->base.crtc_w, + new_vps->base.crtc_h); + + old_mob = ttm_kmap_obj_virtual(&old_vps->cursor.map, &dummy); + new_mob = ttm_kmap_obj_virtual(&new_vps->cursor.map, &dummy); + + if (memcmp(old_mob, new_mob, size) != 0) + return true; + + return false; +} + static void vmw_du_destroy_cursor_mob(struct ttm_buffer_object **bo) { if (*bo == NULL) @@ -716,9 +760,10 @@ vmw_du_cursor_plane_atomic_update(struct drm_plane *plane, struct vmw_private *dev_priv = vmw_priv(crtc->dev); struct vmw_display_unit *du = vmw_crtc_to_du(crtc); struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state); + struct vmw_plane_state *old_vps = vmw_plane_state_to_vps(old_state); s32 hotspot_x, hotspot_y; - void *virtual; bool dummy; + void *image; hotspot_x = du->hotspot_x; hotspot_y = du->hotspot_y; @@ -738,23 +783,32 @@ vmw_du_cursor_plane_atomic_update(struct drm_plane *plane, if (vps->surf != NULL) { du->cursor_age = du->cursor_surface->snooper.age; + image = vps->surf->snooper.image; + } else + image = ttm_kmap_obj_virtual(&vps->bo->map, &dummy); - vmw_cursor_update_image(dev_priv, vps, - vps->surf->snooper.image, + if (vps->cursor.bo != NULL) + vmw_cursor_update_mob(dev_priv, vps, image, + new_state->crtc_w, + new_state->crtc_h, + hotspot_x, hotspot_y); + + if (!vmw_du_cursor_plane_mob_has_changed(old_vps, vps)) { + /* + * If it hasn't changed, avoid making the device do extra + * work by keeping the old mob active. + */ + struct vmw_cursor_plane_state tmp = old_vps->cursor; + old_vps->cursor = vps->cursor; + vps->cursor = tmp; + } else if (image != NULL) + vmw_cursor_update_image(dev_priv, vps, image, new_state->crtc_w, new_state->crtc_h, hotspot_x, hotspot_y); - } else { - virtual = ttm_kmap_obj_virtual(&vps->bo->map, &dummy); - if (virtual) { - vmw_cursor_update_image(dev_priv, vps, virtual, - new_state->crtc_w, - new_state->crtc_h, - hotspot_x, hotspot_y); - atomic_dec(&vps->bo->base_mapped_count); - } - } + if (image != NULL && vps->bo != NULL) + atomic_dec(&vps->bo->base_mapped_count); du->cursor_x = new_state->crtc_x + du->set_gui_x; du->cursor_y = new_state->crtc_y + du->set_gui_y; @@ -1074,7 +1128,6 @@ vmw_du_plane_destroy_state(struct drm_plane *plane, { struct vmw_plane_state *vps = vmw_plane_state_to_vps(state); - /* Should have been freed by cleanup_fb */ if (vps->surf) vmw_surface_unreference(&vps->surf); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index a9bcc91f978b..fb4c9f9e3493 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -272,6 +272,12 @@ struct vmw_crtc_state { struct drm_crtc_state base; }; +struct vmw_cursor_plane_state { + struct ttm_buffer_object *bo; + struct ttm_bo_kmap_obj map; + bool mapped; +}; + /** * Derived class for plane state object * @@ -295,11 +301,7 @@ struct vmw_plane_state { /* For CPU Blit */ unsigned int cpp; - struct { - struct ttm_buffer_object *bo; - struct ttm_bo_kmap_obj map; - bool mapped; - } cursor; + struct vmw_cursor_plane_state cursor; }; -- cgit From 92f59ac41c88cddd79591993d0066a19c932f8e7 Mon Sep 17 00:00:00 2001 From: Michael Banack Date: Sat, 22 Oct 2022 00:02:27 -0400 Subject: drm/vmwgfx: Support cursor surfaces with mob cursor Add support for cursor surfaces when using mob cursors. Signed-off-by: Michael Banack Signed-off-by: Zack Rusin Link: https://patchwork.freedesktop.org/patch/msgid/20221022040236.616490-9-zack@kde.org --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 78 +++++++++++++++++++++++-------------- drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 1 + 2 files changed, 50 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 464d7c8cd1d6..6c41c5b5a913 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -85,7 +85,7 @@ static void vmw_send_define_cursor_cmd(struct vmw_private *dev_priv, other fallible KMS-atomic resources at prepare_fb */ cmd = VMW_CMD_RESERVE(dev_priv, cmd_size); - if (unlikely(cmd == NULL)) + if (unlikely(!cmd)) return; memset(cmd, 0, sizeof(*cmd)); @@ -117,7 +117,7 @@ static void vmw_cursor_update_image(struct vmw_private *dev_priv, u32 *image, u32 width, u32 height, u32 hotspotX, u32 hotspotY) { - if (vps->cursor.bo != NULL) + if (vps->cursor.bo) vmw_cursor_write_mobid(dev_priv, vps); else vmw_send_define_cursor_cmd(dev_priv, image, width, height, @@ -197,7 +197,7 @@ static bool vmw_du_cursor_plane_mob_has_changed(struct vmw_plane_state *old_vps, u32 size; // If either of them aren't using CursorMobs, assume changed. - if (old_vps->cursor.bo == NULL || new_vps->cursor.bo == NULL) + if (!old_vps->cursor.bo || !new_vps->cursor.bo) return true; // If either of them failed to map, assume changed. @@ -222,7 +222,7 @@ static bool vmw_du_cursor_plane_mob_has_changed(struct vmw_plane_state *old_vps, static void vmw_du_destroy_cursor_mob(struct ttm_buffer_object **bo) { - if (*bo == NULL) + if (!(*bo)) return; ttm_bo_unpin(*bo); @@ -236,14 +236,14 @@ static void vmw_du_put_cursor_mob(struct vmw_cursor_plane *vcp, { u32 i; - if (vps->cursor.bo == NULL) + if (!vps->cursor.bo) return; vmw_du_cursor_plane_unmap_cm(vps); /* Look for a free slot to return this mob to the cache. */ for (i = 0; i < ARRAY_SIZE(vcp->cursor_mobs); i++) { - if (vcp->cursor_mobs[i] == NULL) { + if (!vcp->cursor_mobs[i]) { vcp->cursor_mobs[i] = vps->cursor.bo; vps->cursor.bo = NULL; return; @@ -285,7 +285,7 @@ static int vmw_du_get_cursor_mob(struct vmw_cursor_plane *vcp, vps->base.crtc_h > cursor_max_dim) return -EINVAL; - if (vps->cursor.bo != NULL) { + if (vps->cursor.bo) { if (vps->cursor.bo->base.size >= size) return 0; vmw_du_put_cursor_mob(vcp, vps); @@ -293,7 +293,7 @@ static int vmw_du_get_cursor_mob(struct vmw_cursor_plane *vcp, /* Look for an unused mob in the cache. */ for (i = 0; i < ARRAY_SIZE(vcp->cursor_mobs); i++) { - if (vcp->cursor_mobs[i] != NULL && + if (vcp->cursor_mobs[i] && vcp->cursor_mobs[i]->base.size >= size) { vps->cursor.bo = vcp->cursor_mobs[i]; vcp->cursor_mobs[i] = NULL; @@ -371,7 +371,7 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf, cmd = container_of(header, struct vmw_dma_cmd, header); - /* No snooper installed */ + /* No snooper installed, nothing to copy */ if (!srf->snooper.image) return; @@ -471,7 +471,8 @@ void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv) list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { du = vmw_crtc_to_du(crtc); if (!du->cursor_surface || - du->cursor_age == du->cursor_surface->snooper.age) + du->cursor_age == du->cursor_surface->snooper.age || + !du->cursor_surface->snooper.image) continue; du->cursor_age = du->cursor_surface->snooper.age; @@ -567,7 +568,7 @@ vmw_du_cursor_plane_map_cm(struct vmw_plane_state *vps) u32 size = vmw_du_cursor_mob_size(vps->base.crtc_w, vps->base.crtc_h); struct ttm_buffer_object *bo = vps->cursor.bo; - if (bo == NULL) + if (!bo) return -EINVAL; if (bo->base.size < size) @@ -619,7 +620,7 @@ vmw_du_cursor_plane_unmap_cm(struct vmw_plane_state *vps) if (!vps->cursor.mapped) return 0; - if (bo == NULL) + if (!bo) return 0; ret = ttm_bo_reserve(bo, true, false, NULL); @@ -651,7 +652,12 @@ vmw_du_cursor_plane_cleanup_fb(struct drm_plane *plane, struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state); bool dummy; - if (vps->bo != NULL && ttm_kmap_obj_virtual(&vps->bo->map, &dummy) != NULL) { + if (vps->surf_mapped) { + vmw_bo_unmap(vps->surf->res.backup); + vps->surf_mapped = false; + } + + if (vps->bo && ttm_kmap_obj_virtual(&vps->bo->map, &dummy)) { const int ret = ttm_bo_reserve(&vps->bo->base, true, false, NULL); if (likely(ret == 0)) { @@ -666,12 +672,12 @@ vmw_du_cursor_plane_cleanup_fb(struct drm_plane *plane, vmw_du_plane_unpin_surf(vps, false); - if (vps->surf != NULL) { + if (vps->surf) { vmw_surface_unreference(&vps->surf); vps->surf = NULL; } - if (vps->bo != NULL) { + if (vps->bo) { vmw_bo_unreference(&vps->bo); vps->bo = NULL; } @@ -715,7 +721,7 @@ vmw_du_cursor_plane_prepare_fb(struct drm_plane *plane, } } - if (vps->surf == NULL && vps->bo != NULL) { + if (!vps->surf && vps->bo) { const u32 size = new_state->crtc_w * new_state->crtc_h * sizeof(u32); /* @@ -737,9 +743,18 @@ vmw_du_cursor_plane_prepare_fb(struct drm_plane *plane, if (unlikely(ret != 0)) return -ENOMEM; + } else if (vps->surf && !vps->bo && vps->surf->res.backup) { + + ret = ttm_bo_reserve(&vps->surf->res.backup->base, true, false, + NULL); + if (unlikely(ret != 0)) + return -ENOMEM; + vmw_bo_map_and_cache(vps->surf->res.backup); + ttm_bo_unreserve(&vps->surf->res.backup->base); + vps->surf_mapped = true; } - if (vps->surf != NULL || vps->bo != NULL) { + if (vps->surf || vps->bo) { vmw_du_get_cursor_mob(vcp, vps); vmw_du_cursor_plane_map_cm(vps); } @@ -776,18 +791,20 @@ vmw_du_cursor_plane_atomic_update(struct drm_plane *plane, du->cursor_surface = vps->surf; du->cursor_bo = vps->bo; - if (vps->surf == NULL && vps->bo == NULL) { + if (!vps->surf && !vps->bo) { vmw_cursor_update_position(dev_priv, false, 0, 0); return; } - if (vps->surf != NULL) { + if (vps->surf) { du->cursor_age = du->cursor_surface->snooper.age; image = vps->surf->snooper.image; + if (vps->surf_mapped) + image = vmw_bo_map_and_cache(vps->surf->res.backup); } else image = ttm_kmap_obj_virtual(&vps->bo->map, &dummy); - if (vps->cursor.bo != NULL) + if (vps->cursor.bo) vmw_cursor_update_mob(dev_priv, vps, image, new_state->crtc_w, new_state->crtc_h, @@ -801,13 +818,13 @@ vmw_du_cursor_plane_atomic_update(struct drm_plane *plane, struct vmw_cursor_plane_state tmp = old_vps->cursor; old_vps->cursor = vps->cursor; vps->cursor = tmp; - } else if (image != NULL) + } else if (image) vmw_cursor_update_image(dev_priv, vps, image, new_state->crtc_w, new_state->crtc_h, hotspot_x, hotspot_y); - if (image != NULL && vps->bo != NULL) + if (image && vps->bo) atomic_dec(&vps->bo->base_mapped_count); du->cursor_x = new_state->crtc_x + du->set_gui_x; @@ -907,12 +924,16 @@ int vmw_du_cursor_plane_atomic_check(struct drm_plane *plane, return -EINVAL; } - if (!vmw_framebuffer_to_vfb(fb)->bo) + if (!vmw_framebuffer_to_vfb(fb)->bo) { surface = vmw_framebuffer_to_vfbs(fb)->surface; - if (surface && !surface->snooper.image) { - DRM_ERROR("surface not suitable for cursor\n"); - return -EINVAL; + WARN_ON(!surface); + + if (!surface || + (!surface->snooper.image && !surface->res.backup)) { + DRM_ERROR("surface not suitable for cursor\n"); + return -EINVAL; + } } return 0; @@ -1075,10 +1096,10 @@ vmw_du_plane_duplicate_state(struct drm_plane *plane) memset(&vps->cursor, 0, sizeof(vps->cursor)); /* Each ref counted resource needs to be acquired again */ - if (vps->surf != NULL) + if (vps->surf) (void) vmw_surface_reference(vps->surf); - if (vps->bo != NULL) + if (vps->bo) (void) vmw_bo_reference(vps->bo); state = &vps->base; @@ -2223,7 +2244,6 @@ int vmw_kms_cursor_bypass_ioctl(struct drm_device *dev, void *data, struct drm_crtc *crtc; int ret = 0; - mutex_lock(&dev->mode_config.mutex); if (arg->flags & DRM_VMW_CURSOR_BYPASS_ALL) { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index fb4c9f9e3493..c5e4665a956c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -301,6 +301,7 @@ struct vmw_plane_state { /* For CPU Blit */ unsigned int cpp; + bool surf_mapped; struct vmw_cursor_plane_state cursor; }; -- cgit From bb6780aa5a1d99e86757c0c96bfae65a46cf839e Mon Sep 17 00:00:00 2001 From: Michael Banack Date: Sat, 22 Oct 2022 00:02:28 -0400 Subject: drm/vmwgfx: Diff cursors when using cmds Extend the cursor diffing support to support the command-path. Signed-off-by: Michael Banack Signed-off-by: Zack Rusin Link: https://patchwork.freedesktop.org/patch/msgid/20221022040236.616490-10-zack@kde.org --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 120 ++++++++++++++++++------------------ drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 2 + 2 files changed, 62 insertions(+), 60 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 6c41c5b5a913..ff79668ad334 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -53,8 +53,10 @@ void vmw_du_cleanup(struct vmw_display_unit *du) */ static int vmw_du_cursor_plane_unmap_cm(struct vmw_plane_state *vps); -static void vmw_cursor_write_mobid(struct vmw_private *dev_priv, - struct vmw_plane_state *vps); +static void vmw_cursor_update_mob(struct vmw_private *dev_priv, + struct vmw_plane_state *vps, + u32 *image, u32 width, u32 height, + u32 hotspotX, u32 hotspotY); struct vmw_svga_fifo_cmd_define_cursor { u32 cmd; @@ -118,7 +120,10 @@ static void vmw_cursor_update_image(struct vmw_private *dev_priv, u32 hotspotX, u32 hotspotY) { if (vps->cursor.bo) - vmw_cursor_write_mobid(dev_priv, vps); + vmw_cursor_update_mob(dev_priv, vps, image, + vps->base.crtc_w, vps->base.crtc_h, + hotspotX, hotspotY); + else vmw_send_define_cursor_cmd(dev_priv, image, width, height, hotspotX, hotspotY); @@ -163,61 +168,58 @@ static void vmw_cursor_update_mob(struct vmw_private *dev_priv, alpha_header->height = height; memcpy(header + 1, image, image_size); -} - - -/** - * vmw_cursor_write_mobid - Update cursor via CursorMob mechanism - * - * Called from inside vmw_du_cursor_plane_atomic_update to actually - * make the cursor-image live. - * - * @dev_priv: device to work with - * @vps: DRM plane_state - */ -static void vmw_cursor_write_mobid(struct vmw_private *dev_priv, - struct vmw_plane_state *vps) -{ vmw_write(dev_priv, SVGA_REG_CURSOR_MOBID, vps->cursor.bo->resource->start); } + static u32 vmw_du_cursor_mob_size(u32 w, u32 h) { return w * h * sizeof(u32) + sizeof(SVGAGBCursorHeader); } - -static bool vmw_du_cursor_plane_mob_has_changed(struct vmw_plane_state *old_vps, - struct vmw_plane_state *new_vps) +/** + * vmw_du_cursor_plane_acquire_image -- Acquire the image data + * @vps: cursor plane state + */ +static u32 *vmw_du_cursor_plane_acquire_image(struct vmw_plane_state *vps) { - void *old_mob; - void *new_mob; bool dummy; - u32 size; - - // If either of them aren't using CursorMobs, assume changed. - if (!old_vps->cursor.bo || !new_vps->cursor.bo) - return true; + if (vps->surf) { + if (vps->surf_mapped) + return vmw_bo_map_and_cache(vps->surf->res.backup); + return vps->surf->snooper.image; + } else if (vps->bo) + return ttm_kmap_obj_virtual(&vps->bo->map, &dummy); + return NULL; +} - // If either of them failed to map, assume changed. - if (!old_vps->cursor.mapped || !new_vps->cursor.mapped) - return true; +static bool vmw_du_cursor_plane_has_changed(struct vmw_plane_state *old_vps, + struct vmw_plane_state *new_vps) +{ + void *old_image; + void *new_image; + u32 size; + bool changed; if (old_vps->base.crtc_w != new_vps->base.crtc_w || old_vps->base.crtc_h != new_vps->base.crtc_h) return true; - size = vmw_du_cursor_mob_size(new_vps->base.crtc_w, - new_vps->base.crtc_h); + if (old_vps->cursor.hotspot_x != new_vps->cursor.hotspot_x || + old_vps->cursor.hotspot_y != new_vps->cursor.hotspot_y) + return true; - old_mob = ttm_kmap_obj_virtual(&old_vps->cursor.map, &dummy); - new_mob = ttm_kmap_obj_virtual(&new_vps->cursor.map, &dummy); + size = new_vps->base.crtc_w * new_vps->base.crtc_h * sizeof(u32); - if (memcmp(old_mob, new_mob, size) != 0) - return true; + old_image = vmw_du_cursor_plane_acquire_image(old_vps); + new_image = vmw_du_cursor_plane_acquire_image(new_vps); - return false; + changed = false; + if (old_image && new_image) + changed = memcmp(old_image, new_image, size) != 0; + + return changed; } static void vmw_du_destroy_cursor_mob(struct ttm_buffer_object **bo) @@ -745,6 +747,7 @@ vmw_du_cursor_plane_prepare_fb(struct drm_plane *plane, return -ENOMEM; } else if (vps->surf && !vps->bo && vps->surf->res.backup) { + WARN_ON(vps->surf->snooper.image); ret = ttm_bo_reserve(&vps->surf->res.backup->base, true, false, NULL); if (unlikely(ret != 0)) @@ -778,7 +781,6 @@ vmw_du_cursor_plane_atomic_update(struct drm_plane *plane, struct vmw_plane_state *old_vps = vmw_plane_state_to_vps(old_state); s32 hotspot_x, hotspot_y; bool dummy; - void *image; hotspot_x = du->hotspot_x; hotspot_y = du->hotspot_y; @@ -796,36 +798,34 @@ vmw_du_cursor_plane_atomic_update(struct drm_plane *plane, return; } + vps->cursor.hotspot_x = hotspot_x; + vps->cursor.hotspot_y = hotspot_y; + if (vps->surf) { du->cursor_age = du->cursor_surface->snooper.age; - image = vps->surf->snooper.image; - if (vps->surf_mapped) - image = vmw_bo_map_and_cache(vps->surf->res.backup); - } else - image = ttm_kmap_obj_virtual(&vps->bo->map, &dummy); - - if (vps->cursor.bo) - vmw_cursor_update_mob(dev_priv, vps, image, - new_state->crtc_w, - new_state->crtc_h, - hotspot_x, hotspot_y); + } - if (!vmw_du_cursor_plane_mob_has_changed(old_vps, vps)) { + if (!vmw_du_cursor_plane_has_changed(old_vps, vps)) { /* * If it hasn't changed, avoid making the device do extra - * work by keeping the old mob active. + * work by keeping the old cursor active. */ struct vmw_cursor_plane_state tmp = old_vps->cursor; old_vps->cursor = vps->cursor; vps->cursor = tmp; - } else if (image) - vmw_cursor_update_image(dev_priv, vps, image, - new_state->crtc_w, - new_state->crtc_h, - hotspot_x, hotspot_y); - - if (image && vps->bo) - atomic_dec(&vps->bo->base_mapped_count); + } else { + void *image = vmw_du_cursor_plane_acquire_image(vps); + if (image) + vmw_cursor_update_image(dev_priv, vps, image, + new_state->crtc_w, + new_state->crtc_h, + hotspot_x, hotspot_y); + } + + if (vps->bo) { + if (ttm_kmap_obj_virtual(&vps->bo->map, &dummy)) + atomic_dec(&vps->bo->base_mapped_count); + } du->cursor_x = new_state->crtc_x + du->set_gui_x; du->cursor_y = new_state->crtc_y + du->set_gui_y; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index c5e4665a956c..13a265ffd9f8 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -276,6 +276,8 @@ struct vmw_cursor_plane_state { struct ttm_buffer_object *bo; struct ttm_bo_kmap_obj map; bool mapped; + s32 hotspot_x; + s32 hotspot_y; }; /** -- cgit From 76a9e07f270cf5fb556ac237dbf11f5dacd61fef Mon Sep 17 00:00:00 2001 From: Maaz Mombasawala Date: Sat, 22 Oct 2022 00:02:29 -0400 Subject: drm/vmwgfx: Refactor ttm reference object hashtable to use linux/hashtable. This is part of an effort to move from the vmwgfx_open_hash hashtable to linux/hashtable implementation. Refactor the ref_hash hashtable, used for fast lookup of reference objects associated with a ttm file. This also exposed a problem related to inconsistently using 32-bit and 64-bit keys with this hashtable. The hash function used changes depending on the size of the type, and results are not consistent across numbers, for example, hash_32(329) = 329, but hash_long(329) = 328. This would cause the lookup to fail for objects already in the hashtable, since keys of different sizes were being passed during adding and lookup. This was not an issue before because vmwgfx_open_hash always used hash_long. Fix this by always using 64-bit keys for this hashtable, which means that hash_long is always used. Signed-off-by: Maaz Mombasawala Reviewed-by: Zack Rusin Signed-off-by: Zack Rusin Link: https://patchwork.freedesktop.org/patch/msgid/20221022040236.616490-11-zack@kde.org --- drivers/gpu/drm/vmwgfx/ttm_object.c | 91 ++++++++++++++++++++----------------- drivers/gpu/drm/vmwgfx/ttm_object.h | 12 ++--- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 2 +- 3 files changed, 56 insertions(+), 49 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/ttm_object.c b/drivers/gpu/drm/vmwgfx/ttm_object.c index 9546b121bc22..c07b81fbc495 100644 --- a/drivers/gpu/drm/vmwgfx/ttm_object.c +++ b/drivers/gpu/drm/vmwgfx/ttm_object.c @@ -52,9 +52,12 @@ #include #include #include +#include MODULE_IMPORT_NS(DMA_BUF); +#define VMW_TTM_OBJECT_REF_HT_ORDER 10 + /** * struct ttm_object_file * @@ -75,7 +78,7 @@ struct ttm_object_file { struct ttm_object_device *tdev; spinlock_t lock; struct list_head ref_list; - struct vmwgfx_open_hash ref_hash; + DECLARE_HASHTABLE(ref_hash, VMW_TTM_OBJECT_REF_HT_ORDER); struct kref refcount; }; @@ -136,6 +139,36 @@ ttm_object_file_ref(struct ttm_object_file *tfile) return tfile; } +static int ttm_tfile_find_ref_rcu(struct ttm_object_file *tfile, + uint64_t key, + struct vmwgfx_hash_item **p_hash) +{ + struct vmwgfx_hash_item *hash; + + hash_for_each_possible_rcu(tfile->ref_hash, hash, head, key) { + if (hash->key == key) { + *p_hash = hash; + return 0; + } + } + return -EINVAL; +} + +static int ttm_tfile_find_ref(struct ttm_object_file *tfile, + uint64_t key, + struct vmwgfx_hash_item **p_hash) +{ + struct vmwgfx_hash_item *hash; + + hash_for_each_possible(tfile->ref_hash, hash, head, key) { + if (hash->key == key) { + *p_hash = hash; + return 0; + } + } + return -EINVAL; +} + static void ttm_object_file_destroy(struct kref *kref) { struct ttm_object_file *tfile = @@ -238,14 +271,13 @@ void ttm_base_object_unref(struct ttm_base_object **p_base) * Return: A pointer to the object if successful or NULL otherwise. */ struct ttm_base_object * -ttm_base_object_noref_lookup(struct ttm_object_file *tfile, uint32_t key) +ttm_base_object_noref_lookup(struct ttm_object_file *tfile, uint64_t key) { struct vmwgfx_hash_item *hash; - struct vmwgfx_open_hash *ht = &tfile->ref_hash; int ret; rcu_read_lock(); - ret = vmwgfx_ht_find_item_rcu(ht, key, &hash); + ret = ttm_tfile_find_ref_rcu(tfile, key, &hash); if (ret) { rcu_read_unlock(); return NULL; @@ -257,15 +289,14 @@ ttm_base_object_noref_lookup(struct ttm_object_file *tfile, uint32_t key) EXPORT_SYMBOL(ttm_base_object_noref_lookup); struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile, - uint32_t key) + uint64_t key) { struct ttm_base_object *base = NULL; struct vmwgfx_hash_item *hash; - struct vmwgfx_open_hash *ht = &tfile->ref_hash; int ret; rcu_read_lock(); - ret = vmwgfx_ht_find_item_rcu(ht, key, &hash); + ret = ttm_tfile_find_ref_rcu(tfile, key, &hash); if (likely(ret == 0)) { base = drm_hash_entry(hash, struct ttm_ref_object, hash)->obj; @@ -278,7 +309,7 @@ struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile, } struct ttm_base_object * -ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint32_t key) +ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint64_t key) { struct ttm_base_object *base; @@ -297,7 +328,6 @@ int ttm_ref_object_add(struct ttm_object_file *tfile, bool *existed, bool require_existed) { - struct vmwgfx_open_hash *ht = &tfile->ref_hash; struct ttm_ref_object *ref; struct vmwgfx_hash_item *hash; int ret = -EINVAL; @@ -310,7 +340,7 @@ int ttm_ref_object_add(struct ttm_object_file *tfile, while (ret == -EINVAL) { rcu_read_lock(); - ret = vmwgfx_ht_find_item_rcu(ht, base->handle, &hash); + ret = ttm_tfile_find_ref_rcu(tfile, base->handle, &hash); if (ret == 0) { ref = drm_hash_entry(hash, struct ttm_ref_object, hash); @@ -335,21 +365,14 @@ int ttm_ref_object_add(struct ttm_object_file *tfile, kref_init(&ref->kref); spin_lock(&tfile->lock); - ret = vmwgfx_ht_insert_item_rcu(ht, &ref->hash); - - if (likely(ret == 0)) { - list_add_tail(&ref->head, &tfile->ref_list); - kref_get(&base->refcount); - spin_unlock(&tfile->lock); - if (existed != NULL) - *existed = false; - break; - } + hash_add_rcu(tfile->ref_hash, &ref->hash.head, ref->hash.key); + ret = 0; + list_add_tail(&ref->head, &tfile->ref_list); + kref_get(&base->refcount); spin_unlock(&tfile->lock); - BUG_ON(ret != -EINVAL); - - kfree(ref); + if (existed != NULL) + *existed = false; } return ret; @@ -361,10 +384,8 @@ ttm_ref_object_release(struct kref *kref) struct ttm_ref_object *ref = container_of(kref, struct ttm_ref_object, kref); struct ttm_object_file *tfile = ref->tfile; - struct vmwgfx_open_hash *ht; - ht = &tfile->ref_hash; - (void)vmwgfx_ht_remove_item_rcu(ht, &ref->hash); + hash_del_rcu(&ref->hash.head); list_del(&ref->head); spin_unlock(&tfile->lock); @@ -376,13 +397,12 @@ ttm_ref_object_release(struct kref *kref) int ttm_ref_object_base_unref(struct ttm_object_file *tfile, unsigned long key) { - struct vmwgfx_open_hash *ht = &tfile->ref_hash; struct ttm_ref_object *ref; struct vmwgfx_hash_item *hash; int ret; spin_lock(&tfile->lock); - ret = vmwgfx_ht_find_item(ht, key, &hash); + ret = ttm_tfile_find_ref(tfile, key, &hash); if (unlikely(ret != 0)) { spin_unlock(&tfile->lock); return -EINVAL; @@ -414,16 +434,13 @@ void ttm_object_file_release(struct ttm_object_file **p_tfile) } spin_unlock(&tfile->lock); - vmwgfx_ht_remove(&tfile->ref_hash); ttm_object_file_unref(&tfile); } -struct ttm_object_file *ttm_object_file_init(struct ttm_object_device *tdev, - unsigned int hash_order) +struct ttm_object_file *ttm_object_file_init(struct ttm_object_device *tdev) { struct ttm_object_file *tfile = kmalloc(sizeof(*tfile), GFP_KERNEL); - int ret; if (unlikely(tfile == NULL)) return NULL; @@ -433,17 +450,9 @@ struct ttm_object_file *ttm_object_file_init(struct ttm_object_device *tdev, kref_init(&tfile->refcount); INIT_LIST_HEAD(&tfile->ref_list); - ret = vmwgfx_ht_create(&tfile->ref_hash, hash_order); - if (ret) - goto out_err; + hash_init(tfile->ref_hash); return tfile; -out_err: - vmwgfx_ht_remove(&tfile->ref_hash); - - kfree(tfile); - - return NULL; } struct ttm_object_device * diff --git a/drivers/gpu/drm/vmwgfx/ttm_object.h b/drivers/gpu/drm/vmwgfx/ttm_object.h index 6870f951b677..67f30d589e27 100644 --- a/drivers/gpu/drm/vmwgfx/ttm_object.h +++ b/drivers/gpu/drm/vmwgfx/ttm_object.h @@ -104,7 +104,7 @@ struct ttm_base_object { struct ttm_object_file *tfile; struct kref refcount; void (*refcount_release) (struct ttm_base_object **base); - u32 handle; + u64 handle; enum ttm_object_type object_type; u32 shareable; }; @@ -164,7 +164,7 @@ extern int ttm_base_object_init(struct ttm_object_file *tfile, */ extern struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file - *tfile, uint32_t key); + *tfile, uint64_t key); /** * ttm_base_object_lookup_for_ref @@ -178,7 +178,7 @@ extern struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file */ extern struct ttm_base_object * -ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint32_t key); +ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint64_t key); /** * ttm_base_object_unref @@ -237,14 +237,12 @@ extern int ttm_ref_object_base_unref(struct ttm_object_file *tfile, * ttm_object_file_init - initialize a struct ttm_object file * * @tdev: A struct ttm_object device this file is initialized on. - * @hash_order: Order of the hash table used to hold the reference objects. * * This is typically called by the file_ops::open function. */ extern struct ttm_object_file *ttm_object_file_init(struct ttm_object_device - *tdev, - unsigned int hash_order); + *tdev); /** * ttm_object_file_release - release data held by a ttm_object_file @@ -312,7 +310,7 @@ extern int ttm_prime_handle_to_fd(struct ttm_object_file *tfile, kfree_rcu(__obj, __prime.base.rhead) struct ttm_base_object * -ttm_base_object_noref_lookup(struct ttm_object_file *tfile, uint32_t key); +ttm_base_object_noref_lookup(struct ttm_object_file *tfile, uint64_t key); /** * ttm_base_object_noref_release - release a base object pointer looked up diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 8d77e79bd904..b909a3ce9af3 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -1242,7 +1242,7 @@ static int vmw_driver_open(struct drm_device *dev, struct drm_file *file_priv) if (unlikely(!vmw_fp)) return ret; - vmw_fp->tfile = ttm_object_file_init(dev_priv->tdev, 10); + vmw_fp->tfile = ttm_object_file_init(dev_priv->tdev); if (unlikely(vmw_fp->tfile == NULL)) goto out_no_tfile; -- cgit From 9da30cdd6a318595199319708c143ae318f804ef Mon Sep 17 00:00:00 2001 From: Maaz Mombasawala Date: Sat, 22 Oct 2022 00:02:30 -0400 Subject: drm/vmwgfx: Remove vmwgfx_hashtab The vmwgfx driver has migrated from using the hashtable in vmwgfx_hashtab to the linux/hashtable implementation. Remove the vmwgfx_hashtab from the driver. Signed-off-by: Maaz Mombasawala Reviewed-by: Martin Krastev Reviewed-by: Zack Rusin Signed-off-by: Zack Rusin Link: https://patchwork.freedesktop.org/patch/msgid/20221022040236.616490-12-zack@kde.org --- Documentation/gpu/todo.rst | 11 -- drivers/gpu/drm/vmwgfx/Makefile | 2 +- drivers/gpu/drm/vmwgfx/ttm_object.c | 8 +- drivers/gpu/drm/vmwgfx/ttm_object.h | 2 - drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c | 4 +- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 6 +- drivers/gpu/drm/vmwgfx/vmwgfx_hashtab.c | 199 ----------------------------- drivers/gpu/drm/vmwgfx/vmwgfx_hashtab.h | 83 ------------ 8 files changed, 12 insertions(+), 303 deletions(-) delete mode 100644 drivers/gpu/drm/vmwgfx/vmwgfx_hashtab.c delete mode 100644 drivers/gpu/drm/vmwgfx/vmwgfx_hashtab.h diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index 393d218e4a0c..b2c6aaf1edf2 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -651,17 +651,6 @@ See drivers/gpu/drm/amd/display/TODO for tasks. Contact: Harry Wentland, Alex Deucher -vmwgfx: Replace hashtable with Linux' implementation ----------------------------------------------------- - -The vmwgfx driver uses its own hashtable implementation. Replace the -code with Linux' implementation and update the callers. It's mostly a -refactoring task, but the interfaces are different. - -Contact: Zack Rusin, Thomas Zimmermann - -Level: Intermediate - Bootsplash ========== diff --git a/drivers/gpu/drm/vmwgfx/Makefile b/drivers/gpu/drm/vmwgfx/Makefile index eee73b9aa404..68e350f410ad 100644 --- a/drivers/gpu/drm/vmwgfx/Makefile +++ b/drivers/gpu/drm/vmwgfx/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_hashtab.o vmwgfx_kms.o vmwgfx_drv.o \ +vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \ vmwgfx_ioctl.o vmwgfx_resource.o vmwgfx_ttm_buffer.o \ vmwgfx_cmd.o vmwgfx_irq.o vmwgfx_ldu.o vmwgfx_ttm_glue.o \ vmwgfx_overlay.o vmwgfx_gmrid_manager.o vmwgfx_fence.o \ diff --git a/drivers/gpu/drm/vmwgfx/ttm_object.c b/drivers/gpu/drm/vmwgfx/ttm_object.c index c07b81fbc495..932b125ebf3d 100644 --- a/drivers/gpu/drm/vmwgfx/ttm_object.c +++ b/drivers/gpu/drm/vmwgfx/ttm_object.c @@ -284,7 +284,7 @@ ttm_base_object_noref_lookup(struct ttm_object_file *tfile, uint64_t key) } __release(RCU); - return drm_hash_entry(hash, struct ttm_ref_object, hash)->obj; + return hlist_entry(hash, struct ttm_ref_object, hash)->obj; } EXPORT_SYMBOL(ttm_base_object_noref_lookup); @@ -299,7 +299,7 @@ struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile, ret = ttm_tfile_find_ref_rcu(tfile, key, &hash); if (likely(ret == 0)) { - base = drm_hash_entry(hash, struct ttm_ref_object, hash)->obj; + base = hlist_entry(hash, struct ttm_ref_object, hash)->obj; if (!kref_get_unless_zero(&base->refcount)) base = NULL; } @@ -343,7 +343,7 @@ int ttm_ref_object_add(struct ttm_object_file *tfile, ret = ttm_tfile_find_ref_rcu(tfile, base->handle, &hash); if (ret == 0) { - ref = drm_hash_entry(hash, struct ttm_ref_object, hash); + ref = hlist_entry(hash, struct ttm_ref_object, hash); if (kref_get_unless_zero(&ref->kref)) { rcu_read_unlock(); break; @@ -407,7 +407,7 @@ int ttm_ref_object_base_unref(struct ttm_object_file *tfile, spin_unlock(&tfile->lock); return -EINVAL; } - ref = drm_hash_entry(hash, struct ttm_ref_object, hash); + ref = hlist_entry(hash, struct ttm_ref_object, hash); kref_put(&ref->kref, ttm_ref_object_release); spin_unlock(&tfile->lock); return 0; diff --git a/drivers/gpu/drm/vmwgfx/ttm_object.h b/drivers/gpu/drm/vmwgfx/ttm_object.h index 67f30d589e27..f0ebbe340ad6 100644 --- a/drivers/gpu/drm/vmwgfx/ttm_object.h +++ b/drivers/gpu/drm/vmwgfx/ttm_object.h @@ -42,8 +42,6 @@ #include #include -#include "vmwgfx_hashtab.h" - /** * enum ttm_object_type * diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c index 142aef686fcd..47bc0b411055 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c @@ -88,7 +88,7 @@ vmw_cmdbuf_res_lookup(struct vmw_cmdbuf_res_manager *man, hash_for_each_possible_rcu(man->resources, hash, head, key) { if (hash->key == key) - return drm_hash_entry(hash, struct vmw_cmdbuf_res, hash)->res; + return hlist_entry(hash, struct vmw_cmdbuf_res, hash)->res; } return ERR_PTR(-EINVAL); } @@ -243,7 +243,7 @@ int vmw_cmdbuf_res_remove(struct vmw_cmdbuf_res_manager *man, hash_for_each_possible_rcu(man->resources, hash, head, key) { if (hash->key == key) { - entry = drm_hash_entry(hash, struct vmw_cmdbuf_res, hash); + entry = hlist_entry(hash, struct vmw_cmdbuf_res, hash); break; } } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index d87aeedb78d0..7c45c3de0dcf 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -43,7 +43,6 @@ #include "ttm_object.h" #include "vmwgfx_fence.h" -#include "vmwgfx_hashtab.h" #include "vmwgfx_reg.h" #include "vmwgfx_validation.h" @@ -104,6 +103,11 @@ struct vmw_fpriv { bool gb_aware; /* user-space is guest-backed aware */ }; +struct vmwgfx_hash_item { + struct hlist_node head; + unsigned long key; +}; + /** * struct vmw_buffer_object - TTM buffer object with vmwgfx additions * @base: The TTM buffer object diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_hashtab.c b/drivers/gpu/drm/vmwgfx/vmwgfx_hashtab.c deleted file mode 100644 index 06aebc12774e..000000000000 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_hashtab.c +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND. USA. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - * USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * Simple open hash tab implementation. - * - * Authors: - * Thomas Hellström - */ - -#include -#include -#include -#include -#include -#include - -#include - -#include "vmwgfx_hashtab.h" - -int vmwgfx_ht_create(struct vmwgfx_open_hash *ht, unsigned int order) -{ - unsigned int size = 1 << order; - - ht->order = order; - ht->table = NULL; - if (size <= PAGE_SIZE / sizeof(*ht->table)) - ht->table = kcalloc(size, sizeof(*ht->table), GFP_KERNEL); - else - ht->table = vzalloc(array_size(size, sizeof(*ht->table))); - if (!ht->table) { - DRM_ERROR("Out of memory for hash table\n"); - return -ENOMEM; - } - return 0; -} - -void vmwgfx_ht_verbose_list(struct vmwgfx_open_hash *ht, unsigned long key) -{ - struct vmwgfx_hash_item *entry; - struct hlist_head *h_list; - unsigned int hashed_key; - int count = 0; - - hashed_key = hash_long(key, ht->order); - DRM_DEBUG("Key is 0x%08lx, Hashed key is 0x%08x\n", key, hashed_key); - h_list = &ht->table[hashed_key]; - hlist_for_each_entry(entry, h_list, head) - DRM_DEBUG("count %d, key: 0x%08lx\n", count++, entry->key); -} - -static struct hlist_node *vmwgfx_ht_find_key(struct vmwgfx_open_hash *ht, unsigned long key) -{ - struct vmwgfx_hash_item *entry; - struct hlist_head *h_list; - unsigned int hashed_key; - - hashed_key = hash_long(key, ht->order); - h_list = &ht->table[hashed_key]; - hlist_for_each_entry(entry, h_list, head) { - if (entry->key == key) - return &entry->head; - if (entry->key > key) - break; - } - return NULL; -} - -static struct hlist_node *vmwgfx_ht_find_key_rcu(struct vmwgfx_open_hash *ht, unsigned long key) -{ - struct vmwgfx_hash_item *entry; - struct hlist_head *h_list; - unsigned int hashed_key; - - hashed_key = hash_long(key, ht->order); - h_list = &ht->table[hashed_key]; - hlist_for_each_entry_rcu(entry, h_list, head) { - if (entry->key == key) - return &entry->head; - if (entry->key > key) - break; - } - return NULL; -} - -int vmwgfx_ht_insert_item(struct vmwgfx_open_hash *ht, struct vmwgfx_hash_item *item) -{ - struct vmwgfx_hash_item *entry; - struct hlist_head *h_list; - struct hlist_node *parent; - unsigned int hashed_key; - unsigned long key = item->key; - - hashed_key = hash_long(key, ht->order); - h_list = &ht->table[hashed_key]; - parent = NULL; - hlist_for_each_entry(entry, h_list, head) { - if (entry->key == key) - return -EINVAL; - if (entry->key > key) - break; - parent = &entry->head; - } - if (parent) - hlist_add_behind_rcu(&item->head, parent); - else - hlist_add_head_rcu(&item->head, h_list); - return 0; -} - -/* - * Just insert an item and return any "bits" bit key that hasn't been - * used before. - */ -int vmwgfx_ht_just_insert_please(struct vmwgfx_open_hash *ht, struct vmwgfx_hash_item *item, - unsigned long seed, int bits, int shift, - unsigned long add) -{ - int ret; - unsigned long mask = (1UL << bits) - 1; - unsigned long first, unshifted_key; - - unshifted_key = hash_long(seed, bits); - first = unshifted_key; - do { - item->key = (unshifted_key << shift) + add; - ret = vmwgfx_ht_insert_item(ht, item); - if (ret) - unshifted_key = (unshifted_key + 1) & mask; - } while (ret && (unshifted_key != first)); - - if (ret) { - DRM_ERROR("Available key bit space exhausted\n"); - return -EINVAL; - } - return 0; -} - -int vmwgfx_ht_find_item(struct vmwgfx_open_hash *ht, unsigned long key, - struct vmwgfx_hash_item **item) -{ - struct hlist_node *list; - - list = vmwgfx_ht_find_key_rcu(ht, key); - if (!list) - return -EINVAL; - - *item = hlist_entry(list, struct vmwgfx_hash_item, head); - return 0; -} - -int vmwgfx_ht_remove_key(struct vmwgfx_open_hash *ht, unsigned long key) -{ - struct hlist_node *list; - - list = vmwgfx_ht_find_key(ht, key); - if (list) { - hlist_del_init_rcu(list); - return 0; - } - return -EINVAL; -} - -int vmwgfx_ht_remove_item(struct vmwgfx_open_hash *ht, struct vmwgfx_hash_item *item) -{ - hlist_del_init_rcu(&item->head); - return 0; -} - -void vmwgfx_ht_remove(struct vmwgfx_open_hash *ht) -{ - if (ht->table) { - kvfree(ht->table); - ht->table = NULL; - } -} diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_hashtab.h b/drivers/gpu/drm/vmwgfx/vmwgfx_hashtab.h deleted file mode 100644 index a9ce12922e21..000000000000 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_hashtab.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2006 Tungsten Graphics, Inc., Bismack, ND. USA. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - * USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * Simple open hash tab implementation. - * - * Authors: - * Thomas Hellström - */ - -/* - * TODO: Replace this hashtable with Linux' generic implementation - * from . - */ - -#ifndef VMWGFX_HASHTAB_H -#define VMWGFX_HASHTAB_H - -#include - -#define drm_hash_entry(_ptr, _type, _member) container_of(_ptr, _type, _member) - -struct vmwgfx_hash_item { - struct hlist_node head; - unsigned long key; -}; - -struct vmwgfx_open_hash { - struct hlist_head *table; - u8 order; -}; - -int vmwgfx_ht_create(struct vmwgfx_open_hash *ht, unsigned int order); -int vmwgfx_ht_insert_item(struct vmwgfx_open_hash *ht, struct vmwgfx_hash_item *item); -int vmwgfx_ht_just_insert_please(struct vmwgfx_open_hash *ht, struct vmwgfx_hash_item *item, - unsigned long seed, int bits, int shift, - unsigned long add); -int vmwgfx_ht_find_item(struct vmwgfx_open_hash *ht, unsigned long key, - struct vmwgfx_hash_item **item); - -void vmwgfx_ht_verbose_list(struct vmwgfx_open_hash *ht, unsigned long key); -int vmwgfx_ht_remove_key(struct vmwgfx_open_hash *ht, unsigned long key); -int vmwgfx_ht_remove_item(struct vmwgfx_open_hash *ht, struct vmwgfx_hash_item *item); -void vmwgfx_ht_remove(struct vmwgfx_open_hash *ht); - -/* - * RCU-safe interface - * - * The user of this API needs to make sure that two or more instances of the - * hash table manipulation functions are never run simultaneously. - * The lookup function vmwgfx_ht_find_item_rcu may, however, run simultaneously - * with any of the manipulation functions as long as it's called from within - * an RCU read-locked section. - */ -#define vmwgfx_ht_insert_item_rcu vmwgfx_ht_insert_item -#define vmwgfx_ht_just_insert_please_rcu vmwgfx_ht_just_insert_please -#define vmwgfx_ht_remove_key_rcu vmwgfx_ht_remove_key -#define vmwgfx_ht_remove_item_rcu vmwgfx_ht_remove_item -#define vmwgfx_ht_find_item_rcu vmwgfx_ht_find_item - -#endif -- cgit From 1c8d537bbcc9708d667d81ddc2caf43ec753cf05 Mon Sep 17 00:00:00 2001 From: Zack Rusin Date: Sat, 22 Oct 2022 00:02:31 -0400 Subject: drm/vmwgfx: Do not allow invalid bpp's for dumb buffers Dumb buffers allow a very limited set of formats. Basically everything apart from 1, 2 and 4 is expected to return an error. Make vmwgfx follow those guidelines. This fixes igt's dumb_buffer invalid_bpp test on vmwgfx. Signed-off-by: Zack Rusin Reviewed-by: Martin Krastev Reviewed-by: Maaz Mombasawala Link: https://patchwork.freedesktop.org/patch/msgid/20221022040236.616490-13-zack@kde.org --- drivers/gpu/drm/vmwgfx/vmwgfx_bo.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c index 822251aaab0a..d218b15953e0 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c @@ -807,9 +807,23 @@ int vmw_dumb_create(struct drm_file *file_priv, { struct vmw_private *dev_priv = vmw_priv(dev); struct vmw_buffer_object *vbo; + int cpp = DIV_ROUND_UP(args->bpp, 8); int ret; - args->pitch = args->width * ((args->bpp + 7) / 8); + switch (cpp) { + case 1: /* DRM_FORMAT_C8 */ + case 2: /* DRM_FORMAT_RGB565 */ + case 4: /* DRM_FORMAT_XRGB8888 */ + break; + default: + /* + * Dumb buffers don't allow anything else. + * This is tested via IGT's dumb_buffers + */ + return -EINVAL; + } + + args->pitch = args->width * cpp; args->size = ALIGN(args->pitch * args->height, PAGE_SIZE); ret = vmw_gem_object_create_with_handle(dev_priv, file_priv, -- cgit From df42523c12f8d58a41f547f471b46deffd18c203 Mon Sep 17 00:00:00 2001 From: Zack Rusin Date: Sat, 22 Oct 2022 00:02:32 -0400 Subject: drm/vmwgfx: Port the framebuffer code to drm fb helpers Instead of using vmwgfx specific framebuffer implementation use the drm fb helpers. There's no change in functionality, the only difference is a reduction in the amount of code inside the vmwgfx module. drm fb helpers do not deal correctly with changes in crtc preferred mode at runtime, but the old fb code wasn't dealing with it either. Same situation applies to high-res fb consoles - the old code was limited to 1176x885 because it was checking for legacy/deprecated memory limites, the drm fb helpers are limited to the initial resolution set on fb due to first problem (drm fb helpers being unable to handle hotplug crtc preferred mode changes). This also removes the kernel config for disabling fb support which hasn't been used or supported in a very long time. Signed-off-by: Zack Rusin Reviewed-by: Maaz Mombasawala Reviewed-by: Martin Krastev Reviewed-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20221022040236.616490-14-zack@kde.org --- drivers/gpu/drm/vmwgfx/Kconfig | 7 - drivers/gpu/drm/vmwgfx/Makefile | 2 - drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 58 +-- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 35 +- drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 831 ------------------------------------ drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 79 +--- drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 7 - 7 files changed, 28 insertions(+), 991 deletions(-) delete mode 100644 drivers/gpu/drm/vmwgfx/vmwgfx_fb.c diff --git a/drivers/gpu/drm/vmwgfx/Kconfig b/drivers/gpu/drm/vmwgfx/Kconfig index a4fabe208d9f..faddae3d6ac2 100644 --- a/drivers/gpu/drm/vmwgfx/Kconfig +++ b/drivers/gpu/drm/vmwgfx/Kconfig @@ -16,13 +16,6 @@ config DRM_VMWGFX virtual hardware. The compiled module will be called "vmwgfx.ko". -config DRM_VMWGFX_FBCON - depends on DRM_VMWGFX && DRM_FBDEV_EMULATION - bool "Enable framebuffer console under vmwgfx by default" - help - Choose this option if you are shipping a new vmwgfx - userspace driver that supports using the kernel driver. - config DRM_VMWGFX_MKSSTATS bool "Enable mksGuestStats instrumentation of vmwgfx by default" depends on DRM_VMWGFX diff --git a/drivers/gpu/drm/vmwgfx/Makefile b/drivers/gpu/drm/vmwgfx/Makefile index 68e350f410ad..2a644f035597 100644 --- a/drivers/gpu/drm/vmwgfx/Makefile +++ b/drivers/gpu/drm/vmwgfx/Makefile @@ -12,6 +12,4 @@ vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \ vmwgfx_devcaps.o ttm_object.o vmwgfx_system_manager.o \ vmwgfx_gem.o -vmwgfx-$(CONFIG_DRM_FBDEV_EMULATION) += vmwgfx_fb.o - obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index b909a3ce9af3..63496773f714 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -52,9 +53,6 @@ #define VMWGFX_DRIVER_DESC "Linux drm driver for VMware graphics devices" -#define VMW_MIN_INITIAL_WIDTH 800 -#define VMW_MIN_INITIAL_HEIGHT 600 - /* * Fully encoded drm commands. Might move to vmw_drm.h */ @@ -265,7 +263,6 @@ static const struct pci_device_id vmw_pci_id_list[] = { }; MODULE_DEVICE_TABLE(pci, vmw_pci_id_list); -static int enable_fbdev = IS_ENABLED(CONFIG_DRM_VMWGFX_FBCON); static int vmw_restrict_iommu; static int vmw_force_coherent; static int vmw_restrict_dma_mask; @@ -275,8 +272,6 @@ static int vmw_probe(struct pci_dev *, const struct pci_device_id *); static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val, void *ptr); -MODULE_PARM_DESC(enable_fbdev, "Enable vmwgfx fbdev"); -module_param_named(enable_fbdev, enable_fbdev, int, 0600); MODULE_PARM_DESC(restrict_iommu, "Try to limit IOMMU usage for TTM pages"); module_param_named(restrict_iommu, vmw_restrict_iommu, int, 0600); MODULE_PARM_DESC(force_coherent, "Force coherent TTM pages"); @@ -626,8 +621,8 @@ static void vmw_get_initial_size(struct vmw_private *dev_priv) width = vmw_read(dev_priv, SVGA_REG_WIDTH); height = vmw_read(dev_priv, SVGA_REG_HEIGHT); - width = max_t(uint32_t, width, VMW_MIN_INITIAL_WIDTH); - height = max_t(uint32_t, height, VMW_MIN_INITIAL_HEIGHT); + width = max_t(uint32_t, width, VMWGFX_MIN_INITIAL_WIDTH); + height = max_t(uint32_t, height, VMWGFX_MIN_INITIAL_HEIGHT); if (width > dev_priv->fb_max_width || height > dev_priv->fb_max_height) { @@ -636,8 +631,8 @@ static void vmw_get_initial_size(struct vmw_private *dev_priv) * This is a host error and shouldn't occur. */ - width = VMW_MIN_INITIAL_WIDTH; - height = VMW_MIN_INITIAL_HEIGHT; + width = VMWGFX_MIN_INITIAL_WIDTH; + height = VMWGFX_MIN_INITIAL_HEIGHT; } dev_priv->initial_width = width; @@ -886,9 +881,6 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) dev_priv->assume_16bpp = !!vmw_assume_16bpp; - dev_priv->enable_fb = enable_fbdev; - - dev_priv->capabilities = vmw_read(dev_priv, SVGA_REG_CAPABILITIES); vmw_print_bitmap(&dev_priv->drm, "Capabilities", dev_priv->capabilities, @@ -1135,12 +1127,6 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) VMWGFX_DRIVER_PATCHLEVEL, UTS_RELEASE); vmw_write_driver_id(dev_priv); - if (dev_priv->enable_fb) { - vmw_fifo_resource_inc(dev_priv); - vmw_svga_enable(dev_priv); - vmw_fb_init(dev_priv); - } - dev_priv->pm_nb.notifier_call = vmwgfx_pm_notifier; register_pm_notifier(&dev_priv->pm_nb); @@ -1187,12 +1173,9 @@ static void vmw_driver_unload(struct drm_device *dev) unregister_pm_notifier(&dev_priv->pm_nb); vmw_sw_context_fini(dev_priv); - if (dev_priv->enable_fb) { - vmw_fb_off(dev_priv); - vmw_fb_close(dev_priv); - vmw_fifo_resource_dec(dev_priv); - vmw_svga_disable(dev_priv); - } + vmw_fifo_resource_dec(dev_priv); + + vmw_svga_disable(dev_priv); vmw_kms_close(dev_priv); vmw_overlay_close(dev_priv); @@ -1330,8 +1313,6 @@ static void vmw_master_drop(struct drm_device *dev, struct vmw_private *dev_priv = vmw_priv(dev); vmw_kms_legacy_hotspot_clear(dev_priv); - if (!dev_priv->enable_fb) - vmw_svga_disable(dev_priv); } /** @@ -1524,25 +1505,19 @@ static int vmw_pm_freeze(struct device *kdev) DRM_ERROR("Failed to freeze modesetting.\n"); return ret; } - if (dev_priv->enable_fb) - vmw_fb_off(dev_priv); vmw_execbuf_release_pinned_bo(dev_priv); vmw_resource_evict_all(dev_priv); vmw_release_device_early(dev_priv); while (ttm_device_swapout(&dev_priv->bdev, &ctx, GFP_KERNEL) > 0); - if (dev_priv->enable_fb) - vmw_fifo_resource_dec(dev_priv); + vmw_fifo_resource_dec(dev_priv); if (atomic_read(&dev_priv->num_fifo_resources) != 0) { DRM_ERROR("Can't hibernate while 3D resources are active.\n"); - if (dev_priv->enable_fb) - vmw_fifo_resource_inc(dev_priv); + vmw_fifo_resource_inc(dev_priv); WARN_ON(vmw_request_device_late(dev_priv)); dev_priv->suspend_locked = false; if (dev_priv->suspend_state) vmw_kms_resume(dev); - if (dev_priv->enable_fb) - vmw_fb_on(dev_priv); return -EBUSY; } @@ -1562,24 +1537,19 @@ static int vmw_pm_restore(struct device *kdev) vmw_detect_version(dev_priv); - if (dev_priv->enable_fb) - vmw_fifo_resource_inc(dev_priv); + vmw_fifo_resource_inc(dev_priv); ret = vmw_request_device(dev_priv); if (ret) return ret; - if (dev_priv->enable_fb) - __vmw_svga_enable(dev_priv); + __vmw_svga_enable(dev_priv); vmw_fence_fifo_up(dev_priv->fman); dev_priv->suspend_locked = false; if (dev_priv->suspend_state) vmw_kms_resume(&dev_priv->drm); - if (dev_priv->enable_fb) - vmw_fb_on(dev_priv); - return 0; } @@ -1670,6 +1640,10 @@ static int vmw_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (ret) goto out_unload; + vmw_fifo_resource_inc(vmw); + vmw_svga_enable(vmw); + drm_fbdev_generic_setup(&vmw->drm, 0); + vmw_debugfs_gem_init(vmw); vmw_debugfs_resource_managers_init(vmw); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 7c45c3de0dcf..ad470e54d586 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -62,6 +62,9 @@ #define VMWGFX_MAX_DISPLAYS 16 #define VMWGFX_CMD_BOUNCE_INIT_SIZE 32768 +#define VMWGFX_MIN_INITIAL_WIDTH 1280 +#define VMWGFX_MIN_INITIAL_HEIGHT 800 + #define VMWGFX_PCI_ID_SVGA2 0x0405 #define VMWGFX_PCI_ID_SVGA3 0x0406 @@ -551,7 +554,6 @@ struct vmw_private { * Framebuffer info. */ - void *fb_info; enum vmw_display_unit_type active_display_unit; struct vmw_legacy_display *ldu_priv; struct vmw_overlay *overlay_priv; @@ -610,8 +612,6 @@ struct vmw_private { struct mutex cmdbuf_mutex; struct mutex binding_mutex; - bool enable_fb; - /** * PM management. */ @@ -1189,35 +1189,6 @@ extern void vmw_generic_waiter_add(struct vmw_private *dev_priv, u32 flag, extern void vmw_generic_waiter_remove(struct vmw_private *dev_priv, u32 flag, int *waiter_count); - -/** - * Kernel framebuffer - vmwgfx_fb.c - */ - -#ifdef CONFIG_DRM_FBDEV_EMULATION -int vmw_fb_init(struct vmw_private *vmw_priv); -int vmw_fb_close(struct vmw_private *dev_priv); -int vmw_fb_off(struct vmw_private *vmw_priv); -int vmw_fb_on(struct vmw_private *vmw_priv); -#else -static inline int vmw_fb_init(struct vmw_private *vmw_priv) -{ - return 0; -} -static inline int vmw_fb_close(struct vmw_private *dev_priv) -{ - return 0; -} -static inline int vmw_fb_off(struct vmw_private *vmw_priv) -{ - return 0; -} -static inline int vmw_fb_on(struct vmw_private *vmw_priv) -{ - return 0; -} -#endif - /** * Kernel modesetting - vmwgfx_kms.c */ diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c deleted file mode 100644 index 5b85b477e4c6..000000000000 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ /dev/null @@ -1,831 +0,0 @@ -/************************************************************************** - * - * Copyright © 2007 David Airlie - * Copyright © 2009-2015 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - * USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#include -#include - -#include -#include - -#include "vmwgfx_drv.h" -#include "vmwgfx_kms.h" - -#define VMW_DIRTY_DELAY (HZ / 30) - -struct vmw_fb_par { - struct vmw_private *vmw_priv; - - void *vmalloc; - - struct mutex bo_mutex; - struct vmw_buffer_object *vmw_bo; - unsigned bo_size; - struct drm_framebuffer *set_fb; - struct drm_display_mode *set_mode; - u32 fb_x; - u32 fb_y; - bool bo_iowrite; - - u32 pseudo_palette[17]; - - unsigned max_width; - unsigned max_height; - - struct { - spinlock_t lock; - bool active; - unsigned x1; - unsigned y1; - unsigned x2; - unsigned y2; - } dirty; - - struct drm_crtc *crtc; - struct drm_connector *con; - struct delayed_work local_work; -}; - -static int vmw_fb_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, - struct fb_info *info) -{ - struct vmw_fb_par *par = info->par; - u32 *pal = par->pseudo_palette; - - if (regno > 15) { - DRM_ERROR("Bad regno %u.\n", regno); - return 1; - } - - switch (par->set_fb->format->depth) { - case 24: - case 32: - pal[regno] = ((red & 0xff00) << 8) | - (green & 0xff00) | - ((blue & 0xff00) >> 8); - break; - default: - DRM_ERROR("Bad depth %u, bpp %u.\n", - par->set_fb->format->depth, - par->set_fb->format->cpp[0] * 8); - return 1; - } - - return 0; -} - -static int vmw_fb_check_var(struct fb_var_screeninfo *var, - struct fb_info *info) -{ - int depth = var->bits_per_pixel; - struct vmw_fb_par *par = info->par; - struct vmw_private *vmw_priv = par->vmw_priv; - - switch (var->bits_per_pixel) { - case 32: - depth = (var->transp.length > 0) ? 32 : 24; - break; - default: - DRM_ERROR("Bad bpp %u.\n", var->bits_per_pixel); - return -EINVAL; - } - - switch (depth) { - case 24: - var->red.offset = 16; - var->green.offset = 8; - var->blue.offset = 0; - var->red.length = 8; - var->green.length = 8; - var->blue.length = 8; - var->transp.length = 0; - var->transp.offset = 0; - break; - case 32: - var->red.offset = 16; - var->green.offset = 8; - var->blue.offset = 0; - var->red.length = 8; - var->green.length = 8; - var->blue.length = 8; - var->transp.length = 8; - var->transp.offset = 24; - break; - default: - DRM_ERROR("Bad depth %u.\n", depth); - return -EINVAL; - } - - if ((var->xoffset + var->xres) > par->max_width || - (var->yoffset + var->yres) > par->max_height) { - DRM_ERROR("Requested geom can not fit in framebuffer\n"); - return -EINVAL; - } - - if (!vmw_kms_validate_mode_vram(vmw_priv, - var->xres * var->bits_per_pixel/8, - var->yoffset + var->yres)) { - DRM_ERROR("Requested geom can not fit in framebuffer\n"); - return -EINVAL; - } - - return 0; -} - -static int vmw_fb_blank(int blank, struct fb_info *info) -{ - return 0; -} - -/** - * vmw_fb_dirty_flush - flush dirty regions to the kms framebuffer - * - * @work: The struct work_struct associated with this task. - * - * This function flushes the dirty regions of the vmalloc framebuffer to the - * kms framebuffer, and if the kms framebuffer is visible, also updated the - * corresponding displays. Note that this function runs even if the kms - * framebuffer is not bound to a crtc and thus not visible, but it's turned - * off during hibernation using the par->dirty.active bool. - */ -static void vmw_fb_dirty_flush(struct work_struct *work) -{ - struct vmw_fb_par *par = container_of(work, struct vmw_fb_par, - local_work.work); - struct vmw_private *vmw_priv = par->vmw_priv; - struct fb_info *info = vmw_priv->fb_info; - unsigned long irq_flags; - s32 dst_x1, dst_x2, dst_y1, dst_y2, w = 0, h = 0; - u32 cpp, max_x, max_y; - struct drm_clip_rect clip; - struct drm_framebuffer *cur_fb; - u8 *src_ptr, *dst_ptr; - struct vmw_buffer_object *vbo = par->vmw_bo; - void *virtual; - - if (!READ_ONCE(par->dirty.active)) - return; - - mutex_lock(&par->bo_mutex); - cur_fb = par->set_fb; - if (!cur_fb) - goto out_unlock; - - (void) ttm_bo_reserve(&vbo->base, false, false, NULL); - virtual = vmw_bo_map_and_cache(vbo); - if (!virtual) - goto out_unreserve; - - spin_lock_irqsave(&par->dirty.lock, irq_flags); - if (!par->dirty.active) { - spin_unlock_irqrestore(&par->dirty.lock, irq_flags); - goto out_unreserve; - } - - /* - * Handle panning when copying from vmalloc to framebuffer. - * Clip dirty area to framebuffer. - */ - cpp = cur_fb->format->cpp[0]; - max_x = par->fb_x + cur_fb->width; - max_y = par->fb_y + cur_fb->height; - - dst_x1 = par->dirty.x1 - par->fb_x; - dst_y1 = par->dirty.y1 - par->fb_y; - dst_x1 = max_t(s32, dst_x1, 0); - dst_y1 = max_t(s32, dst_y1, 0); - - dst_x2 = par->dirty.x2 - par->fb_x; - dst_y2 = par->dirty.y2 - par->fb_y; - dst_x2 = min_t(s32, dst_x2, max_x); - dst_y2 = min_t(s32, dst_y2, max_y); - w = dst_x2 - dst_x1; - h = dst_y2 - dst_y1; - w = max_t(s32, 0, w); - h = max_t(s32, 0, h); - - par->dirty.x1 = par->dirty.x2 = 0; - par->dirty.y1 = par->dirty.y2 = 0; - spin_unlock_irqrestore(&par->dirty.lock, irq_flags); - - if (w && h) { - dst_ptr = (u8 *)virtual + - (dst_y1 * par->set_fb->pitches[0] + dst_x1 * cpp); - src_ptr = (u8 *)par->vmalloc + - ((dst_y1 + par->fb_y) * info->fix.line_length + - (dst_x1 + par->fb_x) * cpp); - - while (h-- > 0) { - memcpy(dst_ptr, src_ptr, w*cpp); - dst_ptr += par->set_fb->pitches[0]; - src_ptr += info->fix.line_length; - } - - clip.x1 = dst_x1; - clip.x2 = dst_x2; - clip.y1 = dst_y1; - clip.y2 = dst_y2; - } - -out_unreserve: - ttm_bo_unreserve(&vbo->base); - if (w && h) { - WARN_ON_ONCE(par->set_fb->funcs->dirty(cur_fb, NULL, 0, 0, - &clip, 1)); - vmw_cmd_flush(vmw_priv, false); - } -out_unlock: - mutex_unlock(&par->bo_mutex); -} - -static void vmw_fb_dirty_mark(struct vmw_fb_par *par, - unsigned x1, unsigned y1, - unsigned width, unsigned height) -{ - unsigned long flags; - unsigned x2 = x1 + width; - unsigned y2 = y1 + height; - - spin_lock_irqsave(&par->dirty.lock, flags); - if (par->dirty.x1 == par->dirty.x2) { - par->dirty.x1 = x1; - par->dirty.y1 = y1; - par->dirty.x2 = x2; - par->dirty.y2 = y2; - /* if we are active start the dirty work - * we share the work with the defio system */ - if (par->dirty.active) - schedule_delayed_work(&par->local_work, - VMW_DIRTY_DELAY); - } else { - if (x1 < par->dirty.x1) - par->dirty.x1 = x1; - if (y1 < par->dirty.y1) - par->dirty.y1 = y1; - if (x2 > par->dirty.x2) - par->dirty.x2 = x2; - if (y2 > par->dirty.y2) - par->dirty.y2 = y2; - } - spin_unlock_irqrestore(&par->dirty.lock, flags); -} - -static int vmw_fb_pan_display(struct fb_var_screeninfo *var, - struct fb_info *info) -{ - struct vmw_fb_par *par = info->par; - - if ((var->xoffset + var->xres) > var->xres_virtual || - (var->yoffset + var->yres) > var->yres_virtual) { - DRM_ERROR("Requested panning can not fit in framebuffer\n"); - return -EINVAL; - } - - mutex_lock(&par->bo_mutex); - par->fb_x = var->xoffset; - par->fb_y = var->yoffset; - if (par->set_fb) - vmw_fb_dirty_mark(par, par->fb_x, par->fb_y, par->set_fb->width, - par->set_fb->height); - mutex_unlock(&par->bo_mutex); - - return 0; -} - -static void vmw_deferred_io(struct fb_info *info, struct list_head *pagereflist) -{ - struct vmw_fb_par *par = info->par; - unsigned long start, end, min, max; - unsigned long flags; - struct fb_deferred_io_pageref *pageref; - int y1, y2; - - min = ULONG_MAX; - max = 0; - list_for_each_entry(pageref, pagereflist, list) { - start = pageref->offset; - end = start + PAGE_SIZE - 1; - min = min(min, start); - max = max(max, end); - } - - if (min < max) { - y1 = min / info->fix.line_length; - y2 = (max / info->fix.line_length) + 1; - - spin_lock_irqsave(&par->dirty.lock, flags); - par->dirty.x1 = 0; - par->dirty.y1 = y1; - par->dirty.x2 = info->var.xres; - par->dirty.y2 = y2; - spin_unlock_irqrestore(&par->dirty.lock, flags); - - /* - * Since we've already waited on this work once, try to - * execute asap. - */ - cancel_delayed_work(&par->local_work); - schedule_delayed_work(&par->local_work, 0); - } -}; - -static struct fb_deferred_io vmw_defio = { - .delay = VMW_DIRTY_DELAY, - .deferred_io = vmw_deferred_io, -}; - -/* - * Draw code - */ - -static void vmw_fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) -{ - cfb_fillrect(info, rect); - vmw_fb_dirty_mark(info->par, rect->dx, rect->dy, - rect->width, rect->height); -} - -static void vmw_fb_copyarea(struct fb_info *info, const struct fb_copyarea *region) -{ - cfb_copyarea(info, region); - vmw_fb_dirty_mark(info->par, region->dx, region->dy, - region->width, region->height); -} - -static void vmw_fb_imageblit(struct fb_info *info, const struct fb_image *image) -{ - cfb_imageblit(info, image); - vmw_fb_dirty_mark(info->par, image->dx, image->dy, - image->width, image->height); -} - -/* - * Bring up code - */ - -static int vmw_fb_create_bo(struct vmw_private *vmw_priv, - size_t size, struct vmw_buffer_object **out) -{ - struct vmw_buffer_object *vmw_bo; - int ret; - - ret = vmw_bo_create(vmw_priv, size, - &vmw_sys_placement, - false, false, - &vmw_bo_bo_free, &vmw_bo); - if (unlikely(ret != 0)) - return ret; - - *out = vmw_bo; - - return ret; -} - -static int vmw_fb_compute_depth(struct fb_var_screeninfo *var, - int *depth) -{ - switch (var->bits_per_pixel) { - case 32: - *depth = (var->transp.length > 0) ? 32 : 24; - break; - default: - DRM_ERROR("Bad bpp %u.\n", var->bits_per_pixel); - return -EINVAL; - } - - return 0; -} - -static int vmwgfx_set_config_internal(struct drm_mode_set *set) -{ - struct drm_crtc *crtc = set->crtc; - struct drm_modeset_acquire_ctx ctx; - int ret; - - drm_modeset_acquire_init(&ctx, 0); - -restart: - ret = crtc->funcs->set_config(set, &ctx); - - if (ret == -EDEADLK) { - drm_modeset_backoff(&ctx); - goto restart; - } - - drm_modeset_drop_locks(&ctx); - drm_modeset_acquire_fini(&ctx); - - return ret; -} - -static int vmw_fb_kms_detach(struct vmw_fb_par *par, - bool detach_bo, - bool unref_bo) -{ - struct drm_framebuffer *cur_fb = par->set_fb; - int ret; - - /* Detach the KMS framebuffer from crtcs */ - if (par->set_mode) { - struct drm_mode_set set; - - set.crtc = par->crtc; - set.x = 0; - set.y = 0; - set.mode = NULL; - set.fb = NULL; - set.num_connectors = 0; - set.connectors = &par->con; - ret = vmwgfx_set_config_internal(&set); - if (ret) { - DRM_ERROR("Could not unset a mode.\n"); - return ret; - } - drm_mode_destroy(&par->vmw_priv->drm, par->set_mode); - par->set_mode = NULL; - } - - if (cur_fb) { - drm_framebuffer_put(cur_fb); - par->set_fb = NULL; - } - - if (par->vmw_bo && detach_bo && unref_bo) - vmw_bo_unreference(&par->vmw_bo); - - return 0; -} - -static int vmw_fb_kms_framebuffer(struct fb_info *info) -{ - struct drm_mode_fb_cmd2 mode_cmd = {0}; - struct vmw_fb_par *par = info->par; - struct fb_var_screeninfo *var = &info->var; - struct drm_framebuffer *cur_fb; - struct vmw_framebuffer *vfb; - int ret = 0, depth; - size_t new_bo_size; - - ret = vmw_fb_compute_depth(var, &depth); - if (ret) - return ret; - - mode_cmd.width = var->xres; - mode_cmd.height = var->yres; - mode_cmd.pitches[0] = ((var->bits_per_pixel + 7) / 8) * mode_cmd.width; - mode_cmd.pixel_format = - drm_mode_legacy_fb_format(var->bits_per_pixel, depth); - - cur_fb = par->set_fb; - if (cur_fb && cur_fb->width == mode_cmd.width && - cur_fb->height == mode_cmd.height && - cur_fb->format->format == mode_cmd.pixel_format && - cur_fb->pitches[0] == mode_cmd.pitches[0]) - return 0; - - /* Need new buffer object ? */ - new_bo_size = (size_t) mode_cmd.pitches[0] * (size_t) mode_cmd.height; - ret = vmw_fb_kms_detach(par, - par->bo_size < new_bo_size || - par->bo_size > 2*new_bo_size, - true); - if (ret) - return ret; - - if (!par->vmw_bo) { - ret = vmw_fb_create_bo(par->vmw_priv, new_bo_size, - &par->vmw_bo); - if (ret) { - DRM_ERROR("Failed creating a buffer object for " - "fbdev.\n"); - return ret; - } - par->bo_size = new_bo_size; - } - - vfb = vmw_kms_new_framebuffer(par->vmw_priv, par->vmw_bo, NULL, - true, &mode_cmd); - if (IS_ERR(vfb)) - return PTR_ERR(vfb); - - par->set_fb = &vfb->base; - - return 0; -} - -static int vmw_fb_set_par(struct fb_info *info) -{ - struct vmw_fb_par *par = info->par; - struct vmw_private *vmw_priv = par->vmw_priv; - struct drm_mode_set set; - struct fb_var_screeninfo *var = &info->var; - struct drm_display_mode new_mode = { DRM_MODE("fb_mode", - DRM_MODE_TYPE_DRIVER, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) - }; - struct drm_display_mode *mode; - int ret; - - mode = drm_mode_duplicate(&vmw_priv->drm, &new_mode); - if (!mode) { - DRM_ERROR("Could not create new fb mode.\n"); - return -ENOMEM; - } - - mode->hdisplay = var->xres; - mode->vdisplay = var->yres; - vmw_guess_mode_timing(mode); - - if (!vmw_kms_validate_mode_vram(vmw_priv, - mode->hdisplay * - DIV_ROUND_UP(var->bits_per_pixel, 8), - mode->vdisplay)) { - drm_mode_destroy(&vmw_priv->drm, mode); - return -EINVAL; - } - - mutex_lock(&par->bo_mutex); - ret = vmw_fb_kms_framebuffer(info); - if (ret) - goto out_unlock; - - par->fb_x = var->xoffset; - par->fb_y = var->yoffset; - - set.crtc = par->crtc; - set.x = 0; - set.y = 0; - set.mode = mode; - set.fb = par->set_fb; - set.num_connectors = 1; - set.connectors = &par->con; - - ret = vmwgfx_set_config_internal(&set); - if (ret) - goto out_unlock; - - vmw_fb_dirty_mark(par, par->fb_x, par->fb_y, - par->set_fb->width, par->set_fb->height); - - /* If there already was stuff dirty we wont - * schedule a new work, so lets do it now */ - - schedule_delayed_work(&par->local_work, 0); - -out_unlock: - if (par->set_mode) - drm_mode_destroy(&vmw_priv->drm, par->set_mode); - par->set_mode = mode; - - mutex_unlock(&par->bo_mutex); - - return ret; -} - - -static const struct fb_ops vmw_fb_ops = { - .owner = THIS_MODULE, - .fb_check_var = vmw_fb_check_var, - .fb_set_par = vmw_fb_set_par, - .fb_setcolreg = vmw_fb_setcolreg, - .fb_fillrect = vmw_fb_fillrect, - .fb_copyarea = vmw_fb_copyarea, - .fb_imageblit = vmw_fb_imageblit, - .fb_pan_display = vmw_fb_pan_display, - .fb_blank = vmw_fb_blank, - .fb_mmap = fb_deferred_io_mmap, -}; - -int vmw_fb_init(struct vmw_private *vmw_priv) -{ - struct device *device = vmw_priv->drm.dev; - struct vmw_fb_par *par; - struct fb_info *info; - unsigned fb_width, fb_height; - unsigned int fb_bpp, fb_pitch, fb_size; - struct drm_display_mode *init_mode; - int ret; - - fb_bpp = 32; - - /* XXX As shouldn't these be as well. */ - fb_width = min(vmw_priv->fb_max_width, (unsigned)2048); - fb_height = min(vmw_priv->fb_max_height, (unsigned)2048); - - fb_pitch = fb_width * fb_bpp / 8; - fb_size = fb_pitch * fb_height; - - info = framebuffer_alloc(sizeof(*par), device); - if (!info) - return -ENOMEM; - - /* - * Par - */ - vmw_priv->fb_info = info; - par = info->par; - memset(par, 0, sizeof(*par)); - INIT_DELAYED_WORK(&par->local_work, &vmw_fb_dirty_flush); - par->vmw_priv = vmw_priv; - par->vmalloc = NULL; - par->max_width = fb_width; - par->max_height = fb_height; - - ret = vmw_kms_fbdev_init_data(vmw_priv, 0, par->max_width, - par->max_height, &par->con, - &par->crtc, &init_mode); - if (ret) - goto err_kms; - - info->var.xres = init_mode->hdisplay; - info->var.yres = init_mode->vdisplay; - - /* - * Create buffers and alloc memory - */ - par->vmalloc = vzalloc(fb_size); - if (unlikely(par->vmalloc == NULL)) { - ret = -ENOMEM; - goto err_free; - } - - /* - * Fixed and var - */ - strcpy(info->fix.id, "svgadrmfb"); - info->fix.type = FB_TYPE_PACKED_PIXELS; - info->fix.visual = FB_VISUAL_TRUECOLOR; - info->fix.type_aux = 0; - info->fix.xpanstep = 1; /* doing it in hw */ - info->fix.ypanstep = 1; /* doing it in hw */ - info->fix.ywrapstep = 0; - info->fix.accel = FB_ACCEL_NONE; - info->fix.line_length = fb_pitch; - - info->fix.smem_start = 0; - info->fix.smem_len = fb_size; - - info->pseudo_palette = par->pseudo_palette; - info->screen_base = (char __iomem *)par->vmalloc; - info->screen_size = fb_size; - - info->fbops = &vmw_fb_ops; - - /* 24 depth per default */ - info->var.red.offset = 16; - info->var.green.offset = 8; - info->var.blue.offset = 0; - info->var.red.length = 8; - info->var.green.length = 8; - info->var.blue.length = 8; - info->var.transp.offset = 0; - info->var.transp.length = 0; - - info->var.xres_virtual = fb_width; - info->var.yres_virtual = fb_height; - info->var.bits_per_pixel = fb_bpp; - info->var.xoffset = 0; - info->var.yoffset = 0; - info->var.activate = FB_ACTIVATE_NOW; - info->var.height = -1; - info->var.width = -1; - - /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ - info->apertures = alloc_apertures(1); - if (!info->apertures) { - ret = -ENOMEM; - goto err_aper; - } - info->apertures->ranges[0].base = vmw_priv->vram_start; - info->apertures->ranges[0].size = vmw_priv->vram_size; - - /* - * Dirty & Deferred IO - */ - par->dirty.x1 = par->dirty.x2 = 0; - par->dirty.y1 = par->dirty.y2 = 0; - par->dirty.active = true; - spin_lock_init(&par->dirty.lock); - mutex_init(&par->bo_mutex); - info->fbdefio = &vmw_defio; - fb_deferred_io_init(info); - - ret = register_framebuffer(info); - if (unlikely(ret != 0)) - goto err_defio; - - vmw_fb_set_par(info); - - return 0; - -err_defio: - fb_deferred_io_cleanup(info); -err_aper: -err_free: - vfree(par->vmalloc); -err_kms: - framebuffer_release(info); - vmw_priv->fb_info = NULL; - - return ret; -} - -int vmw_fb_close(struct vmw_private *vmw_priv) -{ - struct fb_info *info; - struct vmw_fb_par *par; - - if (!vmw_priv->fb_info) - return 0; - - info = vmw_priv->fb_info; - par = info->par; - - /* ??? order */ - fb_deferred_io_cleanup(info); - cancel_delayed_work_sync(&par->local_work); - unregister_framebuffer(info); - - mutex_lock(&par->bo_mutex); - (void) vmw_fb_kms_detach(par, true, true); - mutex_unlock(&par->bo_mutex); - - vfree(par->vmalloc); - framebuffer_release(info); - - return 0; -} - -int vmw_fb_off(struct vmw_private *vmw_priv) -{ - struct fb_info *info; - struct vmw_fb_par *par; - unsigned long flags; - - if (!vmw_priv->fb_info) - return -EINVAL; - - info = vmw_priv->fb_info; - par = info->par; - - spin_lock_irqsave(&par->dirty.lock, flags); - par->dirty.active = false; - spin_unlock_irqrestore(&par->dirty.lock, flags); - - flush_delayed_work(&info->deferred_work); - flush_delayed_work(&par->local_work); - - return 0; -} - -int vmw_fb_on(struct vmw_private *vmw_priv) -{ - struct fb_info *info; - struct vmw_fb_par *par; - unsigned long flags; - - if (!vmw_priv->fb_info) - return -EINVAL; - - info = vmw_priv->fb_info; - par = info->par; - - spin_lock_irqsave(&par->dirty.lock, flags); - par->dirty.active = true; - spin_unlock_irqrestore(&par->dirty.lock, flags); - - /* - * Need to reschedule a dirty update, because otherwise that's - * only done in dirty_mark() if the previous coalesced - * dirty region was empty. - */ - schedule_delayed_work(&par->local_work, 0); - - return 0; -} diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index ff79668ad334..36e7dc3736fe 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -2203,6 +2203,8 @@ int vmw_kms_init(struct vmw_private *dev_priv) dev->mode_config.min_height = 1; dev->mode_config.max_width = dev_priv->texture_max_width; dev->mode_config.max_height = dev_priv->texture_max_height; + dev->mode_config.preferred_depth = dev_priv->assume_16bpp ? 16 : 32; + dev->mode_config.prefer_shadow_fbdev = !dev_priv->has_mob; drm_mode_create_suggested_offset_properties(dev); vmw_kms_create_hotplug_mode_update_property(dev_priv); @@ -2372,8 +2374,8 @@ retry: du->gui_x = rects[du->unit].x1; du->gui_y = rects[du->unit].y1; } else { - du->pref_width = 800; - du->pref_height = 600; + du->pref_width = VMWGFX_MIN_INITIAL_WIDTH; + du->pref_height = VMWGFX_MIN_INITIAL_HEIGHT; du->pref_active = false; du->gui_x = 0; du->gui_y = 0; @@ -2400,13 +2402,13 @@ retry: } con->status = vmw_du_connector_detect(con, true); } - - drm_sysfs_hotplug_event(dev); out_fini: drm_modeset_drop_locks(&ctx); drm_modeset_acquire_fini(&ctx); mutex_unlock(&dev->mode_config.mutex); + drm_sysfs_hotplug_event(dev); + return 0; } @@ -2686,10 +2688,9 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, int ret, i; if (!arg->num_outputs) { - struct drm_rect def_rect = {0, 0, 800, 600}; - VMW_DEBUG_KMS("Default layout x1 = %d y1 = %d x2 = %d y2 = %d\n", - def_rect.x1, def_rect.y1, - def_rect.x2, def_rect.y2); + struct drm_rect def_rect = {0, 0, + VMWGFX_MIN_INITIAL_WIDTH, + VMWGFX_MIN_INITIAL_HEIGHT}; vmw_du_update_layout(dev_priv, 1, &def_rect); return 0; } @@ -2984,68 +2985,6 @@ int vmw_kms_update_proxy(struct vmw_resource *res, return 0; } -int vmw_kms_fbdev_init_data(struct vmw_private *dev_priv, - unsigned unit, - u32 max_width, - u32 max_height, - struct drm_connector **p_con, - struct drm_crtc **p_crtc, - struct drm_display_mode **p_mode) -{ - struct drm_connector *con; - struct vmw_display_unit *du; - struct drm_display_mode *mode; - int i = 0; - int ret = 0; - - mutex_lock(&dev_priv->drm.mode_config.mutex); - list_for_each_entry(con, &dev_priv->drm.mode_config.connector_list, - head) { - if (i == unit) - break; - - ++i; - } - - if (&con->head == &dev_priv->drm.mode_config.connector_list) { - DRM_ERROR("Could not find initial display unit.\n"); - ret = -EINVAL; - goto out_unlock; - } - - if (list_empty(&con->modes)) - (void) vmw_du_connector_fill_modes(con, max_width, max_height); - - if (list_empty(&con->modes)) { - DRM_ERROR("Could not find initial display mode.\n"); - ret = -EINVAL; - goto out_unlock; - } - - du = vmw_connector_to_du(con); - *p_con = con; - *p_crtc = &du->crtc; - - list_for_each_entry(mode, &con->modes, head) { - if (mode->type & DRM_MODE_TYPE_PREFERRED) - break; - } - - if (&mode->head == &con->modes) { - WARN_ONCE(true, "Could not find initial preferred mode.\n"); - *p_mode = list_first_entry(&con->modes, - struct drm_display_mode, - head); - } else { - *p_mode = mode; - } - - out_unlock: - mutex_unlock(&dev_priv->drm.mode_config.mutex); - - return ret; -} - /** * vmw_kms_create_implicit_placement_property - Set up the implicit placement * property. diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index 13a265ffd9f8..4d6e7b555db7 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -462,13 +462,6 @@ vmw_kms_new_framebuffer(struct vmw_private *dev_priv, struct vmw_surface *surface, bool only_2d, const struct drm_mode_fb_cmd2 *mode_cmd); -int vmw_kms_fbdev_init_data(struct vmw_private *dev_priv, - unsigned unit, - u32 max_width, - u32 max_height, - struct drm_connector **p_con, - struct drm_crtc **p_crtc, - struct drm_display_mode **p_mode); void vmw_guess_mode_timing(struct drm_display_mode *mode); void vmw_kms_update_implicit_fb(struct vmw_private *dev_priv); void vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv); -- cgit From 2e10cdc6e85de5998b0b140deff01765ceb92f64 Mon Sep 17 00:00:00 2001 From: Zack Rusin Date: Sat, 22 Oct 2022 00:02:33 -0400 Subject: drm/vmwgfx: Remove explicit and broken vblank handling The explicit vblank handling was never finished. The driver never had the full implementation of vblank and what was there is emulated by DRM when the driver doesn't pretend to be implementing it itself. Let DRM handle the vblank emulation and stop pretending the driver is doing anything special with vblank. In the future it would make sense to implement helpers for full vblank handling because vkms and amdgpu_vkms already have that code. Exporting it to common helpers and having all three drivers share it would make sense (that would be largely just to allow more of igt to run). Signed-off-by: Zack Rusin Reviewed-by: Maaz Mombasawala Reviewed-by: Martin Krastev Reviewed-by: Michael Banack Link: https://patchwork.freedesktop.org/patch/msgid/20221022040236.616490-15-zack@kde.org --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 3 --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 34 ---------------------------------- drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 8 -------- drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 31 +------------------------------ drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 26 -------------------------- 5 files changed, 1 insertion(+), 101 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index ad470e54d586..4eb7339dd121 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -1208,9 +1208,6 @@ int vmw_kms_write_svga(struct vmw_private *vmw_priv, bool vmw_kms_validate_mode_vram(struct vmw_private *dev_priv, uint32_t pitch, uint32_t height); -u32 vmw_get_vblank_counter(struct drm_crtc *crtc); -int vmw_enable_vblank(struct drm_crtc *crtc); -void vmw_disable_vblank(struct drm_crtc *crtc); int vmw_kms_present(struct vmw_private *dev_priv, struct drm_file *file_priv, struct vmw_framebuffer *vfb, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 36e7dc3736fe..0342efdf9063 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -31,7 +31,6 @@ #include #include #include -#include #include "vmwgfx_kms.h" @@ -981,15 +980,6 @@ void vmw_du_crtc_atomic_begin(struct drm_crtc *crtc, void vmw_du_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *state) { - struct drm_pending_vblank_event *event = crtc->state->event; - - if (event) { - crtc->state->event = NULL; - - spin_lock_irq(&crtc->dev->event_lock); - drm_crtc_send_vblank_event(crtc, event); - spin_unlock_irq(&crtc->dev->event_lock); - } } @@ -2307,30 +2297,6 @@ bool vmw_kms_validate_mode_vram(struct vmw_private *dev_priv, dev_priv->max_primary_mem : dev_priv->vram_size); } - -/* - * Function called by DRM code called with vbl_lock held. - */ -u32 vmw_get_vblank_counter(struct drm_crtc *crtc) -{ - return 0; -} - -/* - * Function called by DRM code called with vbl_lock held. - */ -int vmw_enable_vblank(struct drm_crtc *crtc) -{ - return -EINVAL; -} - -/* - * Function called by DRM code called with vbl_lock held. - */ -void vmw_disable_vblank(struct drm_crtc *crtc) -{ -} - /** * vmw_du_update_layout - Update the display unit with topology from resolution * plugin and generate DRM uevent diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index b8761f16dd78..a56e5d0ca3c6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -28,7 +28,6 @@ #include #include #include -#include #include "vmwgfx_kms.h" @@ -235,9 +234,6 @@ static const struct drm_crtc_funcs vmw_legacy_crtc_funcs = { .atomic_duplicate_state = vmw_du_crtc_duplicate_state, .atomic_destroy_state = vmw_du_crtc_destroy_state, .set_config = drm_atomic_helper_set_config, - .get_vblank_counter = vmw_get_vblank_counter, - .enable_vblank = vmw_enable_vblank, - .disable_vblank = vmw_disable_vblank, }; @@ -507,10 +503,6 @@ int vmw_kms_ldu_init_display(struct vmw_private *dev_priv) dev_priv->ldu_priv->last_num_active = 0; dev_priv->ldu_priv->fb = NULL; - ret = drm_vblank_init(dev, num_display_units); - if (ret != 0) - goto err_free; - vmw_kms_create_implicit_placement_property(dev_priv); for (i = 0; i < num_display_units; ++i) { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index ecd3c2fc978b..8db61c541a80 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -29,7 +29,6 @@ #include #include #include -#include #include "vmwgfx_kms.h" @@ -320,9 +319,6 @@ static const struct drm_crtc_funcs vmw_screen_object_crtc_funcs = { .atomic_destroy_state = vmw_du_crtc_destroy_state, .set_config = drm_atomic_helper_set_config, .page_flip = drm_atomic_helper_page_flip, - .get_vblank_counter = vmw_get_vblank_counter, - .enable_vblank = vmw_enable_vblank, - .disable_vblank = vmw_disable_vblank, }; /* @@ -730,7 +726,6 @@ vmw_sou_primary_plane_atomic_update(struct drm_plane *plane, struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane); struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane); struct drm_crtc *crtc = new_state->crtc; - struct drm_pending_vblank_event *event = NULL; struct vmw_fence_obj *fence = NULL; int ret; @@ -754,24 +749,6 @@ vmw_sou_primary_plane_atomic_update(struct drm_plane *plane, return; } - /* For error case vblank event is send from vmw_du_crtc_atomic_flush */ - event = crtc->state->event; - if (event && fence) { - struct drm_file *file_priv = event->base.file_priv; - - ret = vmw_event_fence_action_queue(file_priv, - fence, - &event->base, - &event->event.vbl.tv_sec, - &event->event.vbl.tv_usec, - true); - - if (unlikely(ret != 0)) - DRM_ERROR("Failed to queue event on fence.\n"); - else - crtc->state->event = NULL; - } - if (fence) vmw_fence_obj_unreference(&fence); } @@ -947,18 +924,12 @@ err_free: int vmw_kms_sou_init_display(struct vmw_private *dev_priv) { struct drm_device *dev = &dev_priv->drm; - int i, ret; + int i; if (!(dev_priv->capabilities & SVGA_CAP_SCREEN_OBJECT_2)) { return -ENOSYS; } - ret = -ENOMEM; - - ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS); - if (unlikely(ret != 0)) - return ret; - for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) vmw_sou_init(dev_priv, i); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index 8650c3aea8f0..0090abe89254 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -29,7 +29,6 @@ #include #include #include -#include #include "vmwgfx_kms.h" #include "vmw_surface_cache.h" @@ -925,9 +924,6 @@ static const struct drm_crtc_funcs vmw_stdu_crtc_funcs = { .atomic_destroy_state = vmw_du_crtc_destroy_state, .set_config = drm_atomic_helper_set_config, .page_flip = drm_atomic_helper_page_flip, - .get_vblank_counter = vmw_get_vblank_counter, - .enable_vblank = vmw_enable_vblank, - .disable_vblank = vmw_disable_vblank, }; @@ -1591,7 +1587,6 @@ vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane, struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state); struct drm_crtc *crtc = new_state->crtc; struct vmw_screen_target_display_unit *stdu; - struct drm_pending_vblank_event *event; struct vmw_fence_obj *fence = NULL; struct vmw_private *dev_priv; int ret; @@ -1640,23 +1635,6 @@ vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane, return; } - /* In case of error, vblank event is send in vmw_du_crtc_atomic_flush */ - event = crtc->state->event; - if (event && fence) { - struct drm_file *file_priv = event->base.file_priv; - - ret = vmw_event_fence_action_queue(file_priv, - fence, - &event->base, - &event->event.vbl.tv_sec, - &event->event.vbl.tv_usec, - true); - if (ret) - DRM_ERROR("Failed to queue event on fence.\n"); - else - crtc->state->event = NULL; - } - if (fence) vmw_fence_obj_unreference(&fence); } @@ -1883,10 +1861,6 @@ int vmw_kms_stdu_init_display(struct vmw_private *dev_priv) if (!(dev_priv->capabilities & SVGA_CAP_GBOBJECTS)) return -ENOSYS; - ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS); - if (unlikely(ret != 0)) - return ret; - dev_priv->active_display_unit = vmw_du_screen_target; for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) { -- cgit From 4bb50606cba221028f3b03e6a90f555d5d658cfc Mon Sep 17 00:00:00 2001 From: Zack Rusin Date: Sat, 22 Oct 2022 00:02:34 -0400 Subject: drm/vmwgfx: Add a mksstat counter for cotable resizes There's been a lot of cotable resizes on startup which we can track by adding a mks stat to measure both the invocation count and time spent doing cotable resizes. This is only used if kernel is configured with CONFIG_DRM_VMWGFX_MKSSTATS The stats are collected on the host size inside the vmware-stats.log file. Signed-off-by: Zack Rusin Reviewed-by: Michael Banack Reviewed-by: Martin Krastev Reviewed-by: Maaz Mombasawala Link: https://patchwork.freedesktop.org/patch/msgid/20221022040236.616490-16-zack@kde.org --- drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c | 13 +++++++++++-- drivers/gpu/drm/vmwgfx/vmwgfx_mksstat.h | 2 ++ drivers/gpu/drm/vmwgfx/vmwgfx_msg.c | 16 +++++++++------- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c index 79b30dc9d825..a4c30f950d7c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c @@ -33,6 +33,7 @@ #include #include "vmwgfx_drv.h" +#include "vmwgfx_mksstat.h" #include "vmwgfx_resource_priv.h" #include "vmwgfx_so.h" @@ -395,9 +396,12 @@ static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size) int ret; size_t i; + MKS_STAT_TIME_DECL(MKSSTAT_KERN_COTABLE_RESIZE); + MKS_STAT_TIME_PUSH(MKSSTAT_KERN_COTABLE_RESIZE); + ret = vmw_cotable_readback(res); if (ret) - return ret; + goto out_done; cur_size_read_back = vcotbl->size_read_back; vcotbl->size_read_back = old_size_read_back; @@ -411,7 +415,7 @@ static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size) true, true, vmw_bo_bo_free, &buf); if (ret) { DRM_ERROR("Failed initializing new cotable MOB.\n"); - return ret; + goto out_done; } bo = &buf->base; @@ -485,6 +489,8 @@ static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size) /* Release the pin acquired in vmw_bo_init */ ttm_bo_unpin(bo); + MKS_STAT_TIME_POP(MKSSTAT_KERN_COTABLE_RESIZE); + return 0; out_map_new: @@ -494,6 +500,9 @@ out_wait: ttm_bo_unreserve(bo); vmw_bo_unreference(&buf); +out_done: + MKS_STAT_TIME_POP(MKSSTAT_KERN_COTABLE_RESIZE); + return ret; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_mksstat.h b/drivers/gpu/drm/vmwgfx/vmwgfx_mksstat.h index 0509f55f07b4..ede74c7fdbbf 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_mksstat.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_mksstat.h @@ -29,6 +29,7 @@ #define _VMWGFX_MKSSTAT_H_ #include +#include /* Reservation marker for mksstat pid's */ #define MKSSTAT_PID_RESERVED -1 @@ -41,6 +42,7 @@ typedef enum { MKSSTAT_KERN_EXECBUF, /* vmw_execbuf_ioctl */ + MKSSTAT_KERN_COTABLE_RESIZE, MKSSTAT_KERN_COUNT /* Reserved entry; always last */ } mksstat_kern_stats_t; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c index 50d8b9bcd72a..06d9e106e3c5 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c @@ -85,7 +85,14 @@ struct rpc_channel { u32 cookie_low; }; - +#if IS_ENABLED(CONFIG_DRM_VMWGFX_MKSSTATS) +/* Kernel mksGuestStats counter names and desciptions; same order as enum mksstat_kern_stats_t */ +static const char* const mksstat_kern_name_desc[MKSSTAT_KERN_COUNT][2] = +{ + { "vmw_execbuf_ioctl", "vmw_execbuf_ioctl" }, + { "vmw_cotable_resize", "vmw_cotable_resize" }, +}; +#endif /** * vmw_open_channel @@ -695,12 +702,6 @@ static inline void hypervisor_ppn_remove(PPN64 pfn) /* Header to the text description of mksGuestStat instance descriptor */ #define MKSSTAT_KERNEL_DESCRIPTION "vmwgfx" -/* Kernel mksGuestStats counter names and desciptions; same order as enum mksstat_kern_stats_t */ -static const char* const mksstat_kern_name_desc[MKSSTAT_KERN_COUNT][2] = -{ - { "vmw_execbuf_ioctl", "vmw_execbuf_ioctl" }, -}; - /** * mksstat_init_record: Initializes an MKSGuestStatCounter-based record * for the respective mksGuestStat index. @@ -786,6 +787,7 @@ static int mksstat_init_kern_id(struct page **ppage) /* Set up all kernel-internal counters and corresponding structures */ pstrs_acc = pstrs; pstrs_acc = mksstat_init_record_time(MKSSTAT_KERN_EXECBUF, pstat, pinfo, pstrs_acc); + pstrs_acc = mksstat_init_record_time(MKSSTAT_KERN_COTABLE_RESIZE, pstat, pinfo, pstrs_acc); /* Add new counters above, in their order of appearance in mksstat_kern_stats_t */ -- cgit From 148e5f5529ac19c8a1aeabe6e11c92a39e44cc6a Mon Sep 17 00:00:00 2001 From: Zack Rusin Date: Sat, 22 Oct 2022 00:02:35 -0400 Subject: drm/vmwgfx: Optimize initial sizes of cotables It's important to get the initial size of cotables right because otherwise every app needs to start with a synchronous cotable resize. This has an measurable impact on system wide performance but is not relevant for long running single full screen apps for which the cotable resizes will happen early in the lifecycle and will continue running just fine. To eliminate the initial cotable resizes match the initial sizes to what the userspace expects. The actual result of the patch is simply setting the initial size of two of the cotables to a size that will align them to two pages instead of one. For a piglit run, before: name | total | per frame | per sec vmw_cotable_resize | 1405 | 0.12 | 1.58 vmw_execbuf_ioctl | 290805 | 25.43 | 326.05 After: name | total | per frame | per sec vmw_cotable_resize | 4 | 0.00 | 0.00 vmw_execbuf_ioctl | 281673 | 25.10 | 274.68 Signed-off-by: Zack Rusin Reviewed-by: Michael Banack Link: https://patchwork.freedesktop.org/patch/msgid/20221022040236.616490-17-zack@kde.org --- drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c index a4c30f950d7c..0422b6b89cc1 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c @@ -73,12 +73,24 @@ struct vmw_cotable_info { bool); }; + +/* + * Getting the initial size right is difficult because it all depends + * on what the userspace is doing. The sizes will be aligned up to + * a PAGE_SIZE so we just want to make sure that for majority of apps + * the initial number of entries doesn't require an immediate resize. + * For all cotables except SVGACOTableDXElementLayoutEntry and + * SVGACOTableDXBlendStateEntry the initial number of entries fits + * within the PAGE_SIZE. For SVGACOTableDXElementLayoutEntry and + * SVGACOTableDXBlendStateEntry we want to reserve two pages, + * because that's what all apps will require initially. + */ static const struct vmw_cotable_info co_info[] = { {1, sizeof(SVGACOTableDXRTViewEntry), &vmw_view_cotable_list_destroy}, {1, sizeof(SVGACOTableDXDSViewEntry), &vmw_view_cotable_list_destroy}, {1, sizeof(SVGACOTableDXSRViewEntry), &vmw_view_cotable_list_destroy}, - {1, sizeof(SVGACOTableDXElementLayoutEntry), NULL}, - {1, sizeof(SVGACOTableDXBlendStateEntry), NULL}, + {PAGE_SIZE/sizeof(SVGACOTableDXElementLayoutEntry) + 1, sizeof(SVGACOTableDXElementLayoutEntry), NULL}, + {PAGE_SIZE/sizeof(SVGACOTableDXBlendStateEntry) + 1, sizeof(SVGACOTableDXBlendStateEntry), NULL}, {1, sizeof(SVGACOTableDXDepthStencilEntry), NULL}, {1, sizeof(SVGACOTableDXRasterizerStateEntry), NULL}, {1, sizeof(SVGACOTableDXSamplerEntry), NULL}, -- cgit From 71bb70f87d636c875212d75ecdde048588914e19 Mon Sep 17 00:00:00 2001 From: Zack Rusin Date: Sat, 22 Oct 2022 00:02:36 -0400 Subject: drm/vmwgfx: Fix a sparse warning in kernel docs Fixes a warning about extra docs about a function argument that has been removed a while back: drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c:3888: warning: Excess function parameter 'sync_file' description in 'vmw_execbuf_copy_fence_user' Fixes: a0f90c881570 ("drm/vmwgfx: Fix stale file descriptors on failed usercopy") Signed-off-by: Zack Rusin Reviewed-by: Martin Krastev Reviewed-by: Maaz Mombasawala Link: https://patchwork.freedesktop.org/patch/msgid/20221022040236.616490-18-zack@kde.org --- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index c943ab801ca7..f16fc489d725 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -3869,7 +3869,6 @@ int vmw_execbuf_fence_commands(struct drm_file *file_priv, * @fence: Pointer to the fenc object. * @fence_handle: User-space fence handle. * @out_fence_fd: exported file descriptor for the fence. -1 if not used - * @sync_file: Only used to clean up in case of an error in this function. * * This function copies fence information to user-space. If copying fails, the * user-space struct drm_vmw_fence_rep::error member is hopefully left -- cgit From 5ca1493e252a8b9cdb573b45bea200735dfbddb9 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 24 Oct 2022 19:15:10 +0300 Subject: drm/i915: Make ilk_load_luts() deal with degamma MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make ilk_load_luts() ready for a degamma lut. Currently we never have one, but soon we may get one from readout, and I think we may want to change the state computation such that we may end up with one even when userspace has simply supplied a gamma lut. At least the code now follows the path laid out by the ivb/bdw counterpars. Reviewed-by: Uma Shankar Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221024161514.5340-2-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_color.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index 123c57ceeb73..ff5f462b1c49 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -649,13 +649,15 @@ static void ilk_load_luts(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut; + const struct drm_property_blob *degamma_lut = crtc_state->hw.degamma_lut; + const struct drm_property_blob *blob = gamma_lut ?: degamma_lut; switch (crtc_state->gamma_mode) { case GAMMA_MODE_MODE_8BIT: - ilk_load_lut_8(crtc, gamma_lut); + ilk_load_lut_8(crtc, blob); break; case GAMMA_MODE_MODE_10BIT: - ilk_load_lut_10(crtc, gamma_lut); + ilk_load_lut_10(crtc, blob); break; default: MISSING_CASE(crtc_state->gamma_mode); -- cgit From 18f1b5ae7ecab0a3009e49ac7d183c59bb11c284 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 24 Oct 2022 19:15:11 +0300 Subject: drm/i915: Introduce crtc_state->{pre,post}_csc_lut MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an extra remapping step between the logical state of the LUTs (hw.(de)gamma_lut) as specified via uapi/bigjoiner copy vs. the actual state of the LUTs programmed into the hardware. With this we should be finally able finish the (de)gamma readout/state checker support for the remaining platforms (ilk-skl) where the same hardware LUT can be positioned either before or after the pipe CSC unit. Where we position it depends on factors such as presence of the logical degamma LUT, RGB vs. YCbCr output, full vs. limited RGB quantization range. Without the extra remapping step the state readout doesn't really know whether the LUT read from the hardware is the degamma or gamma LUT, and so we is unable to accurately store it into our crtc state. With the remapping step we know exactly where to put it given the order of the LUT vs. CSC in the hardware state. Only the initial hw->uapi state readout done during driver load/resume still has the problem of not really knowing what to do with the LUT(s). But we can just assume 1:1 mapping there and let subsequent commits fix things up. Another benefit is that we now have a place for purely internal LUTs, without complicating the bigjoiner uapi->hw copy logic. This should prove useful for streamlining glk degamma LUT handling. Reviewed-by: Uma Shankar Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221024161514.5340-3-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_atomic.c | 8 ++ drivers/gpu/drm/i915/display/intel_color.c | 141 +++++++++++++-------- .../gpu/drm/i915/display/intel_crtc_state_dump.c | 10 +- drivers/gpu/drm/i915/display/intel_display.c | 2 +- drivers/gpu/drm/i915/display/intel_display_types.h | 4 + drivers/gpu/drm/i915/display/intel_modeset_setup.c | 6 + 6 files changed, 114 insertions(+), 57 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_atomic.c b/drivers/gpu/drm/i915/display/intel_atomic.c index 18f0a5ae3bac..6621aa245caf 100644 --- a/drivers/gpu/drm/i915/display/intel_atomic.c +++ b/drivers/gpu/drm/i915/display/intel_atomic.c @@ -252,6 +252,11 @@ intel_crtc_duplicate_state(struct drm_crtc *crtc) if (crtc_state->hw.gamma_lut) drm_property_blob_get(crtc_state->hw.gamma_lut); + if (crtc_state->pre_csc_lut) + drm_property_blob_get(crtc_state->pre_csc_lut); + if (crtc_state->post_csc_lut) + drm_property_blob_get(crtc_state->post_csc_lut); + crtc_state->update_pipe = false; crtc_state->disable_lp_wm = false; crtc_state->disable_cxsr = false; @@ -274,6 +279,9 @@ static void intel_crtc_put_color_blobs(struct intel_crtc_state *crtc_state) drm_property_blob_put(crtc_state->hw.degamma_lut); drm_property_blob_put(crtc_state->hw.gamma_lut); drm_property_blob_put(crtc_state->hw.ctm); + + drm_property_blob_put(crtc_state->pre_csc_lut); + drm_property_blob_put(crtc_state->post_csc_lut); } void intel_crtc_free_hw_state(struct intel_crtc_state *crtc_state) diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index ff5f462b1c49..2b37e3c2dc3b 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -578,9 +578,9 @@ static void i9xx_load_lut_8(struct intel_crtc *crtc, static void i9xx_load_luts(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut; + const struct drm_property_blob *post_csc_lut = crtc_state->post_csc_lut; - i9xx_load_lut_8(crtc, gamma_lut); + i9xx_load_lut_8(crtc, post_csc_lut); } static void i965_load_lut_10p6(struct intel_crtc *crtc, @@ -606,12 +606,12 @@ static void i965_load_lut_10p6(struct intel_crtc *crtc, static void i965_load_luts(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut; + const struct drm_property_blob *post_csc_lut = crtc_state->post_csc_lut; if (crtc_state->gamma_mode == GAMMA_MODE_MODE_8BIT) - i9xx_load_lut_8(crtc, gamma_lut); + i9xx_load_lut_8(crtc, post_csc_lut); else - i965_load_lut_10p6(crtc, gamma_lut); + i965_load_lut_10p6(crtc, post_csc_lut); } static void ilk_load_lut_8(struct intel_crtc *crtc, @@ -648,9 +648,9 @@ static void ilk_load_lut_10(struct intel_crtc *crtc, static void ilk_load_luts(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut; - const struct drm_property_blob *degamma_lut = crtc_state->hw.degamma_lut; - const struct drm_property_blob *blob = gamma_lut ?: degamma_lut; + const struct drm_property_blob *post_csc_lut = crtc_state->post_csc_lut; + const struct drm_property_blob *pre_csc_lut = crtc_state->pre_csc_lut; + const struct drm_property_blob *blob = post_csc_lut ?: pre_csc_lut; switch (crtc_state->gamma_mode) { case GAMMA_MODE_MODE_8BIT: @@ -764,19 +764,19 @@ static void ivb_load_lut_ext_max(const struct intel_crtc_state *crtc_state) static void ivb_load_luts(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut; - const struct drm_property_blob *degamma_lut = crtc_state->hw.degamma_lut; - const struct drm_property_blob *blob = gamma_lut ?: degamma_lut; + const struct drm_property_blob *post_csc_lut = crtc_state->post_csc_lut; + const struct drm_property_blob *pre_csc_lut = crtc_state->pre_csc_lut; + const struct drm_property_blob *blob = post_csc_lut ?: pre_csc_lut; switch (crtc_state->gamma_mode) { case GAMMA_MODE_MODE_8BIT: ilk_load_lut_8(crtc, blob); break; case GAMMA_MODE_MODE_SPLIT: - ivb_load_lut_10(crtc, degamma_lut, PAL_PREC_SPLIT_MODE | + ivb_load_lut_10(crtc, pre_csc_lut, PAL_PREC_SPLIT_MODE | PAL_PREC_INDEX_VALUE(0)); ivb_load_lut_ext_max(crtc_state); - ivb_load_lut_10(crtc, gamma_lut, PAL_PREC_SPLIT_MODE | + ivb_load_lut_10(crtc, post_csc_lut, PAL_PREC_SPLIT_MODE | PAL_PREC_INDEX_VALUE(512)); break; case GAMMA_MODE_MODE_10BIT: @@ -793,19 +793,19 @@ static void ivb_load_luts(const struct intel_crtc_state *crtc_state) static void bdw_load_luts(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut; - const struct drm_property_blob *degamma_lut = crtc_state->hw.degamma_lut; - const struct drm_property_blob *blob = gamma_lut ?: degamma_lut; + const struct drm_property_blob *post_csc_lut = crtc_state->post_csc_lut; + const struct drm_property_blob *pre_csc_lut = crtc_state->pre_csc_lut; + const struct drm_property_blob *blob = post_csc_lut ?: pre_csc_lut; switch (crtc_state->gamma_mode) { case GAMMA_MODE_MODE_8BIT: ilk_load_lut_8(crtc, blob); break; case GAMMA_MODE_MODE_SPLIT: - bdw_load_lut_10(crtc, degamma_lut, PAL_PREC_SPLIT_MODE | + bdw_load_lut_10(crtc, pre_csc_lut, PAL_PREC_SPLIT_MODE | PAL_PREC_INDEX_VALUE(0)); ivb_load_lut_ext_max(crtc_state); - bdw_load_lut_10(crtc, gamma_lut, PAL_PREC_SPLIT_MODE | + bdw_load_lut_10(crtc, post_csc_lut, PAL_PREC_SPLIT_MODE | PAL_PREC_INDEX_VALUE(512)); break; case GAMMA_MODE_MODE_10BIT: @@ -902,8 +902,8 @@ static void glk_load_degamma_lut_linear(const struct intel_crtc_state *crtc_stat static void glk_load_luts(const struct intel_crtc_state *crtc_state) { - const struct drm_property_blob *degamma_lut = crtc_state->hw.degamma_lut; - const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut; + const struct drm_property_blob *pre_csc_lut = crtc_state->pre_csc_lut; + const struct drm_property_blob *post_csc_lut = crtc_state->post_csc_lut; struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); /* @@ -914,17 +914,17 @@ static void glk_load_luts(const struct intel_crtc_state *crtc_state) * the degama LUT so that we don't have to reload * it every time the pipe CSC is being enabled. */ - if (degamma_lut) - glk_load_degamma_lut(crtc_state, degamma_lut); + if (pre_csc_lut) + glk_load_degamma_lut(crtc_state, pre_csc_lut); else glk_load_degamma_lut_linear(crtc_state); switch (crtc_state->gamma_mode) { case GAMMA_MODE_MODE_8BIT: - ilk_load_lut_8(crtc, gamma_lut); + ilk_load_lut_8(crtc, post_csc_lut); break; case GAMMA_MODE_MODE_10BIT: - bdw_load_lut_10(crtc, gamma_lut, PAL_PREC_INDEX_VALUE(0)); + bdw_load_lut_10(crtc, post_csc_lut, PAL_PREC_INDEX_VALUE(0)); ivb_load_lut_ext_max(crtc_state); break; default: @@ -964,7 +964,7 @@ static void icl_program_gamma_superfine_segment(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - const struct drm_property_blob *blob = crtc_state->hw.gamma_lut; + const struct drm_property_blob *blob = crtc_state->post_csc_lut; const struct drm_color_lut *lut = blob->data; enum pipe pipe = crtc->pipe; int i; @@ -993,7 +993,7 @@ static void icl_program_gamma_multi_segment(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - const struct drm_property_blob *blob = crtc_state->hw.gamma_lut; + const struct drm_property_blob *blob = crtc_state->post_csc_lut; const struct drm_color_lut *lut = blob->data; const struct drm_color_lut *entry; enum pipe pipe = crtc->pipe; @@ -1047,23 +1047,23 @@ icl_program_gamma_multi_segment(const struct intel_crtc_state *crtc_state) static void icl_load_luts(const struct intel_crtc_state *crtc_state) { - const struct drm_property_blob *degamma_lut = crtc_state->hw.degamma_lut; - const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut; + const struct drm_property_blob *pre_csc_lut = crtc_state->pre_csc_lut; + const struct drm_property_blob *post_csc_lut = crtc_state->post_csc_lut; struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - if (degamma_lut) - glk_load_degamma_lut(crtc_state, degamma_lut); + if (pre_csc_lut) + glk_load_degamma_lut(crtc_state, pre_csc_lut); switch (crtc_state->gamma_mode & GAMMA_MODE_MODE_MASK) { case GAMMA_MODE_MODE_8BIT: - ilk_load_lut_8(crtc, gamma_lut); + ilk_load_lut_8(crtc, post_csc_lut); break; case GAMMA_MODE_MODE_12BIT_MULTI_SEGMENTED: icl_program_gamma_superfine_segment(crtc_state); icl_program_gamma_multi_segment(crtc_state); break; case GAMMA_MODE_MODE_10BIT: - bdw_load_lut_10(crtc, gamma_lut, PAL_PREC_INDEX_VALUE(0)); + bdw_load_lut_10(crtc, post_csc_lut, PAL_PREC_INDEX_VALUE(0)); ivb_load_lut_ext_max(crtc_state); break; default: @@ -1139,18 +1139,18 @@ static void chv_load_luts(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - const struct drm_property_blob *degamma_lut = crtc_state->hw.degamma_lut; - const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut; + const struct drm_property_blob *pre_csc_lut = crtc_state->pre_csc_lut; + const struct drm_property_blob *post_csc_lut = crtc_state->post_csc_lut; const struct drm_property_blob *ctm = crtc_state->hw.ctm; if (crtc_state->cgm_mode & CGM_PIPE_MODE_CSC) chv_load_cgm_csc(crtc, ctm); if (crtc_state->cgm_mode & CGM_PIPE_MODE_DEGAMMA) - chv_load_cgm_degamma(crtc, degamma_lut); + chv_load_cgm_degamma(crtc, pre_csc_lut); if (crtc_state->cgm_mode & CGM_PIPE_MODE_GAMMA) - chv_load_cgm_gamma(crtc, gamma_lut); + chv_load_cgm_gamma(crtc, post_csc_lut); else i965_load_luts(crtc_state); @@ -1188,8 +1188,8 @@ static bool intel_can_preload_luts(const struct intel_crtc_state *new_crtc_state const struct intel_crtc_state *old_crtc_state = intel_atomic_get_old_crtc_state(state, crtc); - return !old_crtc_state->hw.gamma_lut && - !old_crtc_state->hw.degamma_lut; + return !old_crtc_state->post_csc_lut && + !old_crtc_state->pre_csc_lut; } static bool chv_can_preload_luts(const struct intel_crtc_state *new_crtc_state) @@ -1208,7 +1208,7 @@ static bool chv_can_preload_luts(const struct intel_crtc_state *new_crtc_state) if (old_crtc_state->cgm_mode || new_crtc_state->cgm_mode) return false; - return !old_crtc_state->hw.gamma_lut; + return !old_crtc_state->post_csc_lut; } static bool glk_can_preload_luts(const struct intel_crtc_state *new_crtc_state) @@ -1226,7 +1226,7 @@ static bool glk_can_preload_luts(const struct intel_crtc_state *new_crtc_state) * linear hardware degamma mid scanout. */ return !old_crtc_state->csc_enable && - !old_crtc_state->hw.gamma_lut; + !old_crtc_state->post_csc_lut; } int intel_color_check(struct intel_crtc_state *crtc_state) @@ -1359,6 +1359,14 @@ static u32 i9xx_gamma_mode(struct intel_crtc_state *crtc_state) return GAMMA_MODE_MODE_10BIT; /* i965+ only */ } +static void intel_assign_luts(struct intel_crtc_state *crtc_state) +{ + drm_property_replace_blob(&crtc_state->pre_csc_lut, + crtc_state->hw.degamma_lut); + drm_property_replace_blob(&crtc_state->post_csc_lut, + crtc_state->hw.gamma_lut); +} + static int i9xx_color_check(struct intel_crtc_state *crtc_state) { int ret; @@ -1377,6 +1385,8 @@ static int i9xx_color_check(struct intel_crtc_state *crtc_state) if (ret) return ret; + intel_assign_luts(crtc_state); + crtc_state->preload_luts = intel_can_preload_luts(crtc_state); return 0; @@ -1431,6 +1441,8 @@ static int chv_color_check(struct intel_crtc_state *crtc_state) if (ret) return ret; + intel_assign_luts(crtc_state); + crtc_state->preload_luts = chv_can_preload_luts(crtc_state); return 0; @@ -1456,10 +1468,29 @@ static u32 ilk_csc_mode(const struct intel_crtc_state *crtc_state) if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB) return CSC_BLACK_SCREEN_OFFSET; + if (crtc_state->hw.degamma_lut) + return CSC_MODE_YUV_TO_RGB; + return CSC_MODE_YUV_TO_RGB | CSC_POSITION_BEFORE_GAMMA; } +static void ilk_assign_luts(struct intel_crtc_state *crtc_state) +{ + if (crtc_state->hw.degamma_lut || + crtc_state->csc_mode & CSC_POSITION_BEFORE_GAMMA) { + drm_property_replace_blob(&crtc_state->pre_csc_lut, + crtc_state->hw.degamma_lut); + drm_property_replace_blob(&crtc_state->post_csc_lut, + crtc_state->hw.gamma_lut); + } else { + drm_property_replace_blob(&crtc_state->pre_csc_lut, + crtc_state->hw.gamma_lut); + drm_property_replace_blob(&crtc_state->post_csc_lut, + NULL); + } +} + static int ilk_color_check(struct intel_crtc_state *crtc_state) { int ret; @@ -1487,6 +1518,8 @@ static int ilk_color_check(struct intel_crtc_state *crtc_state) if (ret) return ret; + ilk_assign_luts(crtc_state); + crtc_state->preload_luts = intel_can_preload_luts(crtc_state); return 0; @@ -1554,6 +1587,8 @@ static int ivb_color_check(struct intel_crtc_state *crtc_state) if (ret) return ret; + ilk_assign_luts(crtc_state); + crtc_state->preload_luts = intel_can_preload_luts(crtc_state); return 0; @@ -1602,6 +1637,8 @@ static int glk_color_check(struct intel_crtc_state *crtc_state) if (ret) return ret; + intel_assign_luts(crtc_state); + crtc_state->preload_luts = glk_can_preload_luts(crtc_state); return 0; @@ -1662,6 +1699,8 @@ static int icl_color_check(struct intel_crtc_state *crtc_state) crtc_state->csc_mode = icl_csc_mode(crtc_state); + intel_assign_luts(crtc_state); + crtc_state->preload_luts = intel_can_preload_luts(crtc_state); return 0; @@ -1867,7 +1906,7 @@ static void i9xx_read_luts(struct intel_crtc_state *crtc_state) if (!crtc_state->gamma_enable) return; - crtc_state->hw.gamma_lut = i9xx_read_lut_8(crtc); + crtc_state->post_csc_lut = i9xx_read_lut_8(crtc); } static struct drm_property_blob *i965_read_lut_10p6(struct intel_crtc *crtc) @@ -1908,9 +1947,9 @@ static void i965_read_luts(struct intel_crtc_state *crtc_state) return; if (crtc_state->gamma_mode == GAMMA_MODE_MODE_8BIT) - crtc_state->hw.gamma_lut = i9xx_read_lut_8(crtc); + crtc_state->post_csc_lut = i9xx_read_lut_8(crtc); else - crtc_state->hw.gamma_lut = i965_read_lut_10p6(crtc); + crtc_state->post_csc_lut = i965_read_lut_10p6(crtc); } static struct drm_property_blob *chv_read_cgm_gamma(struct intel_crtc *crtc) @@ -1944,7 +1983,7 @@ static void chv_read_luts(struct intel_crtc_state *crtc_state) struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); if (crtc_state->cgm_mode & CGM_PIPE_MODE_GAMMA) - crtc_state->hw.gamma_lut = chv_read_cgm_gamma(crtc); + crtc_state->post_csc_lut = chv_read_cgm_gamma(crtc); else i965_read_luts(crtc_state); } @@ -2011,10 +2050,10 @@ static void ilk_read_luts(struct intel_crtc_state *crtc_state) switch (crtc_state->gamma_mode) { case GAMMA_MODE_MODE_8BIT: - crtc_state->hw.gamma_lut = ilk_read_lut_8(crtc); + crtc_state->post_csc_lut = ilk_read_lut_8(crtc); break; case GAMMA_MODE_MODE_10BIT: - crtc_state->hw.gamma_lut = ilk_read_lut_10(crtc); + crtc_state->post_csc_lut = ilk_read_lut_10(crtc); break; default: MISSING_CASE(crtc_state->gamma_mode); @@ -2066,10 +2105,10 @@ static void glk_read_luts(struct intel_crtc_state *crtc_state) switch (crtc_state->gamma_mode) { case GAMMA_MODE_MODE_8BIT: - crtc_state->hw.gamma_lut = ilk_read_lut_8(crtc); + crtc_state->post_csc_lut = ilk_read_lut_8(crtc); break; case GAMMA_MODE_MODE_10BIT: - crtc_state->hw.gamma_lut = bdw_read_lut_10(crtc, PAL_PREC_INDEX_VALUE(0)); + crtc_state->post_csc_lut = bdw_read_lut_10(crtc, PAL_PREC_INDEX_VALUE(0)); break; default: MISSING_CASE(crtc_state->gamma_mode); @@ -2124,13 +2163,13 @@ static void icl_read_luts(struct intel_crtc_state *crtc_state) switch (crtc_state->gamma_mode & GAMMA_MODE_MODE_MASK) { case GAMMA_MODE_MODE_8BIT: - crtc_state->hw.gamma_lut = ilk_read_lut_8(crtc); + crtc_state->post_csc_lut = ilk_read_lut_8(crtc); break; case GAMMA_MODE_MODE_10BIT: - crtc_state->hw.gamma_lut = bdw_read_lut_10(crtc, PAL_PREC_INDEX_VALUE(0)); + crtc_state->post_csc_lut = bdw_read_lut_10(crtc, PAL_PREC_INDEX_VALUE(0)); break; case GAMMA_MODE_MODE_12BIT_MULTI_SEGMENTED: - crtc_state->hw.gamma_lut = icl_read_lut_multi_segment(crtc); + crtc_state->post_csc_lut = icl_read_lut_multi_segment(crtc); break; default: MISSING_CASE(crtc_state->gamma_mode); diff --git a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c index e9212f69c360..98e36ab55e9e 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c +++ b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c @@ -298,11 +298,11 @@ void intel_crtc_state_dump(const struct intel_crtc_state *pipe_config, pipe_config->csc_mode, pipe_config->gamma_mode, pipe_config->gamma_enable, pipe_config->csc_enable); - drm_dbg_kms(&i915->drm, "degamma lut: %d entries, gamma lut: %d entries\n", - pipe_config->hw.degamma_lut ? - drm_color_lut_size(pipe_config->hw.degamma_lut) : 0, - pipe_config->hw.gamma_lut ? - drm_color_lut_size(pipe_config->hw.gamma_lut) : 0); + drm_dbg_kms(&i915->drm, "pre csc lut: %d entries, post csc lut: %d entries\n", + pipe_config->pre_csc_lut ? + drm_color_lut_size(pipe_config->pre_csc_lut) : 0, + pipe_config->post_csc_lut ? + drm_color_lut_size(pipe_config->post_csc_lut) : 0); dump_planes: if (!state) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index c4132a9af3a1..e7a72d105ff4 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -5789,7 +5789,7 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, bp_gamma = intel_color_get_gamma_bit_precision(pipe_config); if (bp_gamma) - PIPE_CONF_CHECK_COLOR_LUT(gamma_mode, hw.gamma_lut, bp_gamma); + PIPE_CONF_CHECK_COLOR_LUT(gamma_mode, post_csc_lut, bp_gamma); if (current_config->active_planes) { PIPE_CONF_CHECK_BOOL(has_psr); diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 8450bb50dc34..5b38937c6bbd 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1001,11 +1001,15 @@ struct intel_crtc_state { */ struct { bool active, enable; + /* logical state of LUTs */ struct drm_property_blob *degamma_lut, *gamma_lut, *ctm; struct drm_display_mode mode, pipe_mode, adjusted_mode; enum drm_scaling_filter scaling_filter; } hw; + /* actual state of LUTs */ + struct drm_property_blob *pre_csc_lut, *post_csc_lut; + /** * quirks - bitfield with hw state readout quirks * diff --git a/drivers/gpu/drm/i915/display/intel_modeset_setup.c b/drivers/gpu/drm/i915/display/intel_modeset_setup.c index 5f56e0335ff0..9d8ca230be39 100644 --- a/drivers/gpu/drm/i915/display/intel_modeset_setup.c +++ b/drivers/gpu/drm/i915/display/intel_modeset_setup.c @@ -155,6 +155,12 @@ static void intel_crtc_copy_hw_to_uapi_state(struct intel_crtc_state *crtc_state crtc_state->uapi.adjusted_mode = crtc_state->hw.adjusted_mode; crtc_state->uapi.scaling_filter = crtc_state->hw.scaling_filter; + /* assume 1:1 mapping */ + drm_property_replace_blob(&crtc_state->hw.degamma_lut, + crtc_state->pre_csc_lut); + drm_property_replace_blob(&crtc_state->hw.gamma_lut, + crtc_state->post_csc_lut); + drm_property_replace_blob(&crtc_state->uapi.degamma_lut, crtc_state->hw.degamma_lut); drm_property_replace_blob(&crtc_state->uapi.gamma_lut, -- cgit From b1d9092240b74dbc925a51b93a193ca23055169f Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 24 Oct 2022 19:15:12 +0300 Subject: drm/i915: Assert {pre,post}_csc_lut were assigned sensibly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since we now have the extra step from hw.(de)gamma_lut into {pre,post}_csc_lut let's make sure we didn't forget to assign them appropriately. Ie. basically making sure intel_color_check() was called when necessary (and that it did its job suitable well). Reviewed-by: Uma Shankar Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221024161514.5340-4-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_color.c | 20 ++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_color.h | 1 + drivers/gpu/drm/i915/display/intel_display.c | 2 ++ 3 files changed, 23 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index 2b37e3c2dc3b..f1d207e0e1b5 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -1359,6 +1359,26 @@ static u32 i9xx_gamma_mode(struct intel_crtc_state *crtc_state) return GAMMA_MODE_MODE_10BIT; /* i965+ only */ } +void intel_color_assert_luts(const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); + + /* make sure {pre,post}_csc_lut were correctly assigned */ + if (DISPLAY_VER(i915) >= 10 || HAS_GMCH(i915)) { + drm_WARN_ON(&i915->drm, + crtc_state->pre_csc_lut != crtc_state->hw.degamma_lut); + drm_WARN_ON(&i915->drm, + crtc_state->post_csc_lut != crtc_state->hw.gamma_lut); + } else { + drm_WARN_ON(&i915->drm, + crtc_state->pre_csc_lut != crtc_state->hw.degamma_lut && + crtc_state->pre_csc_lut != crtc_state->hw.gamma_lut); + drm_WARN_ON(&i915->drm, + crtc_state->post_csc_lut != crtc_state->hw.degamma_lut && + crtc_state->post_csc_lut != crtc_state->hw.gamma_lut); + } +} + static void intel_assign_luts(struct intel_crtc_state *crtc_state) { drm_property_replace_blob(&crtc_state->pre_csc_lut, diff --git a/drivers/gpu/drm/i915/display/intel_color.h b/drivers/gpu/drm/i915/display/intel_color.h index 04984e6000b6..e1d423922f98 100644 --- a/drivers/gpu/drm/i915/display/intel_color.h +++ b/drivers/gpu/drm/i915/display/intel_color.h @@ -24,5 +24,6 @@ int intel_color_get_gamma_bit_precision(const struct intel_crtc_state *crtc_stat bool intel_color_lut_equal(struct drm_property_blob *blob1, struct drm_property_blob *blob2, u32 gamma_mode, u32 bit_precision); +void intel_color_assert_luts(const struct intel_crtc_state *crtc_state); #endif /* __INTEL_COLOR_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index e7a72d105ff4..1572a58df322 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -6886,6 +6886,8 @@ static int intel_atomic_check(struct drm_device *dev, for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { + intel_color_assert_luts(new_crtc_state); + ret = intel_async_flip_check_hw(state, crtc); if (ret) goto fail; -- cgit From 48205f42ae9bad5783e3cee780ce1a670f5b0f83 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 24 Oct 2022 19:15:13 +0300 Subject: drm/i915: Get rid of glk_load_degamma_lut_linear() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since we now have a place (pre_csc_lut) to stuff a purely internal LUT we can replace glk_load_degamma_lut_linear() with such a thing and just rely on the normal glk_load_degamma_lut() to load it as well. drm_mode_config_cleanup() will clean this up for us. v2: Pass on the error pointer Drop a hint about this into the state dump Reviewed-by: Uma Shankar Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221024161514.5340-5-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_color.c | 110 +++++++++++++-------- drivers/gpu/drm/i915/display/intel_color.h | 1 + .../gpu/drm/i915/display/intel_crtc_state_dump.c | 4 +- drivers/gpu/drm/i915/display/intel_display.c | 4 + drivers/gpu/drm/i915/display/intel_display_core.h | 5 + 5 files changed, 82 insertions(+), 42 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index f1d207e0e1b5..66d9eef92c45 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -557,6 +557,32 @@ static void skl_color_commit_arm(const struct intel_crtc_state *crtc_state) crtc_state->csc_mode); } +static struct drm_property_blob * +create_linear_lut(struct drm_i915_private *i915, int lut_size) +{ + struct drm_property_blob *blob; + struct drm_color_lut *lut; + int i; + + blob = drm_property_create_blob(&i915->drm, + sizeof(struct drm_color_lut) * lut_size, + NULL); + if (IS_ERR(blob)) + return blob; + + lut = blob->data; + + for (i = 0; i < lut_size; i++) { + u16 val = 0xffff * i / (lut_size - 1); + + lut[i].red = val; + lut[i].green = val; + lut[i].blue = val; + } + + return blob; +} + static void i9xx_load_lut_8(struct intel_crtc *crtc, const struct drm_property_blob *blob) { @@ -871,53 +897,14 @@ static void glk_load_degamma_lut(const struct intel_crtc_state *crtc_state, intel_de_write_fw(dev_priv, PRE_CSC_GAMC_INDEX(pipe), 0); } -static void glk_load_degamma_lut_linear(const struct intel_crtc_state *crtc_state) -{ - struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - enum pipe pipe = crtc->pipe; - int i, lut_size = INTEL_INFO(dev_priv)->display.color.degamma_lut_size; - - /* - * When setting the auto-increment bit, the hardware seems to - * ignore the index bits, so we need to reset it to index 0 - * separately. - */ - intel_de_write_fw(dev_priv, PRE_CSC_GAMC_INDEX(pipe), 0); - intel_de_write_fw(dev_priv, PRE_CSC_GAMC_INDEX(pipe), - PRE_CSC_GAMC_AUTO_INCREMENT); - - for (i = 0; i < lut_size; i++) { - u32 v = (i << 16) / (lut_size - 1); - - intel_de_write_fw(dev_priv, PRE_CSC_GAMC_DATA(pipe), v); - } - - /* Clamp values > 1.0. */ - while (i++ < 35) - intel_de_write_fw(dev_priv, PRE_CSC_GAMC_DATA(pipe), 1 << 16); - - intel_de_write_fw(dev_priv, PRE_CSC_GAMC_INDEX(pipe), 0); -} - static void glk_load_luts(const struct intel_crtc_state *crtc_state) { const struct drm_property_blob *pre_csc_lut = crtc_state->pre_csc_lut; const struct drm_property_blob *post_csc_lut = crtc_state->post_csc_lut; struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - /* - * On GLK+ both pipe CSC and degamma LUT are controlled - * by csc_enable. Hence for the cases where the CSC is - * needed but degamma LUT is not we need to load a - * linear degamma LUT. In fact we'll just always load - * the degama LUT so that we don't have to reload - * it every time the pipe CSC is being enabled. - */ if (pre_csc_lut) glk_load_degamma_lut(crtc_state, pre_csc_lut); - else - glk_load_degamma_lut_linear(crtc_state); switch (crtc_state->gamma_mode) { case GAMMA_MODE_MODE_8BIT: @@ -1364,11 +1351,17 @@ void intel_color_assert_luts(const struct intel_crtc_state *crtc_state) struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); /* make sure {pre,post}_csc_lut were correctly assigned */ - if (DISPLAY_VER(i915) >= 10 || HAS_GMCH(i915)) { + if (DISPLAY_VER(i915) >= 11 || HAS_GMCH(i915)) { drm_WARN_ON(&i915->drm, crtc_state->pre_csc_lut != crtc_state->hw.degamma_lut); drm_WARN_ON(&i915->drm, crtc_state->post_csc_lut != crtc_state->hw.gamma_lut); + } else if (DISPLAY_VER(i915) == 10) { + drm_WARN_ON(&i915->drm, + crtc_state->pre_csc_lut != crtc_state->hw.degamma_lut && + crtc_state->pre_csc_lut != i915->display.color.glk_linear_degamma_lut); + drm_WARN_ON(&i915->drm, + crtc_state->post_csc_lut != crtc_state->hw.gamma_lut); } else { drm_WARN_ON(&i915->drm, crtc_state->pre_csc_lut != crtc_state->hw.degamma_lut && @@ -1623,6 +1616,25 @@ static u32 glk_gamma_mode(const struct intel_crtc_state *crtc_state) return GAMMA_MODE_MODE_10BIT; } +static void glk_assign_luts(struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); + + intel_assign_luts(crtc_state); + + /* + * On GLK+ both pipe CSC and degamma LUT are controlled + * by csc_enable. Hence for the cases where the CSC is + * needed but degamma LUT is not we need to load a + * linear degamma LUT. In fact we'll just always load + * the degama LUT so that we don't have to reload + * it every time the pipe CSC is being enabled. + */ + if (!crtc_state->pre_csc_lut) + drm_property_replace_blob(&crtc_state->pre_csc_lut, + i915->display.color.glk_linear_degamma_lut); +} + static int glk_color_check(struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); @@ -1657,7 +1669,7 @@ static int glk_color_check(struct intel_crtc_state *crtc_state) if (ret) return ret; - intel_assign_luts(crtc_state); + glk_assign_luts(crtc_state); crtc_state->preload_luts = glk_can_preload_luts(crtc_state); @@ -2287,6 +2299,22 @@ void intel_color_crtc_init(struct intel_crtc *crtc) INTEL_INFO(dev_priv)->display.color.gamma_lut_size); } +int intel_color_init(struct drm_i915_private *i915) +{ + struct drm_property_blob *blob; + + if (DISPLAY_VER(i915) != 10) + return 0; + + blob = create_linear_lut(i915, INTEL_INFO(i915)->display.color.degamma_lut_size); + if (IS_ERR(blob)) + return PTR_ERR(blob); + + i915->display.color.glk_linear_degamma_lut = blob; + + return 0; +} + void intel_color_init_hooks(struct drm_i915_private *i915) { if (HAS_GMCH(i915)) { diff --git a/drivers/gpu/drm/i915/display/intel_color.h b/drivers/gpu/drm/i915/display/intel_color.h index e1d423922f98..2a5ada67774d 100644 --- a/drivers/gpu/drm/i915/display/intel_color.h +++ b/drivers/gpu/drm/i915/display/intel_color.h @@ -14,6 +14,7 @@ struct drm_i915_private; struct drm_property_blob; void intel_color_init_hooks(struct drm_i915_private *i915); +int intel_color_init(struct drm_i915_private *i915); void intel_color_crtc_init(struct intel_crtc *crtc); int intel_color_check(struct intel_crtc_state *crtc_state); void intel_color_commit_noarm(const struct intel_crtc_state *crtc_state); diff --git a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c index 98e36ab55e9e..e3273fe8ddac 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c +++ b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c @@ -298,7 +298,9 @@ void intel_crtc_state_dump(const struct intel_crtc_state *pipe_config, pipe_config->csc_mode, pipe_config->gamma_mode, pipe_config->gamma_enable, pipe_config->csc_enable); - drm_dbg_kms(&i915->drm, "pre csc lut: %d entries, post csc lut: %d entries\n", + drm_dbg_kms(&i915->drm, "pre csc lut: %s%d entries, post csc lut: %d entries\n", + pipe_config->pre_csc_lut && pipe_config->pre_csc_lut == + i915->display.color.glk_linear_degamma_lut ? "(linear) " : "", pipe_config->pre_csc_lut ? drm_color_lut_size(pipe_config->pre_csc_lut) : 0, pipe_config->post_csc_lut ? diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 1572a58df322..0691b49f38f1 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -8658,6 +8658,10 @@ int intel_modeset_init_noirq(struct drm_i915_private *i915) if (ret) goto cleanup_vga_client_pw_domain_dmc; + ret = intel_color_init(i915); + if (ret) + goto cleanup_vga_client_pw_domain_dmc; + ret = intel_dbuf_init(i915); if (ret) goto cleanup_vga_client_pw_domain_dmc; diff --git a/drivers/gpu/drm/i915/display/intel_display_core.h b/drivers/gpu/drm/i915/display/intel_display_core.h index 96cf994b0ad1..b4b9c4cef78e 100644 --- a/drivers/gpu/drm/i915/display/intel_display_core.h +++ b/drivers/gpu/drm/i915/display/intel_display_core.h @@ -28,6 +28,7 @@ struct drm_i915_private; struct drm_property; +struct drm_property_blob; struct i915_audio_component; struct i915_hdcp_comp_master; struct intel_atomic_state; @@ -308,6 +309,10 @@ struct intel_display { unsigned int max_cdclk_freq; } cdclk; + struct { + struct drm_property_blob *glk_linear_degamma_lut; + } color; + struct { /* The current hardware dbuf configuration */ u8 enabled_slices; -- cgit From 0701c285087d79b44546e04dd13b9056443571a3 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 24 Oct 2022 19:15:14 +0300 Subject: drm/i915: Stop loading linear degamma LUT on glk needlessly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make glk_load_luts() a bit lighter for the common case where neither the degamma LUT nor pipe CSC are enabled by not loading the linear degamma LUT. Making .load_luts() as lightweight as possible is a good idea since it may need to execute from a vblank worker under tight deadlines. My earlier reasoning for always loading the linear degamma LUT was to avoid an extra LUT load when just enabling/disabling the pipe CSC, but that is nonsense since we load the LUTs on every flagged color management change/modeset anyway (either of which is needed for a pipe CSC toggle). We can also get rid of the glk_can_preload_luts() special case since the presence of the degamma LUT will now always match csc_enable. v2: Fix typos (Uma) Reviewed-by: Uma Shankar Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221024161514.5340-6-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_color.c | 26 +++----------------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index 66d9eef92c45..4bb113c39f4b 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -1198,24 +1198,6 @@ static bool chv_can_preload_luts(const struct intel_crtc_state *new_crtc_state) return !old_crtc_state->post_csc_lut; } -static bool glk_can_preload_luts(const struct intel_crtc_state *new_crtc_state) -{ - struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc); - struct intel_atomic_state *state = - to_intel_atomic_state(new_crtc_state->uapi.state); - const struct intel_crtc_state *old_crtc_state = - intel_atomic_get_old_crtc_state(state, crtc); - - /* - * The hardware degamma is active whenever the pipe - * CSC is active. Thus even if the old state has no - * software degamma we need to avoid clobbering the - * linear hardware degamma mid scanout. - */ - return !old_crtc_state->csc_enable && - !old_crtc_state->post_csc_lut; -} - int intel_color_check(struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); @@ -1626,11 +1608,9 @@ static void glk_assign_luts(struct intel_crtc_state *crtc_state) * On GLK+ both pipe CSC and degamma LUT are controlled * by csc_enable. Hence for the cases where the CSC is * needed but degamma LUT is not we need to load a - * linear degamma LUT. In fact we'll just always load - * the degama LUT so that we don't have to reload - * it every time the pipe CSC is being enabled. + * linear degamma LUT. */ - if (!crtc_state->pre_csc_lut) + if (crtc_state->csc_enable && !crtc_state->pre_csc_lut) drm_property_replace_blob(&crtc_state->pre_csc_lut, i915->display.color.glk_linear_degamma_lut); } @@ -1671,7 +1651,7 @@ static int glk_color_check(struct intel_crtc_state *crtc_state) glk_assign_luts(crtc_state); - crtc_state->preload_luts = glk_can_preload_luts(crtc_state); + crtc_state->preload_luts = intel_can_preload_luts(crtc_state); return 0; } -- cgit From 0a20a3ea4259ae761597aacd8a088d7e1304e804 Mon Sep 17 00:00:00 2001 From: Zack Rusin Date: Thu, 20 Oct 2022 21:07:03 -0400 Subject: drm/nouveau: Remove unused variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Trivial removal of an unused variable. Not sure how it snuck by me and build bots in the 7c99616e3fe7. Fixes: 7c99616e3fe7 ("drm: Remove drm_mode_config::fb_base") Reported-by: Stephen Rothwell Cc: Laurent Pinchart Cc: Thomas Zimmermann Cc: Christian König Cc: Ben Skeggs Cc: Karol Herbst Cc: Lyude Paul Reviewed-by: Lyude Paul Signed-off-by: Zack Rusin Signed-off-by: Lyude Paul Link: https://patchwork.freedesktop.org/patch/msgid/20221021010703.536318-1-zack@kde.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/nouveau/nouveau_display.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 928fdfa8e8e5..2e97186090c8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -659,7 +659,6 @@ int nouveau_display_create(struct drm_device *dev) { struct nouveau_drm *drm = nouveau_drm(dev); - struct nvkm_device *device = nvxx_device(&drm->client.device); struct nouveau_display *disp; int ret; -- cgit From 6e0fff462eccaeed9f499c3d5e661aed688ef4e4 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 24 Oct 2022 15:33:29 +0300 Subject: drm/i915/hdmi: do dual mode detect only if connected MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For normal connector detect, there's really no point in trying dual mode detect if the connector is disconnected. We can simplify the detect sequence by skipping it. Since intel_hdmi_dp_dual_mode_detect() is only called when EDID is present, we can drop the has_edid parameter. The functional effect is speeding up disconnected connector detection ever so slightly, and, combined with firmware EDID, also stop logging about assuming dual mode adaptor. It's a bit subtle, but this will also skip dual mode detect if the connector is force connected and a) there's no EDID of any kind, normal or override/firmware or b) there's EDID but it does not indicate digital. These are corner cases no matter what, and arguably forcing should not be limited by dual mode detect. Cc: Ville Syrjälä Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/f8f2a4a147e1c87ba93269a607f71fc29c4b59f6.1666614699.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_hdmi.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index 7816b2a33fee..0b4b894b66a9 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -2355,7 +2355,7 @@ intel_hdmi_unset_edid(struct drm_connector *connector) } static void -intel_hdmi_dp_dual_mode_detect(struct drm_connector *connector, bool has_edid) +intel_hdmi_dp_dual_mode_detect(struct drm_connector *connector) { struct drm_i915_private *dev_priv = to_i915(connector->dev); struct intel_hdmi *hdmi = intel_attached_hdmi(to_intel_connector(connector)); @@ -2371,16 +2371,13 @@ intel_hdmi_dp_dual_mode_detect(struct drm_connector *connector, bool has_edid) * CONFIG1 pin, but no such luck on our hardware. * * The only method left to us is to check the VBT to see - * if the port is a dual mode capable DP port. But let's - * only do that when we sucesfully read the EDID, to avoid - * confusing log messages about DP dual mode adaptors when - * there's nothing connected to the port. + * if the port is a dual mode capable DP port. */ if (type == DRM_DP_DUAL_MODE_UNKNOWN) { /* An overridden EDID imply that we want this port for testing. * Make sure not to set limits for that port. */ - if (has_edid && !connector->override_edid && + if (!connector->override_edid && intel_bios_is_port_dp_dual_mode(dev_priv, port)) { drm_dbg_kms(&dev_priv->drm, "Assuming DP dual mode adaptor presence based on VBT\n"); @@ -2435,18 +2432,18 @@ intel_hdmi_set_edid(struct drm_connector *connector) intel_gmbus_force_bit(i2c, false); } - intel_hdmi_dp_dual_mode_detect(connector, edid != NULL); - - intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS, wakeref); - to_intel_connector(connector)->detect_edid = edid; if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) { intel_hdmi->has_audio = drm_detect_monitor_audio(edid); intel_hdmi->has_hdmi_sink = drm_detect_hdmi_monitor(edid); + intel_hdmi_dp_dual_mode_detect(connector); + connected = true; } + intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS, wakeref); + cec_notifier_set_phys_addr_from_edid(intel_hdmi->cec_notifier, edid); return connected; -- cgit From 0281af2ade1fda50409afc62ebe9dd71194c6ed8 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 24 Oct 2022 15:33:30 +0300 Subject: drm/i915/hdmi: stop using connector->override_edid MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The connector->override_edid flag is strictly for EDID override debugfs management, and drivers have no business using it. The check for override_edid was added in commit 301906290553 ("drm/i915: Ignore TMDS clock limit for DP++ when EDID override is set") to facilitate mode list cross-checking against modes in override EDID when the connector in question isn't even connected. The dual mode detect fallback would do VBT based limiting in this case. Instead of override EDID, check for connector forcing in the fallback. v2: Simply use !connector->force (Ville) Cc: Ville Syrjälä Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/c8b45867cf37134ab40be23e22825ca45adc6041.1666614699.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_hdmi.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index 0b4b894b66a9..18451f5d2548 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -2374,10 +2374,7 @@ intel_hdmi_dp_dual_mode_detect(struct drm_connector *connector) * if the port is a dual mode capable DP port. */ if (type == DRM_DP_DUAL_MODE_UNKNOWN) { - /* An overridden EDID imply that we want this port for testing. - * Make sure not to set limits for that port. - */ - if (!connector->override_edid && + if (!connector->force && intel_bios_is_port_dp_dual_mode(dev_priv, port)) { drm_dbg_kms(&dev_priv->drm, "Assuming DP dual mode adaptor presence based on VBT\n"); -- cgit From 2db98059ff67e205be8a820f4e99c15f765e3c5a Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 24 Oct 2022 15:33:31 +0300 Subject: drm/amd/display: stop using connector->override_edid MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The connector->override_edid flag is strictly for EDID override debugfs management, and drivers have no business using it. Cc: Alex Deucher Cc: Christian König Cc: Xinhui Pan Cc: amd-gfx@lists.freedesktop.org Signed-off-by: Jani Nikula Reviewed-by: Harry Wentland Acked-by: Alex Deucher Link: https://patchwork.freedesktop.org/patch/msgid/c901869ff8a4e3aebc4abec99c7dd7b4c224f6e6.1666614699.git.jani.nikula@intel.com --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 0db2a88cd4d7..3c072754738d 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -6108,7 +6108,6 @@ static void create_eml_sink(struct amdgpu_dm_connector *aconnector) aconnector->base.name); aconnector->base.force = DRM_FORCE_OFF; - aconnector->base.override_edid = false; return; } @@ -6143,8 +6142,6 @@ static void handle_edid_mgmt(struct amdgpu_dm_connector *aconnector) link->verified_link_cap.link_rate = LINK_RATE_HIGH2; } - - aconnector->base.override_edid = true; create_eml_sink(aconnector); } -- cgit From 2c9332de05612a766dfd956f79430c02702cad0c Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 24 Oct 2022 15:33:32 +0300 Subject: drm/edid: debug log EDID override set/reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's useful debugging information to know if and when an override EDID was set or reset. Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/ae352f542b4d69398c0965e33fb2e6e34156cbfb.1666614699.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 47465b9765f1..a863cffa2dc5 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -2194,6 +2194,9 @@ int drm_edid_override_set(struct drm_connector *connector, const void *edid, connector->override_edid = false; + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] EDID override set\n", + connector->base.id, connector->name); + ret = drm_connector_update_edid_property(connector, edid); if (!ret) connector->override_edid = true; @@ -2206,6 +2209,9 @@ int drm_edid_override_reset(struct drm_connector *connector) { connector->override_edid = false; + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] EDID override reset\n", + connector->base.id, connector->name); + return drm_connector_update_edid_property(connector, NULL); } -- cgit From 91ec9ab4a6e3fff7b33f145c6b08f1e3c27d1c46 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 24 Oct 2022 15:33:33 +0300 Subject: drm/edid: abstract debugfs override EDID show better MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a function to dump the override EDID in debugfs. This hides the override EDID management better in drm_edid.c. Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/74defa7b595f51e6c1f2eacd9c799d567d29f053.1666614699.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_crtc_internal.h | 4 +++- drivers/gpu/drm/drm_debugfs.c | 8 +------- drivers/gpu/drm/drm_edid.c | 11 +++++++++++ 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index 56041b604881..fb8a68d90940 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -56,9 +56,10 @@ struct drm_plane; struct drm_plane_state; struct drm_property; struct edid; +struct fwnode_handle; struct kref; +struct seq_file; struct work_struct; -struct fwnode_handle; /* drm_crtc.c */ int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, @@ -286,5 +287,6 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, /* drm_edid.c */ void drm_mode_fixup_1366x768(struct drm_display_mode *mode); +int drm_edid_override_show(struct drm_connector *connector, struct seq_file *m); int drm_edid_override_set(struct drm_connector *connector, const void *edid, size_t size); int drm_edid_override_reset(struct drm_connector *connector); diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index 01ee3febb813..ee445f4605ba 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -328,13 +328,7 @@ static ssize_t connector_write(struct file *file, const char __user *ubuf, static int edid_show(struct seq_file *m, void *data) { - struct drm_connector *connector = m->private; - struct drm_property_blob *edid = connector->edid_blob_ptr; - - if (connector->override_edid && edid) - seq_write(m, edid->data, edid->length); - - return 0; + return drm_edid_override_show(m->private, m); } static int edid_open(struct inode *inode, struct file *file) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index a863cffa2dc5..1ada36e0d826 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -2183,6 +2183,17 @@ static struct edid *drm_get_override_edid(struct drm_connector *connector, return IS_ERR(override) ? NULL : override; } +/* For debugfs edid_override implementation */ +int drm_edid_override_show(struct drm_connector *connector, struct seq_file *m) +{ + struct drm_property_blob *edid = connector->edid_blob_ptr; + + if (connector->override_edid && edid) + seq_write(m, edid->data, edid->length); + + return 0; +} + /* For debugfs edid_override implementation */ int drm_edid_override_set(struct drm_connector *connector, const void *edid, size_t size) -- cgit From 019b93874834e7810499b65f4bfc990d16363581 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 24 Oct 2022 15:33:34 +0300 Subject: drm/edid: rename drm_add_override_edid_modes() to drm_edid_override_connector_update() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow the naming of both EDID override functions as well as drm_edid_connector_update(). This also matches better what the function does; a combination of EDID property update and add modes. Indeed it should later be converted to call drm_edid_connector_update(). Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/ba12957e0488654e8db010a3ff1534079caec972.1666614699.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 6 +++--- drivers/gpu/drm/drm_probe_helper.c | 2 +- include/drm/drm_edid.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 1ada36e0d826..8baa46dc2537 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -2227,7 +2227,7 @@ int drm_edid_override_reset(struct drm_connector *connector) } /** - * drm_add_override_edid_modes - add modes from override/firmware EDID + * drm_edid_override_connector_update - add modes from override/firmware EDID * @connector: connector we're probing * * Add modes from the override/firmware EDID, if available. Only to be used from @@ -2237,7 +2237,7 @@ int drm_edid_override_reset(struct drm_connector *connector) * * Return: The number of modes added or 0 if we couldn't find any. */ -int drm_add_override_edid_modes(struct drm_connector *connector) +int drm_edid_override_connector_update(struct drm_connector *connector) { struct edid *override; int num_modes = 0; @@ -2254,7 +2254,7 @@ int drm_add_override_edid_modes(struct drm_connector *connector) return num_modes; } -EXPORT_SYMBOL(drm_add_override_edid_modes); +EXPORT_SYMBOL(drm_edid_override_connector_update); typedef int read_block_fn(void *context, u8 *buf, unsigned int block, size_t len); diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 69b0b2b9cc1c..2fc21df709bc 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -367,7 +367,7 @@ static int drm_helper_probe_get_modes(struct drm_connector *connector) * override/firmware EDID. */ if (count == 0 && connector->status == connector_status_connected) - count = drm_add_override_edid_modes(connector); + count = drm_edid_override_connector_update(connector); return count; } diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 429735b91f63..05380681a4fb 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -577,7 +577,7 @@ struct edid *drm_get_edid_switcheroo(struct drm_connector *connector, struct i2c_adapter *adapter); struct edid *drm_edid_duplicate(const struct edid *edid); int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid); -int drm_add_override_edid_modes(struct drm_connector *connector); +int drm_edid_override_connector_update(struct drm_connector *connector); u8 drm_match_cea_mode(const struct drm_display_mode *to_match); bool drm_detect_hdmi_monitor(const struct edid *edid); -- cgit From b16c9e6c7d91c91e97a30f69b408388726e0376d Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 24 Oct 2022 15:33:35 +0300 Subject: drm/edid: split drm_edid block count helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split the drm_edid block count helper to a base version that reports the block count indicated by EDID contents, and another on top that limits the block count based on size allocated for the EDID. Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/a7d63878c7fb3dd6f3b987f5257897113797b94f.1666614699.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 8baa46dc2537..616c1cdc7507 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1613,7 +1613,8 @@ static const void *edid_extension_block_data(const struct edid *edid, int index) return edid_block_data(edid, index + 1); } -static int drm_edid_block_count(const struct drm_edid *drm_edid) +/* EDID block count indicated in EDID, may exceed allocated size */ +static int __drm_edid_block_count(const struct drm_edid *drm_edid) { int num_blocks; @@ -1633,12 +1634,18 @@ static int drm_edid_block_count(const struct drm_edid *drm_edid) num_blocks = eeodb; } - /* Limit by allocated size */ - num_blocks = min(num_blocks, (int)drm_edid->size / EDID_LENGTH); - return num_blocks; } +/* EDID block count, limited by allocated size */ +static int drm_edid_block_count(const struct drm_edid *drm_edid) +{ + /* Limit by allocated size */ + return min(__drm_edid_block_count(drm_edid), + (int)drm_edid->size / EDID_LENGTH); +} + +/* EDID extension block count, limited by allocated size */ static int drm_edid_extension_block_count(const struct drm_edid *drm_edid) { return drm_edid_block_count(drm_edid) - 1; -- cgit From 6c9b3db70aad556152cba7291e93ae9e4bb1a6b0 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 24 Oct 2022 15:33:36 +0300 Subject: drm/edid: add function for checking drm_edid validity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We've lacked a function for immutable validity check on drm_edid. Add one. Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/f96188f64e9f7f3deff348d08296609353b12316.1666614699.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 30 ++++++++++++++++++++++++++++++ include/drm/drm_edid.h | 1 + 2 files changed, 31 insertions(+) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 616c1cdc7507..c3cf942186b7 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -2040,6 +2040,36 @@ bool drm_edid_is_valid(struct edid *edid) } EXPORT_SYMBOL(drm_edid_is_valid); +/** + * drm_edid_valid - sanity check EDID data + * @drm_edid: EDID data + * + * Sanity check an EDID. Cross check block count against allocated size and + * checksum the blocks. + * + * Return: True if the EDID data is valid, false otherwise. + */ +bool drm_edid_valid(const struct drm_edid *drm_edid) +{ + int i; + + if (!drm_edid) + return false; + + if (edid_size_by_blocks(__drm_edid_block_count(drm_edid)) != drm_edid->size) + return false; + + for (i = 0; i < drm_edid_block_count(drm_edid); i++) { + const void *block = drm_edid_block_data(drm_edid, i); + + if (!edid_block_valid(block, i == 0)) + return false; + } + + return true; +} +EXPORT_SYMBOL(drm_edid_valid); + static struct edid *edid_filter_invalid_blocks(struct edid *edid, size_t *alloc_size) { diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 05380681a4fb..a2e25e7e6ee5 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -606,6 +606,7 @@ drm_display_mode_from_cea_vic(struct drm_device *dev, const struct drm_edid *drm_edid_alloc(const void *edid, size_t size); const struct drm_edid *drm_edid_dup(const struct drm_edid *drm_edid); void drm_edid_free(const struct drm_edid *drm_edid); +bool drm_edid_valid(const struct drm_edid *drm_edid); const struct edid *drm_edid_raw(const struct drm_edid *drm_edid); const struct drm_edid *drm_edid_read(struct drm_connector *connector); const struct drm_edid *drm_edid_read_ddc(struct drm_connector *connector, -- cgit From 90b575f52c6ab35979968e2e4d9cbd9f1eb3901c Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 24 Oct 2022 15:33:37 +0300 Subject: drm/edid: detach debugfs EDID override from EDID property update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Having the EDID override debugfs directly update the EDID property is problematic. The update is partial only. The driver has no way of knowing it's been updated. Mode list is not updated. It's an inconsistent state. Detach debugfs EDID override from the property update completely. Only set and reset a separate override EDID copy from debugfs, and have it take effect only at detect (via EDID read). The copy is at connector->edid_override, protected by connector->edid_override_mutex. This also brings override EDID closer to firmware EDID in behaviour. Add validation of the override EDID which we completely lacked. Note that IGT already forces a detect whenever tests update the override EDID. v2: Add locking (Ville) Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/4c875f8e06c4499f498fcf876e1233cbb155ec8a.1666614699.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_connector.c | 1 + drivers/gpu/drm/drm_edid.c | 73 ++++++++++++++++++++--------------------- include/drm/drm_connector.h | 16 ++++++--- 3 files changed, 49 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index 90dad87e9ad0..223ff2666c3c 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -274,6 +274,7 @@ static int __drm_connector_init(struct drm_device *dev, INIT_LIST_HEAD(&connector->probed_modes); INIT_LIST_HEAD(&connector->modes); mutex_init(&connector->mutex); + mutex_init(&connector->edid_override_mutex); connector->edid_blob_ptr = NULL; connector->epoch_counter = 0; connector->tile_blob_ptr = NULL; diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index c3cf942186b7..b8d07e4d6215 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -2207,8 +2207,12 @@ static struct edid *drm_get_override_edid(struct drm_connector *connector, { struct edid *override = NULL; - if (connector->override_edid) - override = drm_edid_duplicate(connector->edid_blob_ptr->data); + mutex_lock(&connector->edid_override_mutex); + + if (connector->edid_override) + override = drm_edid_duplicate(connector->edid_override->edid); + + mutex_unlock(&connector->edid_override_mutex); if (!override) override = drm_load_edid_firmware(connector); @@ -2223,10 +2227,15 @@ static struct edid *drm_get_override_edid(struct drm_connector *connector, /* For debugfs edid_override implementation */ int drm_edid_override_show(struct drm_connector *connector, struct seq_file *m) { - struct drm_property_blob *edid = connector->edid_blob_ptr; + const struct drm_edid *drm_edid; - if (connector->override_edid && edid) - seq_write(m, edid->data, edid->length); + mutex_lock(&connector->edid_override_mutex); + + drm_edid = connector->edid_override; + if (drm_edid) + seq_write(m, drm_edid->edid, drm_edid->size); + + mutex_unlock(&connector->edid_override_mutex); return 0; } @@ -2235,32 +2244,43 @@ int drm_edid_override_show(struct drm_connector *connector, struct seq_file *m) int drm_edid_override_set(struct drm_connector *connector, const void *edid, size_t size) { - int ret; + const struct drm_edid *drm_edid; - if (size < EDID_LENGTH || edid_size(edid) > size) + drm_edid = drm_edid_alloc(edid, size); + if (!drm_edid_valid(drm_edid)) { + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] EDID override invalid\n", + connector->base.id, connector->name); + drm_edid_free(drm_edid); return -EINVAL; - - connector->override_edid = false; + } drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] EDID override set\n", connector->base.id, connector->name); - ret = drm_connector_update_edid_property(connector, edid); - if (!ret) - connector->override_edid = true; + mutex_lock(&connector->edid_override_mutex); - return ret; + drm_edid_free(connector->edid_override); + connector->edid_override = drm_edid; + + mutex_unlock(&connector->edid_override_mutex); + + return 0; } /* For debugfs edid_override implementation */ int drm_edid_override_reset(struct drm_connector *connector) { - connector->override_edid = false; - drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] EDID override reset\n", connector->base.id, connector->name); - return drm_connector_update_edid_property(connector, NULL); + mutex_lock(&connector->edid_override_mutex); + + drm_edid_free(connector->edid_override); + connector->edid_override = NULL; + + mutex_unlock(&connector->edid_override_mutex); + + return 0; } /** @@ -6634,23 +6654,6 @@ int drm_edid_connector_update(struct drm_connector *connector, { int count; - /* - * FIXME: Reconcile the differences in override_edid handling between - * this and drm_connector_update_edid_property(). - * - * If override_edid is set, and the EDID passed in here originates from - * drm_edid_read() and friends, it will be the override EDID, and there - * are no issues. drm_connector_update_edid_property() ignoring requests - * to set the EDID dates back to a time when override EDID was not - * handled at the low level EDID read. - * - * The only way the EDID passed in here can be different from the - * override EDID is when a driver passes in an EDID that does *not* - * originate from drm_edid_read() and friends, or passes in a stale - * cached version. This, in turn, is a question of when an override EDID - * set via debugfs should take effect. - */ - count = _drm_edid_connector_update(connector, drm_edid); _drm_update_tile_info(connector, drm_edid); @@ -6665,10 +6668,6 @@ EXPORT_SYMBOL(drm_edid_connector_update); static int _drm_connector_update_edid_property(struct drm_connector *connector, const struct drm_edid *drm_edid) { - /* ignore requests to set edid when overridden */ - if (connector->override_edid) - return 0; - /* * Set the display info, using edid if available, otherwise resetting * the values to defaults. This duplicates the work done in diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index b1b2df48d42c..e641a4725f99 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -1550,12 +1550,20 @@ struct drm_connector { struct drm_cmdline_mode cmdline_mode; /** @force: a DRM_FORCE_ state for forced mode sets */ enum drm_connector_force force; + + /** + * @edid_override: Override EDID set via debugfs. + * + * Do not modify or access outside of the drm_edid_override_* family of + * functions. + */ + const struct drm_edid *edid_override; + /** - * @override_edid: has the EDID been overwritten through debugfs for - * testing? Do not modify outside of drm_edid_override_set() and - * drm_edid_override_reset(). + * @edid_override_mutex: Protect access to edid_override. */ - bool override_edid; + struct mutex edid_override_mutex; + /** @epoch_counter: used to detect any other changes in connector, besides status */ u64 epoch_counter; -- cgit From 8319d26a292ed1f76b793da5e9b48d4820c7a5e6 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 24 Oct 2022 15:33:38 +0300 Subject: drm/edid/firmware: drop redundant connector_name variable/parameter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stop passing around something that's readily available in connector->name. Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/befa53a33f2ea83094027a0e88d155779ad096e1.1666614699.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid_load.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/drm_edid_load.c b/drivers/gpu/drm/drm_edid_load.c index 37d8ba3ddb46..13cdbfb991eb 100644 --- a/drivers/gpu/drm/drm_edid_load.c +++ b/drivers/gpu/drm/drm_edid_load.c @@ -167,8 +167,7 @@ static int edid_size(const u8 *edid, int data_size) return (edid[0x7e] + 1) * EDID_LENGTH; } -static void *edid_load(struct drm_connector *connector, const char *name, - const char *connector_name) +static void *edid_load(struct drm_connector *connector, const char *name) { const struct firmware *fw = NULL; const u8 *fwdata; @@ -185,10 +184,10 @@ static void *edid_load(struct drm_connector *connector, const char *name, struct platform_device *pdev; int err; - pdev = platform_device_register_simple(connector_name, -1, NULL, 0); + pdev = platform_device_register_simple(connector->name, -1, NULL, 0); if (IS_ERR(pdev)) { DRM_ERROR("Failed to register EDID firmware platform device " - "for connector \"%s\"\n", connector_name); + "for connector \"%s\"\n", connector->name); return ERR_CAST(pdev); } @@ -244,7 +243,7 @@ static void *edid_load(struct drm_connector *connector, const char *name, edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions; DRM_INFO("Found %d valid extensions instead of %d in EDID data " "\"%s\" for connector \"%s\"\n", valid_extensions, - edid[0x7e], name, connector_name); + edid[0x7e], name, connector->name); edid[0x7e] = valid_extensions; new_edid = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH, @@ -256,7 +255,7 @@ static void *edid_load(struct drm_connector *connector, const char *name, DRM_INFO("Got %s EDID base block and %d extension%s from " "\"%s\" for connector \"%s\"\n", (builtin >= 0) ? "built-in" : "external", valid_extensions, valid_extensions == 1 ? "" : "s", - name, connector_name); + name, connector->name); out: release_firmware(fw); @@ -265,7 +264,6 @@ out: struct edid *drm_load_edid_firmware(struct drm_connector *connector) { - const char *connector_name = connector->name; char *edidname, *last, *colon, *fwstr, *edidstr, *fallback = NULL; struct edid *edid; @@ -288,7 +286,7 @@ struct edid *drm_load_edid_firmware(struct drm_connector *connector) while ((edidname = strsep(&edidstr, ","))) { colon = strchr(edidname, ':'); if (colon != NULL) { - if (strncmp(connector_name, edidname, colon - edidname)) + if (strncmp(connector->name, edidname, colon - edidname)) continue; edidname = colon + 1; break; @@ -310,7 +308,7 @@ struct edid *drm_load_edid_firmware(struct drm_connector *connector) if (*last == '\n') *last = '\0'; - edid = edid_load(connector, edidname, connector_name); + edid = edid_load(connector, edidname); kfree(fwstr); return edid; -- cgit From a05992d5ea779da174246186d88bfeaf2d2754f2 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 24 Oct 2022 15:33:39 +0300 Subject: drm/edid/firmware: rename drm_load_edid_firmware() to drm_edid_load_firmware() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow the usual naming convention by file name. Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/d6714ae737d789764bd2bdb6e7c9a5f56c99eef3.1666614699.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 10 +++++----- drivers/gpu/drm/drm_edid_load.c | 2 +- include/drm/drm_edid.h | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index b8d07e4d6215..5e5e1463e45f 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -2215,7 +2215,7 @@ static struct edid *drm_get_override_edid(struct drm_connector *connector, mutex_unlock(&connector->edid_override_mutex); if (!override) - override = drm_load_edid_firmware(connector); + override = drm_edid_load_firmware(connector); /* FIXME: Get alloc size from deeper down the stack */ if (!IS_ERR_OR_NULL(override) && alloc_size) @@ -2462,7 +2462,7 @@ fail: * adapter and use drm_get_edid() instead of abusing this function. * * The EDID may be overridden using debugfs override_edid or firmware EDID - * (drm_load_edid_firmware() and drm.edid_firmware parameter), in this priority + * (drm_edid_load_firmware() and drm.edid_firmware parameter), in this priority * order. Having either of them bypasses actual EDID reads. * * Return: Pointer to valid EDID or NULL if we couldn't find any. @@ -2640,7 +2640,7 @@ EXPORT_SYMBOL(drm_get_edid); * this function. * * The EDID may be overridden using debugfs override_edid or firmware EDID - * (drm_load_edid_firmware() and drm.edid_firmware parameter), in this priority + * (drm_edid_load_firmware() and drm.edid_firmware parameter), in this priority * order. Having either of them bypasses actual EDID reads. * * The returned pointer must be freed using drm_edid_free(). @@ -2678,7 +2678,7 @@ EXPORT_SYMBOL(drm_edid_read_custom); * Read EDID using the given I2C adapter. * * The EDID may be overridden using debugfs override_edid or firmware EDID - * (drm_load_edid_firmware() and drm.edid_firmware parameter), in this priority + * (drm_edid_load_firmware() and drm.edid_firmware parameter), in this priority * order. Having either of them bypasses actual EDID reads. * * Prefer initializing connector->ddc with drm_connector_init_with_ddc() and @@ -2714,7 +2714,7 @@ EXPORT_SYMBOL(drm_edid_read_ddc); * Read EDID using the connector's I2C adapter. * * The EDID may be overridden using debugfs override_edid or firmware EDID - * (drm_load_edid_firmware() and drm.edid_firmware parameter), in this priority + * (drm_edid_load_firmware() and drm.edid_firmware parameter), in this priority * order. Having either of them bypasses actual EDID reads. * * The returned pointer must be freed using drm_edid_free(). diff --git a/drivers/gpu/drm/drm_edid_load.c b/drivers/gpu/drm/drm_edid_load.c index 13cdbfb991eb..bc6b96abd1b3 100644 --- a/drivers/gpu/drm/drm_edid_load.c +++ b/drivers/gpu/drm/drm_edid_load.c @@ -262,7 +262,7 @@ out: return edid; } -struct edid *drm_load_edid_firmware(struct drm_connector *connector) +struct edid *drm_edid_load_firmware(struct drm_connector *connector) { char *edidname, *last, *colon, *fwstr, *edidstr, *fallback = NULL; struct edid *edid; diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index a2e25e7e6ee5..dc7467d25cd8 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -388,12 +388,12 @@ int drm_av_sync_delay(struct drm_connector *connector, const struct drm_display_mode *mode); #ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE -struct edid *drm_load_edid_firmware(struct drm_connector *connector); +struct edid *drm_edid_load_firmware(struct drm_connector *connector); int __drm_set_edid_firmware_path(const char *path); int __drm_get_edid_firmware_path(char *buf, size_t bufsize); #else static inline struct edid * -drm_load_edid_firmware(struct drm_connector *connector) +drm_edid_load_firmware(struct drm_connector *connector) { return ERR_PTR(-ENOENT); } -- cgit From 794aca0ec214bb23ff4fcb28c053ac6fdfa3ce07 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 24 Oct 2022 15:33:40 +0300 Subject: drm/edid: use struct drm_edid for override/firmware EDID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's a lot going on here, but the main thing is switching the firmware EDID loader to use struct drm_edid. Unfortunately, it's difficult to reasonably split to smaller pieces. Convert the EDID loader to struct drm_edid. There's a functional change in validation; it no longer tries to fix errors or filter invalid blocks. It's stricter in this sense. Hopefully this will not be an issue. As a by-product, this change also allows HF-EEODB extended EDIDs to be passed via override/firmware EDID. Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/e64267c28eca483e83c802bc06ddd149bdcdfc66.1666614699.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 32 ++++++++------- drivers/gpu/drm/drm_edid_load.c | 86 ++++++++--------------------------------- include/drm/drm_edid.h | 4 +- 3 files changed, 36 insertions(+), 86 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 5e5e1463e45f..9078d1fb6d00 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -2202,25 +2202,20 @@ static void connector_bad_edid(struct drm_connector *connector, } /* Get override or firmware EDID */ -static struct edid *drm_get_override_edid(struct drm_connector *connector, - size_t *alloc_size) +static const struct drm_edid *drm_edid_override_get(struct drm_connector *connector) { - struct edid *override = NULL; + const struct drm_edid *override = NULL; mutex_lock(&connector->edid_override_mutex); if (connector->edid_override) - override = drm_edid_duplicate(connector->edid_override->edid); + override = drm_edid_dup(connector->edid_override); mutex_unlock(&connector->edid_override_mutex); if (!override) override = drm_edid_load_firmware(connector); - /* FIXME: Get alloc size from deeper down the stack */ - if (!IS_ERR_OR_NULL(override) && alloc_size) - *alloc_size = edid_size(override); - return IS_ERR(override) ? NULL : override; } @@ -2296,14 +2291,14 @@ int drm_edid_override_reset(struct drm_connector *connector) */ int drm_edid_override_connector_update(struct drm_connector *connector) { - struct edid *override; + const struct drm_edid *override; int num_modes = 0; - override = drm_get_override_edid(connector, NULL); + override = drm_edid_override_get(connector); if (override) { - drm_connector_update_edid_property(connector, override); - num_modes = drm_add_edid_modes(connector, override); - kfree(override); + num_modes = drm_edid_connector_update(connector, override); + + drm_edid_free(override); DRM_DEBUG_KMS("[CONNECTOR:%d:%s] adding %d modes via fallback override/firmware EDID\n", connector->base.id, connector->name, num_modes); @@ -2354,12 +2349,19 @@ static struct edid *_drm_do_get_edid(struct drm_connector *connector, { enum edid_block_status status; int i, num_blocks, invalid_blocks = 0; + const struct drm_edid *override; struct edid *edid, *new; size_t alloc_size = EDID_LENGTH; - edid = drm_get_override_edid(connector, &alloc_size); - if (edid) + override = drm_edid_override_get(connector); + if (override) { + alloc_size = override->size; + edid = kmemdup(override->edid, alloc_size, GFP_KERNEL); + drm_edid_free(override); + if (!edid) + return NULL; goto ok; + } edid = kmalloc(alloc_size, GFP_KERNEL); if (!edid) diff --git a/drivers/gpu/drm/drm_edid_load.c b/drivers/gpu/drm/drm_edid_load.c index bc6b96abd1b3..248f0685c33e 100644 --- a/drivers/gpu/drm/drm_edid_load.c +++ b/drivers/gpu/drm/drm_edid_load.c @@ -159,22 +159,12 @@ static const u8 generic_edid[GENERIC_EDIDS][128] = { }, }; -static int edid_size(const u8 *edid, int data_size) -{ - if (data_size < EDID_LENGTH) - return 0; - - return (edid[0x7e] + 1) * EDID_LENGTH; -} - -static void *edid_load(struct drm_connector *connector, const char *name) +static const struct drm_edid *edid_load(struct drm_connector *connector, const char *name) { const struct firmware *fw = NULL; const u8 *fwdata; - u8 *edid; + const struct drm_edid *drm_edid; int fwsize, builtin; - int i, valid_extensions = 0; - bool print_bad_edid = !connector->bad_edid_counter || drm_debug_enabled(DRM_UT_KMS); builtin = match_string(generic_edid_name, GENERIC_EDIDS, name); if (builtin >= 0) { @@ -203,69 +193,26 @@ static void *edid_load(struct drm_connector *connector, const char *name) fwsize = fw->size; } - if (edid_size(fwdata, fwsize) != fwsize) { - DRM_ERROR("Size of EDID firmware \"%s\" is invalid " - "(expected %d, got %d\n", name, - edid_size(fwdata, fwsize), (int)fwsize); - edid = ERR_PTR(-EINVAL); - goto out; - } - - edid = kmemdup(fwdata, fwsize, GFP_KERNEL); - if (edid == NULL) { - edid = ERR_PTR(-ENOMEM); - goto out; - } - - if (!drm_edid_block_valid(edid, 0, print_bad_edid, - &connector->edid_corrupt)) { - connector->bad_edid_counter++; - DRM_ERROR("Base block of EDID firmware \"%s\" is invalid ", - name); - kfree(edid); - edid = ERR_PTR(-EINVAL); - goto out; - } - - for (i = 1; i <= edid[0x7e]; i++) { - if (i != valid_extensions + 1) - memcpy(edid + (valid_extensions + 1) * EDID_LENGTH, - edid + i * EDID_LENGTH, EDID_LENGTH); - if (drm_edid_block_valid(edid + i * EDID_LENGTH, i, - print_bad_edid, - NULL)) - valid_extensions++; - } - - if (valid_extensions != edid[0x7e]) { - u8 *new_edid; + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] Loaded %s firmware EDID \"%s\"\n", + connector->base.id, connector->name, + builtin >= 0 ? "built-in" : "external", name); - edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions; - DRM_INFO("Found %d valid extensions instead of %d in EDID data " - "\"%s\" for connector \"%s\"\n", valid_extensions, - edid[0x7e], name, connector->name); - edid[0x7e] = valid_extensions; - - new_edid = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH, - GFP_KERNEL); - if (new_edid) - edid = new_edid; + drm_edid = drm_edid_alloc(fwdata, fwsize); + if (!drm_edid_valid(drm_edid)) { + drm_err(connector->dev, "Invalid firmware EDID \"%s\"\n", name); + drm_edid_free(drm_edid); + drm_edid = ERR_PTR(-EINVAL); } - DRM_INFO("Got %s EDID base block and %d extension%s from " - "\"%s\" for connector \"%s\"\n", (builtin >= 0) ? "built-in" : - "external", valid_extensions, valid_extensions == 1 ? "" : "s", - name, connector->name); - -out: release_firmware(fw); - return edid; + + return drm_edid; } -struct edid *drm_edid_load_firmware(struct drm_connector *connector) +const struct drm_edid *drm_edid_load_firmware(struct drm_connector *connector) { char *edidname, *last, *colon, *fwstr, *edidstr, *fallback = NULL; - struct edid *edid; + const struct drm_edid *drm_edid; if (edid_firmware[0] == '\0') return ERR_PTR(-ENOENT); @@ -308,8 +255,9 @@ struct edid *drm_edid_load_firmware(struct drm_connector *connector) if (*last == '\n') *last = '\0'; - edid = edid_load(connector, edidname); + drm_edid = edid_load(connector, edidname); + kfree(fwstr); - return edid; + return drm_edid; } diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index dc7467d25cd8..8138613f4e4e 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -388,11 +388,11 @@ int drm_av_sync_delay(struct drm_connector *connector, const struct drm_display_mode *mode); #ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE -struct edid *drm_edid_load_firmware(struct drm_connector *connector); +const struct drm_edid *drm_edid_load_firmware(struct drm_connector *connector); int __drm_set_edid_firmware_path(const char *path); int __drm_get_edid_firmware_path(char *buf, size_t bufsize); #else -static inline struct edid * +static inline const struct drm_edid * drm_edid_load_firmware(struct drm_connector *connector) { return ERR_PTR(-ENOENT); -- cgit From 5f2d0ed49036a0218685e7d9d03539bdbdc66f78 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 24 Oct 2022 15:33:41 +0300 Subject: drm/edid: move edid load declarations to internal header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The EDID loader is internal to drm, not for drivers. Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/d58a59fede286caa8766e0813f4be492a7200287.1666614699.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_crtc_internal.h | 11 +++++++++++ drivers/gpu/drm/drm_edid_load.c | 5 +++-- include/drm/drm_edid.h | 7 ------- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index fb8a68d90940..501a10edd0e1 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -290,3 +290,14 @@ void drm_mode_fixup_1366x768(struct drm_display_mode *mode); int drm_edid_override_show(struct drm_connector *connector, struct seq_file *m); int drm_edid_override_set(struct drm_connector *connector, const void *edid, size_t size); int drm_edid_override_reset(struct drm_connector *connector); + +/* drm_edid_load.c */ +#ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE +const struct drm_edid *drm_edid_load_firmware(struct drm_connector *connector); +#else +static inline const struct drm_edid * +drm_edid_load_firmware(struct drm_connector *connector) +{ + return ERR_PTR(-ENOENT); +} +#endif diff --git a/drivers/gpu/drm/drm_edid_load.c b/drivers/gpu/drm/drm_edid_load.c index 248f0685c33e..882caaa6e663 100644 --- a/drivers/gpu/drm/drm_edid_load.c +++ b/drivers/gpu/drm/drm_edid_load.c @@ -11,12 +11,13 @@ #include #include -#include -#include +#include #include #include #include +#include "drm_crtc_internal.h" + static char edid_firmware[PATH_MAX]; module_param_string(edid_firmware, edid_firmware, sizeof(edid_firmware), 0644); MODULE_PARM_DESC(edid_firmware, "Do not probe monitor, use specified EDID blob " diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 8138613f4e4e..372963600f1d 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -388,15 +388,8 @@ int drm_av_sync_delay(struct drm_connector *connector, const struct drm_display_mode *mode); #ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE -const struct drm_edid *drm_edid_load_firmware(struct drm_connector *connector); int __drm_set_edid_firmware_path(const char *path); int __drm_get_edid_firmware_path(char *buf, size_t bufsize); -#else -static inline const struct drm_edid * -drm_edid_load_firmware(struct drm_connector *connector) -{ - return ERR_PTR(-ENOENT); -} #endif bool drm_edid_are_equal(const struct edid *edid1, const struct edid *edid2); -- cgit From 2ab6590cd96ff2d3005e9011577b08b0aed8388a Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 24 Oct 2022 15:33:42 +0300 Subject: drm/edid/firmware: convert to drm device specific logging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Conform to device specific logging. v2: Include [CONNECTOR:%d:%s] (Ville) Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/14f3a1e55729c9157aae93fc45320d05cc4cc7bc.1666614699.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid_load.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_edid_load.c b/drivers/gpu/drm/drm_edid_load.c index 882caaa6e663..ef4ab59d6935 100644 --- a/drivers/gpu/drm/drm_edid_load.c +++ b/drivers/gpu/drm/drm_edid_load.c @@ -177,16 +177,20 @@ static const struct drm_edid *edid_load(struct drm_connector *connector, const c pdev = platform_device_register_simple(connector->name, -1, NULL, 0); if (IS_ERR(pdev)) { - DRM_ERROR("Failed to register EDID firmware platform device " - "for connector \"%s\"\n", connector->name); + drm_err(connector->dev, + "[CONNECTOR:%d:%s] Failed to register EDID firmware platform device for connector \"%s\"\n", + connector->base.id, connector->name, + connector->name); return ERR_CAST(pdev); } err = request_firmware(&fw, name, &pdev->dev); platform_device_unregister(pdev); if (err) { - DRM_ERROR("Requesting EDID firmware \"%s\" failed (err=%d)\n", - name, err); + drm_err(connector->dev, + "[CONNECTOR:%d:%s] Requesting EDID firmware \"%s\" failed (err=%d)\n", + connector->base.id, connector->name, + name, err); return ERR_PTR(err); } -- cgit From 66d17ecde7cae2b0e526473217c4178a4059181e Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 24 Oct 2022 15:33:43 +0300 Subject: drm/edid: add [CONNECTOR:%d:%s] to debug logging Reference the connector using [CONNECTOR:%d:%s] in existing device based debug logging. Signed-off-by: Jani Nikula Reviewed-by: Simon Ser Link: https://patchwork.freedesktop.org/patch/msgid/5884410682bcbc032de4d3af8562c0b271edaa7f.1666614699.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 9078d1fb6d00..3be98ac2e711 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -2196,7 +2196,8 @@ static void connector_bad_edid(struct drm_connector *connector, if (connector->bad_edid_counter++ && !drm_debug_enabled(DRM_UT_KMS)) return; - drm_dbg_kms(connector->dev, "%s: EDID is invalid:\n", connector->name); + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] EDID is invalid:\n", + connector->base.id, connector->name); for (i = 0; i < num_blocks; i++) edid_block_dump(KERN_DEBUG, edid + i, i); } @@ -6031,7 +6032,8 @@ static void drm_parse_hdmi_forum_scds(struct drm_connector *connector, } drm_dbg_kms(connector->dev, - "HF-VSDB: max TMDS clock: %d KHz, HDMI 2.1 support: %s, DSC 1.2 support: %s\n", + "[CONNECTOR:%d:%s] HF-VSDB: max TMDS clock: %d KHz, HDMI 2.1 support: %s, DSC 1.2 support: %s\n", + connector->base.id, connector->name, max_tmds_clock, str_yes_no(max_frl_rate), str_yes_no(dsc_support)); } @@ -6131,8 +6133,9 @@ static void drm_parse_microsoft_vsdb(struct drm_connector *connector, if (version == 1 || version == 2 || (version == 3 && !desktop_usage)) info->non_desktop = true; - drm_dbg_kms(connector->dev, "HMD or specialized display VSDB version %u: 0x%02x\n", - version, db[5]); + drm_dbg_kms(connector->dev, + "[CONNECTOR:%d:%s] HMD or specialized display VSDB version %u: 0x%02x\n", + connector->base.id, connector->name, version, db[5]); } static void drm_parse_cea_ext(struct drm_connector *connector, @@ -6253,8 +6256,9 @@ static void drm_parse_vesa_mso_data(struct drm_connector *connector, struct drm_display_info *info = &connector->display_info; if (block->num_bytes < 3) { - drm_dbg_kms(connector->dev, "Unexpected vendor block size %u\n", - block->num_bytes); + drm_dbg_kms(connector->dev, + "[CONNECTOR:%d:%s] Unexpected vendor block size %u\n", + connector->base.id, connector->name, block->num_bytes); return; } @@ -6262,13 +6266,16 @@ static void drm_parse_vesa_mso_data(struct drm_connector *connector, return; if (sizeof(*vesa) != sizeof(*block) + block->num_bytes) { - drm_dbg_kms(connector->dev, "Unexpected VESA vendor block size\n"); + drm_dbg_kms(connector->dev, + "[CONNECTOR:%d:%s] Unexpected VESA vendor block size\n", + connector->base.id, connector->name); return; } switch (FIELD_GET(DISPLAYID_VESA_MSO_MODE, vesa->mso)) { default: - drm_dbg_kms(connector->dev, "Reserved MSO mode value\n"); + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] Reserved MSO mode value\n", + connector->base.id, connector->name); fallthrough; case 0: info->mso_stream_count = 0; @@ -6288,12 +6295,16 @@ static void drm_parse_vesa_mso_data(struct drm_connector *connector, info->mso_pixel_overlap = FIELD_GET(DISPLAYID_VESA_MSO_OVERLAP, vesa->mso); if (info->mso_pixel_overlap > 8) { - drm_dbg_kms(connector->dev, "Reserved MSO pixel overlap value %u\n", + drm_dbg_kms(connector->dev, + "[CONNECTOR:%d:%s] Reserved MSO pixel overlap value %u\n", + connector->base.id, connector->name, info->mso_pixel_overlap); info->mso_pixel_overlap = 8; } - drm_dbg_kms(connector->dev, "MSO stream count %u, pixel overlap %u\n", + drm_dbg_kms(connector->dev, + "[CONNECTOR:%d:%s] MSO stream count %u, pixel overlap %u\n", + connector->base.id, connector->name, info->mso_stream_count, info->mso_pixel_overlap); } @@ -6421,7 +6432,8 @@ static u32 update_display_info(struct drm_connector *connector, out: if (quirks & EDID_QUIRK_NON_DESKTOP) { - drm_dbg_kms(connector->dev, "Non-desktop display%s\n", + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] Non-desktop display%s\n", + connector->base.id, connector->name, info->non_desktop ? " (redundant quirk)" : ""); info->non_desktop = true; } @@ -6732,8 +6744,8 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid) struct drm_edid drm_edid; if (edid && !drm_edid_is_valid(edid)) { - drm_warn(connector->dev, "%s: EDID invalid.\n", - connector->name); + drm_warn(connector->dev, "[CONNECTOR:%d:%s] EDID invalid.\n", + connector->base.id, connector->name); edid = NULL; } -- cgit From e1e7bc481d49c3e3ada11029ce0d9b85a0a539d7 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 24 Oct 2022 15:33:44 +0300 Subject: drm/edid: convert to device specific logging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert to drm_kms_dbg/drm_err where possible, and reference the connector using [CONNECTOR:%d:%s]. Pass connectors around a bit more to enable this. Where this is not possible, unify the rest of the debugs to DRM_DEBUG_KMS. Rewrite tile debug logging to one line while at it. v2: - Use [CONNECTOR:%d:%s] throughout (Ville) - Tile debug logging revamp - Pass connector around a bit more Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/e48346bfe09a632d5a5faa55e3c161b196cf21e8.1666614699.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 137 +++++++++++++++++++++++++-------------------- 1 file changed, 77 insertions(+), 60 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 3be98ac2e711..b2d61c05f559 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1979,7 +1979,7 @@ bool drm_edid_block_valid(u8 *_block, int block_num, bool print_bad_edid, status = edid_block_check(block, is_base_block); if (status == EDID_BLOCK_HEADER_REPAIR) { - DRM_DEBUG("Fixing EDID header, your hardware may be failing\n"); + DRM_DEBUG_KMS("Fixing EDID header, your hardware may be failing\n"); edid_header_fix(block); /* Retry with fixed header, update status if that worked. */ @@ -2301,8 +2301,9 @@ int drm_edid_override_connector_update(struct drm_connector *connector) drm_edid_free(override); - DRM_DEBUG_KMS("[CONNECTOR:%d:%s] adding %d modes via fallback override/firmware EDID\n", - connector->base.id, connector->name, num_modes); + drm_dbg_kms(connector->dev, + "[CONNECTOR:%d:%s] adding %d modes via fallback override/firmware EDID\n", + connector->base.id, connector->name, num_modes); } return num_modes; @@ -3388,11 +3389,12 @@ drm_mode_do_interlace_quirk(struct drm_display_mode *mode, * timing block contains enough info for us to create and return a new struct * drm_display_mode. */ -static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, +static struct drm_display_mode *drm_mode_detailed(struct drm_connector *connector, const struct drm_edid *drm_edid, const struct detailed_timing *timing, u32 quirks) { + struct drm_device *dev = connector->dev; struct drm_display_mode *mode; const struct detailed_pixel_timing *pt = &timing->data.pixel_data; unsigned hactive = (pt->hactive_hblank_hi & 0xf0) << 4 | pt->hactive_lo; @@ -3409,17 +3411,19 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, return NULL; if (pt->misc & DRM_EDID_PT_STEREO) { - DRM_DEBUG_KMS("stereo mode not supported\n"); + drm_dbg_kms(dev, "[CONNECTOR:%d:%s] Stereo mode not supported\n", + connector->base.id, connector->name); return NULL; } if (!(pt->misc & DRM_EDID_PT_SEPARATE_SYNC)) { - DRM_DEBUG_KMS("composite sync not supported\n"); + drm_dbg_kms(dev, "[CONNECTOR:%d:%s] Composite sync not supported\n", + connector->base.id, connector->name); } /* it is incorrect if hsync/vsync width is zero */ if (!hsync_pulse_width || !vsync_pulse_width) { - DRM_DEBUG_KMS("Incorrect Detailed timing. " - "Wrong Hsync/Vsync pulse width\n"); + drm_dbg_kms(dev, "[CONNECTOR:%d:%s] Incorrect Detailed timing. Wrong Hsync/Vsync pulse width\n", + connector->base.id, connector->name); return NULL; } @@ -3976,7 +3980,8 @@ add_cvt_modes(struct drm_connector *connector, const struct drm_edid *drm_edid) return closure.modes; } -static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode); +static void fixup_detailed_cea_mode_clock(struct drm_connector *connector, + struct drm_display_mode *mode); static void do_detailed_mode(const struct detailed_timing *timing, void *c) @@ -3987,7 +3992,7 @@ do_detailed_mode(const struct detailed_timing *timing, void *c) if (!is_detailed_timing_descriptor(timing)) return; - newmode = drm_mode_detailed(closure->connector->dev, + newmode = drm_mode_detailed(closure->connector, closure->drm_edid, timing, closure->quirks); if (!newmode) @@ -4001,7 +4006,7 @@ do_detailed_mode(const struct detailed_timing *timing, void *c) * so fix up anything that looks like CEA/HDMI mode, but the clock * is just slightly off. */ - fixup_detailed_cea_mode_clock(newmode); + fixup_detailed_cea_mode_clock(closure->connector, newmode); drm_mode_probed_add(closure->connector, newmode); closure->modes++; @@ -4663,7 +4668,8 @@ static int add_hdmi_mode(struct drm_connector *connector, u8 vic) struct drm_display_mode *newmode; if (!drm_valid_hdmi_vic(vic)) { - DRM_ERROR("Unknown HDMI VIC: %d\n", vic); + drm_err(connector->dev, "[CONNECTOR:%d:%s] Unknown HDMI VIC: %d\n", + connector->base.id, connector->name, vic); return 0; } @@ -5270,7 +5276,8 @@ static int add_cea_modes(struct drm_connector *connector, return modes; } -static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode) +static void fixup_detailed_cea_mode_clock(struct drm_connector *connector, + struct drm_display_mode *mode) { const struct drm_display_mode *cea_mode; int clock1, clock2, clock; @@ -5308,8 +5315,10 @@ static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode) if (mode->clock == clock) return; - DRM_DEBUG("detailed mode matches %s VIC %d, adjusting clock %d -> %d\n", - type, vic, mode->clock, clock); + drm_dbg_kms(connector->dev, + "[CONNECTOR:%d:%s] detailed mode matches %s VIC %d, adjusting clock %d -> %d\n", + connector->base.id, connector->name, + type, vic, mode->clock, clock); mode->clock = clock; } @@ -5417,15 +5426,12 @@ drm_parse_hdmi_vsdb_audio(struct drm_connector *connector, const u8 *db) if (len >= 12) connector->audio_latency[1] = db[12]; - DRM_DEBUG_KMS("HDMI: latency present %d %d, " - "video latency %d %d, " - "audio latency %d %d\n", - connector->latency_present[0], - connector->latency_present[1], - connector->video_latency[0], - connector->video_latency[1], - connector->audio_latency[0], - connector->audio_latency[1]); + drm_dbg_kms(connector->dev, + "[CONNECTOR:%d:%s] HDMI: latency present %d %d, video latency %d %d, audio latency %d %d\n", + connector->base.id, connector->name, + connector->latency_present[0], connector->latency_present[1], + connector->video_latency[0], connector->video_latency[1], + connector->audio_latency[0], connector->audio_latency[1]); } static void @@ -5523,7 +5529,9 @@ static void drm_edid_to_eld(struct drm_connector *connector, return; mnl = get_monitor_name(drm_edid, &eld[DRM_ELD_MONITOR_NAME_STRING]); - DRM_DEBUG_KMS("ELD monitor %s\n", &eld[DRM_ELD_MONITOR_NAME_STRING]); + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] ELD monitor %s\n", + connector->base.id, connector->name, + &eld[DRM_ELD_MONITOR_NAME_STRING]); eld[DRM_ELD_CEA_EDID_VER_MNL] = info->cea_rev << DRM_ELD_CEA_EDID_VER_SHIFT; eld[DRM_ELD_CEA_EDID_VER_MNL] |= mnl; @@ -5577,8 +5585,9 @@ static void drm_edid_to_eld(struct drm_connector *connector, eld[DRM_ELD_BASELINE_ELD_LEN] = DIV_ROUND_UP(drm_eld_calc_baseline_block_size(eld), 4); - DRM_DEBUG_KMS("ELD size %d, SAD count %d\n", - drm_eld_size(eld), total_sad_count); + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] ELD size %d, SAD count %d\n", + connector->base.id, connector->name, + drm_eld_size(eld), total_sad_count); } static int _drm_edid_to_sad(const struct drm_edid *drm_edid, @@ -5849,7 +5858,8 @@ static void drm_parse_vcdb(struct drm_connector *connector, const u8 *db) { struct drm_display_info *info = &connector->display_info; - DRM_DEBUG_KMS("CEA VCDB 0x%02x\n", db[2]); + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] CEA VCDB 0x%02x\n", + connector->base.id, connector->name, db[2]); if (db[2] & EDID_CEA_VCDB_QS) info->rgb_quant_range_selectable = true; @@ -6052,39 +6062,39 @@ static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector, if (hdmi[6] & DRM_EDID_HDMI_DC_30) { dc_bpc = 10; info->edid_hdmi_rgb444_dc_modes |= DRM_EDID_HDMI_DC_30; - DRM_DEBUG("%s: HDMI sink does deep color 30.\n", - connector->name); + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] HDMI sink does deep color 30.\n", + connector->base.id, connector->name); } if (hdmi[6] & DRM_EDID_HDMI_DC_36) { dc_bpc = 12; info->edid_hdmi_rgb444_dc_modes |= DRM_EDID_HDMI_DC_36; - DRM_DEBUG("%s: HDMI sink does deep color 36.\n", - connector->name); + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] HDMI sink does deep color 36.\n", + connector->base.id, connector->name); } if (hdmi[6] & DRM_EDID_HDMI_DC_48) { dc_bpc = 16; info->edid_hdmi_rgb444_dc_modes |= DRM_EDID_HDMI_DC_48; - DRM_DEBUG("%s: HDMI sink does deep color 48.\n", - connector->name); + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] HDMI sink does deep color 48.\n", + connector->base.id, connector->name); } if (dc_bpc == 0) { - DRM_DEBUG("%s: No deep color support on this HDMI sink.\n", - connector->name); + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] No deep color support on this HDMI sink.\n", + connector->base.id, connector->name); return; } - DRM_DEBUG("%s: Assigning HDMI sink color depth as %d bpc.\n", - connector->name, dc_bpc); + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] Assigning HDMI sink color depth as %d bpc.\n", + connector->base.id, connector->name, dc_bpc); info->bpc = dc_bpc; /* YCRCB444 is optional according to spec. */ if (hdmi[6] & DRM_EDID_HDMI_DC_Y444) { info->edid_hdmi_ycbcr444_dc_modes = info->edid_hdmi_rgb444_dc_modes; - DRM_DEBUG("%s: HDMI sink does YCRCB444 in deep color.\n", - connector->name); + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] HDMI sink does YCRCB444 in deep color.\n", + connector->base.id, connector->name); } /* @@ -6092,8 +6102,8 @@ static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector, * then deep color 36 bit must be supported. */ if (!(hdmi[6] & DRM_EDID_HDMI_DC_36)) { - DRM_DEBUG("%s: HDMI sink should do DC_36, but does not!\n", - connector->name); + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] HDMI sink should do DC_36, but does not!\n", + connector->base.id, connector->name); } } @@ -6110,10 +6120,9 @@ drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db) if (len >= 7) info->max_tmds_clock = db[7] * 5000; - DRM_DEBUG_KMS("HDMI: DVI dual %d, " - "max TMDS clock %d kHz\n", - info->dvi_dual, - info->max_tmds_clock); + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] HDMI: DVI dual %d, max TMDS clock %d kHz\n", + connector->base.id, connector->name, + info->dvi_dual, info->max_tmds_clock); drm_parse_hdmi_deep_color_info(connector, db); } @@ -6156,8 +6165,10 @@ static void drm_parse_cea_ext(struct drm_connector *connector, info->cea_rev = edid_ext[1]; if (info->cea_rev != edid_ext[1]) - DRM_DEBUG_KMS("CEA extension version mismatch %u != %u\n", - info->cea_rev, edid_ext[1]); + drm_dbg_kms(connector->dev, + "[CONNECTOR:%d:%s] CEA extension version mismatch %u != %u\n", + connector->base.id, connector->name, + info->cea_rev, edid_ext[1]); /* The existence of a CTA extension should imply RGB support */ info->color_formats = DRM_COLOR_FORMAT_RGB444; @@ -6243,9 +6254,10 @@ static void drm_get_monitor_range(struct drm_connector *connector, drm_for_each_detailed_block(drm_edid, get_monitor_range, &closure); - DRM_DEBUG_KMS("Supported Monitor Refresh rate range is %d Hz - %d Hz\n", - info->monitor_range.min_vfreq, - info->monitor_range.max_vfreq); + drm_dbg_kms(connector->dev, + "[CONNECTOR:%d:%s] Supported Monitor Refresh rate range is %d Hz - %d Hz\n", + connector->base.id, connector->name, + info->monitor_range.min_vfreq, info->monitor_range.max_vfreq); } static void drm_parse_vesa_mso_data(struct drm_connector *connector, @@ -6387,8 +6399,9 @@ static u32 update_display_info(struct drm_connector *connector, if (info->bpc == 0 && edid->revision == 3 && edid->input & DRM_EDID_DIGITAL_DFP_1_X) { info->bpc = 8; - DRM_DEBUG("%s: Assigning DFP sink color depth as %d bpc.\n", - connector->name, info->bpc); + drm_dbg_kms(connector->dev, + "[CONNECTOR:%d:%s] Assigning DFP sink color depth as %d bpc.\n", + connector->base.id, connector->name, info->bpc); } /* Only defined for 1.4 with digital displays */ @@ -6420,8 +6433,9 @@ static u32 update_display_info(struct drm_connector *connector, break; } - DRM_DEBUG("%s: Assigning EDID-1.4 digital sink color depth as %d bpc.\n", - connector->name, info->bpc); + drm_dbg_kms(connector->dev, + "[CONNECTOR:%d:%s] Assigning EDID-1.4 digital sink color depth as %d bpc.\n", + connector->base.id, connector->name, info->bpc); if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB444) info->color_formats |= DRM_COLOR_FORMAT_YCBCR444; @@ -7121,11 +7135,14 @@ static void drm_parse_tiled_block(struct drm_connector *connector, connector->tile_h_size = w + 1; connector->tile_v_size = h + 1; - DRM_DEBUG_KMS("tile cap 0x%x\n", tile->tile_cap); - DRM_DEBUG_KMS("tile_size %d x %d\n", w + 1, h + 1); - DRM_DEBUG_KMS("topo num tiles %dx%d, location %dx%d\n", - num_h_tile + 1, num_v_tile + 1, tile_h_loc, tile_v_loc); - DRM_DEBUG_KMS("vend %c%c%c\n", tile->topology_id[0], tile->topology_id[1], tile->topology_id[2]); + drm_dbg_kms(connector->dev, + "[CONNECTOR:%d:%s] tile cap 0x%x, size %dx%d, num tiles %dx%d, location %dx%d, vend %c%c%c", + connector->base.id, connector->name, + tile->tile_cap, + connector->tile_h_size, connector->tile_v_size, + connector->num_h_tile, connector->num_v_tile, + connector->tile_h_loc, connector->tile_v_loc, + tile->topology_id[0], tile->topology_id[1], tile->topology_id[2]); tg = drm_mode_get_tile_group(connector->dev, tile->topology_id); if (!tg) -- cgit From 89cb0ba4ceee6bed1059904859c5723b3f39da68 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 25 Oct 2022 14:44:55 +0300 Subject: drm/i915/tgl+: Add locking around DKL PHY register accesses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Accessing the TypeC DKL PHY registers during modeset-commit, -verification, DP link-retraining and AUX power well toggling is racy due to these code paths being concurrent and the PHY register bank selection register (HIP_INDEX_REG) being shared between PHY instances (aka TC ports) and the bank selection being not atomic wrt. the actual PHY register access. Add the required locking around each PHY register bank selection-> register access sequence. Kudos to Ville for noticing the race conditions. v2: - Add the DKL PHY register accessors to intel_dkl_phy.[ch]. (Jani) - Make the DKL_REG_TC_PORT macro independent of PHY internals. - Move initing the DKL PHY lock to a more logical place. v3: - Fix parameter reuse in the DKL_REG_TC_PORT definition. - Document the usage of phy_lock. v4: - Fix adding TC_PORT_1 offset in the DKL_REG_TC_PORT definition. Cc: Ville Syrjälä Cc: Jani Nikula Cc: # v5.5+ Acked-by: Jani Nikula Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20221025114457.2191004-1-imre.deak@intel.com --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/display/intel_ddi.c | 68 ++++++------- drivers/gpu/drm/i915/display/intel_display_core.h | 8 ++ .../drm/i915/display/intel_display_power_well.c | 7 +- drivers/gpu/drm/i915/display/intel_dkl_phy.c | 109 +++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_dkl_phy.h | 24 +++++ drivers/gpu/drm/i915/display/intel_dpll_mgr.c | 59 +++++------ drivers/gpu/drm/i915/i915_driver.c | 1 + drivers/gpu/drm/i915/i915_reg.h | 3 + 9 files changed, 204 insertions(+), 76 deletions(-) create mode 100644 drivers/gpu/drm/i915/display/intel_dkl_phy.c create mode 100644 drivers/gpu/drm/i915/display/intel_dkl_phy.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 8f35be02b80e..b9da872ba8c0 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -281,6 +281,7 @@ i915-y += \ display/intel_ddi.o \ display/intel_ddi_buf_trans.o \ display/intel_display_trace.o \ + display/intel_dkl_phy.o \ display/intel_dp.o \ display/intel_dp_aux.o \ display/intel_dp_aux_backlight.o \ diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 971356237eca..7708ccbbdeb7 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -43,6 +43,7 @@ #include "intel_de.h" #include "intel_display_power.h" #include "intel_display_types.h" +#include "intel_dkl_phy.h" #include "intel_dp.h" #include "intel_dp_link_training.h" #include "intel_dp_mst.h" @@ -1262,33 +1263,30 @@ static void tgl_dkl_phy_set_signal_levels(struct intel_encoder *encoder, for (ln = 0; ln < 2; ln++) { int level; - intel_de_write(dev_priv, HIP_INDEX_REG(tc_port), - HIP_INDEX_VAL(tc_port, ln)); - - intel_de_write(dev_priv, DKL_TX_PMD_LANE_SUS(tc_port), 0); + intel_dkl_phy_write(dev_priv, DKL_TX_PMD_LANE_SUS(tc_port), ln, 0); level = intel_ddi_level(encoder, crtc_state, 2*ln+0); - intel_de_rmw(dev_priv, DKL_TX_DPCNTL0(tc_port), - DKL_TX_PRESHOOT_COEFF_MASK | - DKL_TX_DE_EMPAHSIS_COEFF_MASK | - DKL_TX_VSWING_CONTROL_MASK, - DKL_TX_PRESHOOT_COEFF(trans->entries[level].dkl.preshoot) | - DKL_TX_DE_EMPHASIS_COEFF(trans->entries[level].dkl.de_emphasis) | - DKL_TX_VSWING_CONTROL(trans->entries[level].dkl.vswing)); + intel_dkl_phy_rmw(dev_priv, DKL_TX_DPCNTL0(tc_port), ln, + DKL_TX_PRESHOOT_COEFF_MASK | + DKL_TX_DE_EMPAHSIS_COEFF_MASK | + DKL_TX_VSWING_CONTROL_MASK, + DKL_TX_PRESHOOT_COEFF(trans->entries[level].dkl.preshoot) | + DKL_TX_DE_EMPHASIS_COEFF(trans->entries[level].dkl.de_emphasis) | + DKL_TX_VSWING_CONTROL(trans->entries[level].dkl.vswing)); level = intel_ddi_level(encoder, crtc_state, 2*ln+1); - intel_de_rmw(dev_priv, DKL_TX_DPCNTL1(tc_port), - DKL_TX_PRESHOOT_COEFF_MASK | - DKL_TX_DE_EMPAHSIS_COEFF_MASK | - DKL_TX_VSWING_CONTROL_MASK, - DKL_TX_PRESHOOT_COEFF(trans->entries[level].dkl.preshoot) | - DKL_TX_DE_EMPHASIS_COEFF(trans->entries[level].dkl.de_emphasis) | - DKL_TX_VSWING_CONTROL(trans->entries[level].dkl.vswing)); + intel_dkl_phy_rmw(dev_priv, DKL_TX_DPCNTL1(tc_port), ln, + DKL_TX_PRESHOOT_COEFF_MASK | + DKL_TX_DE_EMPAHSIS_COEFF_MASK | + DKL_TX_VSWING_CONTROL_MASK, + DKL_TX_PRESHOOT_COEFF(trans->entries[level].dkl.preshoot) | + DKL_TX_DE_EMPHASIS_COEFF(trans->entries[level].dkl.de_emphasis) | + DKL_TX_VSWING_CONTROL(trans->entries[level].dkl.vswing)); - intel_de_rmw(dev_priv, DKL_TX_DPCNTL2(tc_port), - DKL_TX_DP20BITMODE, 0); + intel_dkl_phy_rmw(dev_priv, DKL_TX_DPCNTL2(tc_port), ln, + DKL_TX_DP20BITMODE, 0); if (IS_ALDERLAKE_P(dev_priv)) { u32 val; @@ -1306,10 +1304,10 @@ static void tgl_dkl_phy_set_signal_levels(struct intel_encoder *encoder, val |= DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2(0); } - intel_de_rmw(dev_priv, DKL_TX_DPCNTL2(tc_port), - DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX1_MASK | - DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2_MASK, - val); + intel_dkl_phy_rmw(dev_priv, DKL_TX_DPCNTL2(tc_port), ln, + DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX1_MASK | + DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2_MASK, + val); } } } @@ -2019,12 +2017,8 @@ icl_program_mg_dp_mode(struct intel_digital_port *dig_port, return; if (DISPLAY_VER(dev_priv) >= 12) { - intel_de_write(dev_priv, HIP_INDEX_REG(tc_port), - HIP_INDEX_VAL(tc_port, 0x0)); - ln0 = intel_de_read(dev_priv, DKL_DP_MODE(tc_port)); - intel_de_write(dev_priv, HIP_INDEX_REG(tc_port), - HIP_INDEX_VAL(tc_port, 0x1)); - ln1 = intel_de_read(dev_priv, DKL_DP_MODE(tc_port)); + ln0 = intel_dkl_phy_read(dev_priv, DKL_DP_MODE(tc_port), 0); + ln1 = intel_dkl_phy_read(dev_priv, DKL_DP_MODE(tc_port), 1); } else { ln0 = intel_de_read(dev_priv, MG_DP_MODE(0, tc_port)); ln1 = intel_de_read(dev_priv, MG_DP_MODE(1, tc_port)); @@ -2085,12 +2079,8 @@ icl_program_mg_dp_mode(struct intel_digital_port *dig_port, } if (DISPLAY_VER(dev_priv) >= 12) { - intel_de_write(dev_priv, HIP_INDEX_REG(tc_port), - HIP_INDEX_VAL(tc_port, 0x0)); - intel_de_write(dev_priv, DKL_DP_MODE(tc_port), ln0); - intel_de_write(dev_priv, HIP_INDEX_REG(tc_port), - HIP_INDEX_VAL(tc_port, 0x1)); - intel_de_write(dev_priv, DKL_DP_MODE(tc_port), ln1); + intel_dkl_phy_write(dev_priv, DKL_DP_MODE(tc_port), 0, ln0); + intel_dkl_phy_write(dev_priv, DKL_DP_MODE(tc_port), 1, ln1); } else { intel_de_write(dev_priv, MG_DP_MODE(0, tc_port), ln0); intel_de_write(dev_priv, MG_DP_MODE(1, tc_port), ln1); @@ -3094,10 +3084,8 @@ static void adlp_tbt_to_dp_alt_switch_wa(struct intel_encoder *encoder) enum tc_port tc_port = intel_port_to_tc(i915, encoder->port); int ln; - for (ln = 0; ln < 2; ln++) { - intel_de_write(i915, HIP_INDEX_REG(tc_port), HIP_INDEX_VAL(tc_port, ln)); - intel_de_rmw(i915, DKL_PCS_DW5(tc_port), DKL_PCS_DW5_CORE_SOFTRESET, 0); - } + for (ln = 0; ln < 2; ln++) + intel_dkl_phy_rmw(i915, DKL_PCS_DW5(tc_port), ln, DKL_PCS_DW5_CORE_SOFTRESET, 0); } static void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp, diff --git a/drivers/gpu/drm/i915/display/intel_display_core.h b/drivers/gpu/drm/i915/display/intel_display_core.h index b4b9c4cef78e..337d8e08ba43 100644 --- a/drivers/gpu/drm/i915/display/intel_display_core.h +++ b/drivers/gpu/drm/i915/display/intel_display_core.h @@ -320,6 +320,14 @@ struct intel_display { struct intel_global_obj obj; } dbuf; + struct { + /* + * dkl.phy_lock protects against concurrent access of the + * Dekel TypeC PHYs. + */ + spinlock_t phy_lock; + } dkl; + struct { /* VLV/CHV/BXT/GLK DSI MMIO register base address */ u32 mmio_base; diff --git a/drivers/gpu/drm/i915/display/intel_display_power_well.c b/drivers/gpu/drm/i915/display/intel_display_power_well.c index df7ee4969ef1..1d18eee56253 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power_well.c +++ b/drivers/gpu/drm/i915/display/intel_display_power_well.c @@ -12,6 +12,7 @@ #include "intel_de.h" #include "intel_display_power_well.h" #include "intel_display_types.h" +#include "intel_dkl_phy.h" #include "intel_dmc.h" #include "intel_dpio_phy.h" #include "intel_dpll.h" @@ -529,11 +530,9 @@ icl_tc_phy_aux_power_well_enable(struct drm_i915_private *dev_priv, enum tc_port tc_port; tc_port = TGL_AUX_PW_TO_TC_PORT(i915_power_well_instance(power_well)->hsw.idx); - intel_de_write(dev_priv, HIP_INDEX_REG(tc_port), - HIP_INDEX_VAL(tc_port, 0x2)); - if (intel_de_wait_for_set(dev_priv, DKL_CMN_UC_DW_27(tc_port), - DKL_CMN_UC_DW27_UC_HEALTH, 1)) + if (wait_for(intel_dkl_phy_read(dev_priv, DKL_CMN_UC_DW_27(tc_port), 2) & + DKL_CMN_UC_DW27_UC_HEALTH, 1)) drm_warn(&dev_priv->drm, "Timeout waiting TC uC health\n"); } diff --git a/drivers/gpu/drm/i915/display/intel_dkl_phy.c b/drivers/gpu/drm/i915/display/intel_dkl_phy.c new file mode 100644 index 000000000000..710b030c7ed5 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_dkl_phy.c @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2022 Intel Corporation + */ + +#include "i915_drv.h" +#include "i915_reg.h" + +#include "intel_de.h" +#include "intel_display.h" +#include "intel_dkl_phy.h" + +static void +dkl_phy_set_hip_idx(struct drm_i915_private *i915, i915_reg_t reg, int idx) +{ + enum tc_port tc_port = DKL_REG_TC_PORT(reg); + + drm_WARN_ON(&i915->drm, tc_port < TC_PORT_1 || tc_port >= I915_MAX_TC_PORTS); + + intel_de_write(i915, + HIP_INDEX_REG(tc_port), + HIP_INDEX_VAL(tc_port, idx)); +} + +/** + * intel_dkl_phy_read - read a Dekel PHY register + * @i915: i915 device instance + * @reg: Dekel PHY register + * @ln: lane instance of @reg + * + * Read the @reg Dekel PHY register. + * + * Returns the read value. + */ +u32 +intel_dkl_phy_read(struct drm_i915_private *i915, i915_reg_t reg, int ln) +{ + u32 val; + + spin_lock(&i915->display.dkl.phy_lock); + + dkl_phy_set_hip_idx(i915, reg, ln); + val = intel_de_read(i915, reg); + + spin_unlock(&i915->display.dkl.phy_lock); + + return val; +} + +/** + * intel_dkl_phy_write - write a Dekel PHY register + * @i915: i915 device instance + * @reg: Dekel PHY register + * @ln: lane instance of @reg + * @val: value to write + * + * Write @val to the @reg Dekel PHY register. + */ +void +intel_dkl_phy_write(struct drm_i915_private *i915, i915_reg_t reg, int ln, u32 val) +{ + spin_lock(&i915->display.dkl.phy_lock); + + dkl_phy_set_hip_idx(i915, reg, ln); + intel_de_write(i915, reg, val); + + spin_unlock(&i915->display.dkl.phy_lock); +} + +/** + * intel_dkl_phy_rmw - read-modify-write a Dekel PHY register + * @i915: i915 device instance + * @reg: Dekel PHY register + * @ln: lane instance of @reg + * @clear: mask to clear + * @set: mask to set + * + * Read the @reg Dekel PHY register, clearing then setting the @clear/@set bits in it, and writing + * this value back to the register if the value differs from the read one. + */ +void +intel_dkl_phy_rmw(struct drm_i915_private *i915, i915_reg_t reg, int ln, u32 clear, u32 set) +{ + spin_lock(&i915->display.dkl.phy_lock); + + dkl_phy_set_hip_idx(i915, reg, ln); + intel_de_rmw(i915, reg, clear, set); + + spin_unlock(&i915->display.dkl.phy_lock); +} + +/** + * intel_dkl_phy_posting_read - do a posting read from a Dekel PHY register + * @i915: i915 device instance + * @reg: Dekel PHY register + * @ln: lane instance of @reg + * + * Read the @reg Dekel PHY register without returning the read value. + */ +void +intel_dkl_phy_posting_read(struct drm_i915_private *i915, i915_reg_t reg, int ln) +{ + spin_lock(&i915->display.dkl.phy_lock); + + dkl_phy_set_hip_idx(i915, reg, ln); + intel_de_posting_read(i915, reg); + + spin_unlock(&i915->display.dkl.phy_lock); +} diff --git a/drivers/gpu/drm/i915/display/intel_dkl_phy.h b/drivers/gpu/drm/i915/display/intel_dkl_phy.h new file mode 100644 index 000000000000..260ad121a0b1 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_dkl_phy.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2022 Intel Corporation + */ + +#ifndef __INTEL_DKL_PHY_H__ +#define __INTEL_DKL_PHY_H__ + +#include + +#include "i915_reg_defs.h" + +struct drm_i915_private; + +u32 +intel_dkl_phy_read(struct drm_i915_private *i915, i915_reg_t reg, int ln); +void +intel_dkl_phy_write(struct drm_i915_private *i915, i915_reg_t reg, int ln, u32 val); +void +intel_dkl_phy_rmw(struct drm_i915_private *i915, i915_reg_t reg, int ln, u32 clear, u32 set); +void +intel_dkl_phy_posting_read(struct drm_i915_private *i915, i915_reg_t reg, int ln); + +#endif /* __INTEL_DKL_PHY_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c index b63600d8ebeb..8bbc2b5e50ed 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c @@ -25,6 +25,7 @@ #include "intel_de.h" #include "intel_display_types.h" +#include "intel_dkl_phy.h" #include "intel_dpio_phy.h" #include "intel_dpll.h" #include "intel_dpll_mgr.h" @@ -3486,15 +3487,12 @@ static bool dkl_pll_get_hw_state(struct drm_i915_private *dev_priv, * All registers read here have the same HIP_INDEX_REG even though * they are on different building blocks */ - intel_de_write(dev_priv, HIP_INDEX_REG(tc_port), - HIP_INDEX_VAL(tc_port, 0x2)); - - hw_state->mg_refclkin_ctl = intel_de_read(dev_priv, - DKL_REFCLKIN_CTL(tc_port)); + hw_state->mg_refclkin_ctl = intel_dkl_phy_read(dev_priv, + DKL_REFCLKIN_CTL(tc_port), 2); hw_state->mg_refclkin_ctl &= MG_REFCLKIN_CTL_OD_2_MUX_MASK; hw_state->mg_clktop2_hsclkctl = - intel_de_read(dev_priv, DKL_CLKTOP2_HSCLKCTL(tc_port)); + intel_dkl_phy_read(dev_priv, DKL_CLKTOP2_HSCLKCTL(tc_port), 2); hw_state->mg_clktop2_hsclkctl &= MG_CLKTOP2_HSCLKCTL_TLINEDRV_CLKSEL_MASK | MG_CLKTOP2_HSCLKCTL_CORE_INPUTSEL_MASK | @@ -3502,32 +3500,32 @@ static bool dkl_pll_get_hw_state(struct drm_i915_private *dev_priv, MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_MASK; hw_state->mg_clktop2_coreclkctl1 = - intel_de_read(dev_priv, DKL_CLKTOP2_CORECLKCTL1(tc_port)); + intel_dkl_phy_read(dev_priv, DKL_CLKTOP2_CORECLKCTL1(tc_port), 2); hw_state->mg_clktop2_coreclkctl1 &= MG_CLKTOP2_CORECLKCTL1_A_DIVRATIO_MASK; - hw_state->mg_pll_div0 = intel_de_read(dev_priv, DKL_PLL_DIV0(tc_port)); + hw_state->mg_pll_div0 = intel_dkl_phy_read(dev_priv, DKL_PLL_DIV0(tc_port), 2); val = DKL_PLL_DIV0_MASK; if (dev_priv->display.vbt.override_afc_startup) val |= DKL_PLL_DIV0_AFC_STARTUP_MASK; hw_state->mg_pll_div0 &= val; - hw_state->mg_pll_div1 = intel_de_read(dev_priv, DKL_PLL_DIV1(tc_port)); + hw_state->mg_pll_div1 = intel_dkl_phy_read(dev_priv, DKL_PLL_DIV1(tc_port), 2); hw_state->mg_pll_div1 &= (DKL_PLL_DIV1_IREF_TRIM_MASK | DKL_PLL_DIV1_TDC_TARGET_CNT_MASK); - hw_state->mg_pll_ssc = intel_de_read(dev_priv, DKL_PLL_SSC(tc_port)); + hw_state->mg_pll_ssc = intel_dkl_phy_read(dev_priv, DKL_PLL_SSC(tc_port), 2); hw_state->mg_pll_ssc &= (DKL_PLL_SSC_IREF_NDIV_RATIO_MASK | DKL_PLL_SSC_STEP_LEN_MASK | DKL_PLL_SSC_STEP_NUM_MASK | DKL_PLL_SSC_EN); - hw_state->mg_pll_bias = intel_de_read(dev_priv, DKL_PLL_BIAS(tc_port)); + hw_state->mg_pll_bias = intel_dkl_phy_read(dev_priv, DKL_PLL_BIAS(tc_port), 2); hw_state->mg_pll_bias &= (DKL_PLL_BIAS_FRAC_EN_H | DKL_PLL_BIAS_FBDIV_FRAC_MASK); hw_state->mg_pll_tdc_coldst_bias = - intel_de_read(dev_priv, DKL_PLL_TDC_COLDST_BIAS(tc_port)); + intel_dkl_phy_read(dev_priv, DKL_PLL_TDC_COLDST_BIAS(tc_port), 2); hw_state->mg_pll_tdc_coldst_bias &= (DKL_PLL_TDC_SSC_STEP_SIZE_MASK | DKL_PLL_TDC_FEED_FWD_GAIN_MASK); @@ -3715,61 +3713,58 @@ static void dkl_pll_write(struct drm_i915_private *dev_priv, * All registers programmed here have the same HIP_INDEX_REG even * though on different building block */ - intel_de_write(dev_priv, HIP_INDEX_REG(tc_port), - HIP_INDEX_VAL(tc_port, 0x2)); - /* All the registers are RMW */ - val = intel_de_read(dev_priv, DKL_REFCLKIN_CTL(tc_port)); + val = intel_dkl_phy_read(dev_priv, DKL_REFCLKIN_CTL(tc_port), 2); val &= ~MG_REFCLKIN_CTL_OD_2_MUX_MASK; val |= hw_state->mg_refclkin_ctl; - intel_de_write(dev_priv, DKL_REFCLKIN_CTL(tc_port), val); + intel_dkl_phy_write(dev_priv, DKL_REFCLKIN_CTL(tc_port), 2, val); - val = intel_de_read(dev_priv, DKL_CLKTOP2_CORECLKCTL1(tc_port)); + val = intel_dkl_phy_read(dev_priv, DKL_CLKTOP2_CORECLKCTL1(tc_port), 2); val &= ~MG_CLKTOP2_CORECLKCTL1_A_DIVRATIO_MASK; val |= hw_state->mg_clktop2_coreclkctl1; - intel_de_write(dev_priv, DKL_CLKTOP2_CORECLKCTL1(tc_port), val); + intel_dkl_phy_write(dev_priv, DKL_CLKTOP2_CORECLKCTL1(tc_port), 2, val); - val = intel_de_read(dev_priv, DKL_CLKTOP2_HSCLKCTL(tc_port)); + val = intel_dkl_phy_read(dev_priv, DKL_CLKTOP2_HSCLKCTL(tc_port), 2); val &= ~(MG_CLKTOP2_HSCLKCTL_TLINEDRV_CLKSEL_MASK | MG_CLKTOP2_HSCLKCTL_CORE_INPUTSEL_MASK | MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_MASK | MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_MASK); val |= hw_state->mg_clktop2_hsclkctl; - intel_de_write(dev_priv, DKL_CLKTOP2_HSCLKCTL(tc_port), val); + intel_dkl_phy_write(dev_priv, DKL_CLKTOP2_HSCLKCTL(tc_port), 2, val); val = DKL_PLL_DIV0_MASK; if (dev_priv->display.vbt.override_afc_startup) val |= DKL_PLL_DIV0_AFC_STARTUP_MASK; - intel_de_rmw(dev_priv, DKL_PLL_DIV0(tc_port), val, - hw_state->mg_pll_div0); + intel_dkl_phy_rmw(dev_priv, DKL_PLL_DIV0(tc_port), 2, val, + hw_state->mg_pll_div0); - val = intel_de_read(dev_priv, DKL_PLL_DIV1(tc_port)); + val = intel_dkl_phy_read(dev_priv, DKL_PLL_DIV1(tc_port), 2); val &= ~(DKL_PLL_DIV1_IREF_TRIM_MASK | DKL_PLL_DIV1_TDC_TARGET_CNT_MASK); val |= hw_state->mg_pll_div1; - intel_de_write(dev_priv, DKL_PLL_DIV1(tc_port), val); + intel_dkl_phy_write(dev_priv, DKL_PLL_DIV1(tc_port), 2, val); - val = intel_de_read(dev_priv, DKL_PLL_SSC(tc_port)); + val = intel_dkl_phy_read(dev_priv, DKL_PLL_SSC(tc_port), 2); val &= ~(DKL_PLL_SSC_IREF_NDIV_RATIO_MASK | DKL_PLL_SSC_STEP_LEN_MASK | DKL_PLL_SSC_STEP_NUM_MASK | DKL_PLL_SSC_EN); val |= hw_state->mg_pll_ssc; - intel_de_write(dev_priv, DKL_PLL_SSC(tc_port), val); + intel_dkl_phy_write(dev_priv, DKL_PLL_SSC(tc_port), 2, val); - val = intel_de_read(dev_priv, DKL_PLL_BIAS(tc_port)); + val = intel_dkl_phy_read(dev_priv, DKL_PLL_BIAS(tc_port), 2); val &= ~(DKL_PLL_BIAS_FRAC_EN_H | DKL_PLL_BIAS_FBDIV_FRAC_MASK); val |= hw_state->mg_pll_bias; - intel_de_write(dev_priv, DKL_PLL_BIAS(tc_port), val); + intel_dkl_phy_write(dev_priv, DKL_PLL_BIAS(tc_port), 2, val); - val = intel_de_read(dev_priv, DKL_PLL_TDC_COLDST_BIAS(tc_port)); + val = intel_dkl_phy_read(dev_priv, DKL_PLL_TDC_COLDST_BIAS(tc_port), 2); val &= ~(DKL_PLL_TDC_SSC_STEP_SIZE_MASK | DKL_PLL_TDC_FEED_FWD_GAIN_MASK); val |= hw_state->mg_pll_tdc_coldst_bias; - intel_de_write(dev_priv, DKL_PLL_TDC_COLDST_BIAS(tc_port), val); + intel_dkl_phy_write(dev_priv, DKL_PLL_TDC_COLDST_BIAS(tc_port), 2, val); - intel_de_posting_read(dev_priv, DKL_PLL_TDC_COLDST_BIAS(tc_port)); + intel_dkl_phy_posting_read(dev_priv, DKL_PLL_TDC_COLDST_BIAS(tc_port), 2); } static void icl_pll_power_enable(struct drm_i915_private *dev_priv, diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c index e7b2ebc6b88d..5802be24a22f 100644 --- a/drivers/gpu/drm/i915/i915_driver.c +++ b/drivers/gpu/drm/i915/i915_driver.c @@ -341,6 +341,7 @@ static int i915_driver_early_probe(struct drm_i915_private *dev_priv) mutex_init(&dev_priv->display.wm.wm_mutex); mutex_init(&dev_priv->display.pps.mutex); mutex_init(&dev_priv->display.hdcp.comp_mutex); + spin_lock_init(&dev_priv->display.dkl.phy_lock); i915_memcpy_init_early(dev_priv); intel_runtime_pm_init_early(&dev_priv->runtime_pm); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 975ce5e0a890..959c2bd6707c 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -7425,6 +7425,9 @@ enum skl_power_gate { #define _DKL_PHY5_BASE 0x16C000 #define _DKL_PHY6_BASE 0x16D000 +#define DKL_REG_TC_PORT(__reg) \ + (TC_PORT_1 + ((__reg).reg - _DKL_PHY1_BASE) / (_DKL_PHY2_BASE - _DKL_PHY1_BASE)) + /* DEKEL PHY MMIO Address = Phy base + (internal address & ~index_mask) */ #define _DKL_PCS_DW5 0x14 #define DKL_PCS_DW5(tc_port) _MMIO(_PORT(tc_port, _DKL_PHY1_BASE, \ -- cgit From 589ebefd7a892f3f8b550066524643f1ea66f858 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 25 Oct 2022 13:26:42 +0300 Subject: drm/i915: Rename intel_tc_phy_regs.h to intel_mg_phy_regs.h An upcoming patch moves the DKL PHY register definitions to intel_dkl_phy_regs.h, so for consistency rename intel_tc_phy_regs.h containing only MG PHY register definitions to intel_mg_phy_regs.h. Suggested-by: Jani Nikula Cc: Jani Nikula Acked-by: Jani Nikula Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20221025102644.2123988-3-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 2 +- drivers/gpu/drm/i915/display/intel_dpll_mgr.c | 2 +- drivers/gpu/drm/i915/display/intel_mg_phy_regs.h | 280 +++++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_tc.c | 2 +- drivers/gpu/drm/i915/display/intel_tc_phy_regs.h | 280 ----------------------- 5 files changed, 283 insertions(+), 283 deletions(-) create mode 100644 drivers/gpu/drm/i915/display/intel_mg_phy_regs.h delete mode 100644 drivers/gpu/drm/i915/display/intel_tc_phy_regs.h diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 7708ccbbdeb7..37272c6e4269 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -56,13 +56,13 @@ #include "intel_hdmi.h" #include "intel_hotplug.h" #include "intel_lspcon.h" +#include "intel_mg_phy_regs.h" #include "intel_pps.h" #include "intel_psr.h" #include "intel_quirks.h" #include "intel_snps_phy.h" #include "intel_sprite.h" #include "intel_tc.h" -#include "intel_tc_phy_regs.h" #include "intel_vdsc.h" #include "intel_vrr.h" #include "skl_scaler.h" diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c index 8bbc2b5e50ed..eb4decd8c68b 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c @@ -29,9 +29,9 @@ #include "intel_dpio_phy.h" #include "intel_dpll.h" #include "intel_dpll_mgr.h" +#include "intel_mg_phy_regs.h" #include "intel_pch_refclk.h" #include "intel_tc.h" -#include "intel_tc_phy_regs.h" /** * DOC: Display PLLs diff --git a/drivers/gpu/drm/i915/display/intel_mg_phy_regs.h b/drivers/gpu/drm/i915/display/intel_mg_phy_regs.h new file mode 100644 index 000000000000..07978f8d5fb7 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_mg_phy_regs.h @@ -0,0 +1,280 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2022 Intel Corporation + */ + +#ifndef __INTEL_MG_PHY_REGS__ +#define __INTEL_MG_PHY_REGS__ + +#include "i915_reg_defs.h" + +#define MG_PHY_PORT_LN(ln, tc_port, ln0p1, ln0p2, ln1p1) \ + _MMIO(_PORT(tc_port, ln0p1, ln0p2) + (ln) * ((ln1p1) - (ln0p1))) + +#define MG_TX_LINK_PARAMS_TX1LN0_PORT1 0x16812C +#define MG_TX_LINK_PARAMS_TX1LN1_PORT1 0x16852C +#define MG_TX_LINK_PARAMS_TX1LN0_PORT2 0x16912C +#define MG_TX_LINK_PARAMS_TX1LN1_PORT2 0x16952C +#define MG_TX1_LINK_PARAMS(ln, tc_port) \ + MG_PHY_PORT_LN(ln, tc_port, MG_TX_LINK_PARAMS_TX1LN0_PORT1, \ + MG_TX_LINK_PARAMS_TX1LN0_PORT2, \ + MG_TX_LINK_PARAMS_TX1LN1_PORT1) + +#define MG_TX_LINK_PARAMS_TX2LN0_PORT1 0x1680AC +#define MG_TX_LINK_PARAMS_TX2LN1_PORT1 0x1684AC +#define MG_TX_LINK_PARAMS_TX2LN0_PORT2 0x1690AC +#define MG_TX_LINK_PARAMS_TX2LN1_PORT2 0x1694AC +#define MG_TX2_LINK_PARAMS(ln, tc_port) \ + MG_PHY_PORT_LN(ln, tc_port, MG_TX_LINK_PARAMS_TX2LN0_PORT1, \ + MG_TX_LINK_PARAMS_TX2LN0_PORT2, \ + MG_TX_LINK_PARAMS_TX2LN1_PORT1) +#define CRI_USE_FS32 (1 << 5) + +#define MG_TX_PISO_READLOAD_TX1LN0_PORT1 0x16814C +#define MG_TX_PISO_READLOAD_TX1LN1_PORT1 0x16854C +#define MG_TX_PISO_READLOAD_TX1LN0_PORT2 0x16914C +#define MG_TX_PISO_READLOAD_TX1LN1_PORT2 0x16954C +#define MG_TX1_PISO_READLOAD(ln, tc_port) \ + MG_PHY_PORT_LN(ln, tc_port, MG_TX_PISO_READLOAD_TX1LN0_PORT1, \ + MG_TX_PISO_READLOAD_TX1LN0_PORT2, \ + MG_TX_PISO_READLOAD_TX1LN1_PORT1) + +#define MG_TX_PISO_READLOAD_TX2LN0_PORT1 0x1680CC +#define MG_TX_PISO_READLOAD_TX2LN1_PORT1 0x1684CC +#define MG_TX_PISO_READLOAD_TX2LN0_PORT2 0x1690CC +#define MG_TX_PISO_READLOAD_TX2LN1_PORT2 0x1694CC +#define MG_TX2_PISO_READLOAD(ln, tc_port) \ + MG_PHY_PORT_LN(ln, tc_port, MG_TX_PISO_READLOAD_TX2LN0_PORT1, \ + MG_TX_PISO_READLOAD_TX2LN0_PORT2, \ + MG_TX_PISO_READLOAD_TX2LN1_PORT1) +#define CRI_CALCINIT (1 << 1) + +#define MG_TX_SWINGCTRL_TX1LN0_PORT1 0x168148 +#define MG_TX_SWINGCTRL_TX1LN1_PORT1 0x168548 +#define MG_TX_SWINGCTRL_TX1LN0_PORT2 0x169148 +#define MG_TX_SWINGCTRL_TX1LN1_PORT2 0x169548 +#define MG_TX1_SWINGCTRL(ln, tc_port) \ + MG_PHY_PORT_LN(ln, tc_port, MG_TX_SWINGCTRL_TX1LN0_PORT1, \ + MG_TX_SWINGCTRL_TX1LN0_PORT2, \ + MG_TX_SWINGCTRL_TX1LN1_PORT1) + +#define MG_TX_SWINGCTRL_TX2LN0_PORT1 0x1680C8 +#define MG_TX_SWINGCTRL_TX2LN1_PORT1 0x1684C8 +#define MG_TX_SWINGCTRL_TX2LN0_PORT2 0x1690C8 +#define MG_TX_SWINGCTRL_TX2LN1_PORT2 0x1694C8 +#define MG_TX2_SWINGCTRL(ln, tc_port) \ + MG_PHY_PORT_LN(ln, tc_port, MG_TX_SWINGCTRL_TX2LN0_PORT1, \ + MG_TX_SWINGCTRL_TX2LN0_PORT2, \ + MG_TX_SWINGCTRL_TX2LN1_PORT1) +#define CRI_TXDEEMPH_OVERRIDE_17_12(x) ((x) << 0) +#define CRI_TXDEEMPH_OVERRIDE_17_12_MASK (0x3F << 0) + +#define MG_TX_DRVCTRL_TX1LN0_TXPORT1 0x168144 +#define MG_TX_DRVCTRL_TX1LN1_TXPORT1 0x168544 +#define MG_TX_DRVCTRL_TX1LN0_TXPORT2 0x169144 +#define MG_TX_DRVCTRL_TX1LN1_TXPORT2 0x169544 +#define MG_TX_DRVCTRL_TX1LN0_TXPORT3 0x16A144 +#define MG_TX_DRVCTRL_TX1LN1_TXPORT3 0x16A544 +#define MG_TX_DRVCTRL_TX1LN0_TXPORT4 0x16B144 +#define MG_TX_DRVCTRL_TX1LN1_TXPORT4 0x16B544 +#define MG_TX1_DRVCTRL(ln, tc_port) \ + MG_PHY_PORT_LN(ln, tc_port, MG_TX_DRVCTRL_TX1LN0_TXPORT1, \ + MG_TX_DRVCTRL_TX1LN0_TXPORT2, \ + MG_TX_DRVCTRL_TX1LN1_TXPORT1) + +#define MG_TX_DRVCTRL_TX2LN0_PORT1 0x1680C4 +#define MG_TX_DRVCTRL_TX2LN1_PORT1 0x1684C4 +#define MG_TX_DRVCTRL_TX2LN0_PORT2 0x1690C4 +#define MG_TX_DRVCTRL_TX2LN1_PORT2 0x1694C4 +#define MG_TX2_DRVCTRL(ln, tc_port) \ + MG_PHY_PORT_LN(ln, tc_port, MG_TX_DRVCTRL_TX2LN0_PORT1, \ + MG_TX_DRVCTRL_TX2LN0_PORT2, \ + MG_TX_DRVCTRL_TX2LN1_PORT1) +#define CRI_TXDEEMPH_OVERRIDE_11_6(x) ((x) << 24) +#define CRI_TXDEEMPH_OVERRIDE_11_6_MASK (0x3F << 24) +#define CRI_TXDEEMPH_OVERRIDE_EN (1 << 22) +#define CRI_TXDEEMPH_OVERRIDE_5_0(x) ((x) << 16) +#define CRI_TXDEEMPH_OVERRIDE_5_0_MASK (0x3F << 16) +#define CRI_LOADGEN_SEL(x) ((x) << 12) +#define CRI_LOADGEN_SEL_MASK (0x3 << 12) + +#define MG_CLKHUB_LN0_PORT1 0x16839C +#define MG_CLKHUB_LN1_PORT1 0x16879C +#define MG_CLKHUB_LN0_PORT2 0x16939C +#define MG_CLKHUB_LN1_PORT2 0x16979C +#define MG_CLKHUB(ln, tc_port) \ + MG_PHY_PORT_LN(ln, tc_port, MG_CLKHUB_LN0_PORT1, \ + MG_CLKHUB_LN0_PORT2, \ + MG_CLKHUB_LN1_PORT1) +#define CFG_LOW_RATE_LKREN_EN (1 << 11) + +#define MG_TX_DCC_TX1LN0_PORT1 0x168110 +#define MG_TX_DCC_TX1LN1_PORT1 0x168510 +#define MG_TX_DCC_TX1LN0_PORT2 0x169110 +#define MG_TX_DCC_TX1LN1_PORT2 0x169510 +#define MG_TX1_DCC(ln, tc_port) \ + MG_PHY_PORT_LN(ln, tc_port, MG_TX_DCC_TX1LN0_PORT1, \ + MG_TX_DCC_TX1LN0_PORT2, \ + MG_TX_DCC_TX1LN1_PORT1) +#define MG_TX_DCC_TX2LN0_PORT1 0x168090 +#define MG_TX_DCC_TX2LN1_PORT1 0x168490 +#define MG_TX_DCC_TX2LN0_PORT2 0x169090 +#define MG_TX_DCC_TX2LN1_PORT2 0x169490 +#define MG_TX2_DCC(ln, tc_port) \ + MG_PHY_PORT_LN(ln, tc_port, MG_TX_DCC_TX2LN0_PORT1, \ + MG_TX_DCC_TX2LN0_PORT2, \ + MG_TX_DCC_TX2LN1_PORT1) +#define CFG_AMI_CK_DIV_OVERRIDE_VAL(x) ((x) << 25) +#define CFG_AMI_CK_DIV_OVERRIDE_VAL_MASK (0x3 << 25) +#define CFG_AMI_CK_DIV_OVERRIDE_EN (1 << 24) + +#define MG_DP_MODE_LN0_ACU_PORT1 0x1683A0 +#define MG_DP_MODE_LN1_ACU_PORT1 0x1687A0 +#define MG_DP_MODE_LN0_ACU_PORT2 0x1693A0 +#define MG_DP_MODE_LN1_ACU_PORT2 0x1697A0 +#define MG_DP_MODE(ln, tc_port) \ + MG_PHY_PORT_LN(ln, tc_port, MG_DP_MODE_LN0_ACU_PORT1, \ + MG_DP_MODE_LN0_ACU_PORT2, \ + MG_DP_MODE_LN1_ACU_PORT1) +#define MG_DP_MODE_CFG_DP_X2_MODE (1 << 7) +#define MG_DP_MODE_CFG_DP_X1_MODE (1 << 6) + +#define FIA1_BASE 0x163000 +#define FIA2_BASE 0x16E000 +#define FIA3_BASE 0x16F000 +#define _FIA(fia) _PICK((fia), FIA1_BASE, FIA2_BASE, FIA3_BASE) +#define _MMIO_FIA(fia, off) _MMIO(_FIA(fia) + (off)) + +/* ICL PHY DFLEX registers */ +#define PORT_TX_DFLEXDPMLE1(fia) _MMIO_FIA((fia), 0x008C0) +#define DFLEXDPMLE1_DPMLETC_MASK(idx) (0xf << (4 * (idx))) +#define DFLEXDPMLE1_DPMLETC_ML0(idx) (1 << (4 * (idx))) +#define DFLEXDPMLE1_DPMLETC_ML1_0(idx) (3 << (4 * (idx))) +#define DFLEXDPMLE1_DPMLETC_ML3(idx) (8 << (4 * (idx))) +#define DFLEXDPMLE1_DPMLETC_ML3_2(idx) (12 << (4 * (idx))) +#define DFLEXDPMLE1_DPMLETC_ML3_0(idx) (15 << (4 * (idx))) + +#define _MG_REFCLKIN_CTL_PORT1 0x16892C +#define _MG_REFCLKIN_CTL_PORT2 0x16992C +#define MG_REFCLKIN_CTL_OD_2_MUX(x) ((x) << 8) +#define MG_REFCLKIN_CTL_OD_2_MUX_MASK (0x7 << 8) +#define MG_REFCLKIN_CTL(tc_port) _MMIO_PORT((tc_port), \ + _MG_REFCLKIN_CTL_PORT1, \ + _MG_REFCLKIN_CTL_PORT2) + +#define _MG_CLKTOP2_CORECLKCTL1_PORT1 0x1688D8 +#define _MG_CLKTOP2_CORECLKCTL1_PORT2 0x1698D8 +#define MG_CLKTOP2_CORECLKCTL1_B_DIVRATIO(x) ((x) << 16) +#define MG_CLKTOP2_CORECLKCTL1_B_DIVRATIO_MASK (0xff << 16) +#define MG_CLKTOP2_CORECLKCTL1_A_DIVRATIO(x) ((x) << 8) +#define MG_CLKTOP2_CORECLKCTL1_A_DIVRATIO_MASK (0xff << 8) +#define MG_CLKTOP2_CORECLKCTL1(tc_port) _MMIO_PORT((tc_port), \ + _MG_CLKTOP2_CORECLKCTL1_PORT1, \ + _MG_CLKTOP2_CORECLKCTL1_PORT2) + +#define _MG_CLKTOP2_HSCLKCTL_PORT1 0x1688D4 +#define _MG_CLKTOP2_HSCLKCTL_PORT2 0x1698D4 +#define MG_CLKTOP2_HSCLKCTL_CORE_INPUTSEL(x) ((x) << 16) +#define MG_CLKTOP2_HSCLKCTL_CORE_INPUTSEL_MASK (0x1 << 16) +#define MG_CLKTOP2_HSCLKCTL_TLINEDRV_CLKSEL(x) ((x) << 14) +#define MG_CLKTOP2_HSCLKCTL_TLINEDRV_CLKSEL_MASK (0x3 << 14) +#define MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_MASK (0x3 << 12) +#define MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_2 (0 << 12) +#define MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_3 (1 << 12) +#define MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_5 (2 << 12) +#define MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_7 (3 << 12) +#define MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO(x) ((x) << 8) +#define MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_SHIFT 8 +#define MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_MASK (0xf << 8) +#define MG_CLKTOP2_HSCLKCTL(tc_port) _MMIO_PORT((tc_port), \ + _MG_CLKTOP2_HSCLKCTL_PORT1, \ + _MG_CLKTOP2_HSCLKCTL_PORT2) + +#define _MG_PLL_DIV0_PORT1 0x168A00 +#define _MG_PLL_DIV0_PORT2 0x169A00 +#define MG_PLL_DIV0_FRACNEN_H (1 << 30) +#define MG_PLL_DIV0_FBDIV_FRAC_MASK (0x3fffff << 8) +#define MG_PLL_DIV0_FBDIV_FRAC_SHIFT 8 +#define MG_PLL_DIV0_FBDIV_FRAC(x) ((x) << 8) +#define MG_PLL_DIV0_FBDIV_INT_MASK (0xff << 0) +#define MG_PLL_DIV0_FBDIV_INT(x) ((x) << 0) +#define MG_PLL_DIV0(tc_port) _MMIO_PORT((tc_port), _MG_PLL_DIV0_PORT1, \ + _MG_PLL_DIV0_PORT2) + +#define _MG_PLL_DIV1_PORT1 0x168A04 +#define _MG_PLL_DIV1_PORT2 0x169A04 +#define MG_PLL_DIV1_IREF_NDIVRATIO(x) ((x) << 16) +#define MG_PLL_DIV1_DITHER_DIV_1 (0 << 12) +#define MG_PLL_DIV1_DITHER_DIV_2 (1 << 12) +#define MG_PLL_DIV1_DITHER_DIV_4 (2 << 12) +#define MG_PLL_DIV1_DITHER_DIV_8 (3 << 12) +#define MG_PLL_DIV1_NDIVRATIO(x) ((x) << 4) +#define MG_PLL_DIV1_FBPREDIV_MASK (0xf << 0) +#define MG_PLL_DIV1_FBPREDIV(x) ((x) << 0) +#define MG_PLL_DIV1(tc_port) _MMIO_PORT((tc_port), _MG_PLL_DIV1_PORT1, \ + _MG_PLL_DIV1_PORT2) + +#define _MG_PLL_LF_PORT1 0x168A08 +#define _MG_PLL_LF_PORT2 0x169A08 +#define MG_PLL_LF_TDCTARGETCNT(x) ((x) << 24) +#define MG_PLL_LF_AFCCNTSEL_256 (0 << 20) +#define MG_PLL_LF_AFCCNTSEL_512 (1 << 20) +#define MG_PLL_LF_GAINCTRL(x) ((x) << 16) +#define MG_PLL_LF_INT_COEFF(x) ((x) << 8) +#define MG_PLL_LF_PROP_COEFF(x) ((x) << 0) +#define MG_PLL_LF(tc_port) _MMIO_PORT((tc_port), _MG_PLL_LF_PORT1, \ + _MG_PLL_LF_PORT2) + +#define _MG_PLL_FRAC_LOCK_PORT1 0x168A0C +#define _MG_PLL_FRAC_LOCK_PORT2 0x169A0C +#define MG_PLL_FRAC_LOCK_TRUELOCK_CRIT_32 (1 << 18) +#define MG_PLL_FRAC_LOCK_EARLYLOCK_CRIT_32 (1 << 16) +#define MG_PLL_FRAC_LOCK_LOCKTHRESH(x) ((x) << 11) +#define MG_PLL_FRAC_LOCK_DCODITHEREN (1 << 10) +#define MG_PLL_FRAC_LOCK_FEEDFWRDCAL_EN (1 << 8) +#define MG_PLL_FRAC_LOCK_FEEDFWRDGAIN(x) ((x) << 0) +#define MG_PLL_FRAC_LOCK(tc_port) _MMIO_PORT((tc_port), \ + _MG_PLL_FRAC_LOCK_PORT1, \ + _MG_PLL_FRAC_LOCK_PORT2) + +#define _MG_PLL_SSC_PORT1 0x168A10 +#define _MG_PLL_SSC_PORT2 0x169A10 +#define MG_PLL_SSC_EN (1 << 28) +#define MG_PLL_SSC_TYPE(x) ((x) << 26) +#define MG_PLL_SSC_STEPLENGTH(x) ((x) << 16) +#define MG_PLL_SSC_STEPNUM(x) ((x) << 10) +#define MG_PLL_SSC_FLLEN (1 << 9) +#define MG_PLL_SSC_STEPSIZE(x) ((x) << 0) +#define MG_PLL_SSC(tc_port) _MMIO_PORT((tc_port), _MG_PLL_SSC_PORT1, \ + _MG_PLL_SSC_PORT2) + +#define _MG_PLL_BIAS_PORT1 0x168A14 +#define _MG_PLL_BIAS_PORT2 0x169A14 +#define MG_PLL_BIAS_BIAS_GB_SEL(x) ((x) << 30) +#define MG_PLL_BIAS_BIAS_GB_SEL_MASK (0x3 << 30) +#define MG_PLL_BIAS_INIT_DCOAMP(x) ((x) << 24) +#define MG_PLL_BIAS_INIT_DCOAMP_MASK (0x3f << 24) +#define MG_PLL_BIAS_BIAS_BONUS(x) ((x) << 16) +#define MG_PLL_BIAS_BIAS_BONUS_MASK (0xff << 16) +#define MG_PLL_BIAS_BIASCAL_EN (1 << 15) +#define MG_PLL_BIAS_CTRIM(x) ((x) << 8) +#define MG_PLL_BIAS_CTRIM_MASK (0x1f << 8) +#define MG_PLL_BIAS_VREF_RDAC(x) ((x) << 5) +#define MG_PLL_BIAS_VREF_RDAC_MASK (0x7 << 5) +#define MG_PLL_BIAS_IREFTRIM(x) ((x) << 0) +#define MG_PLL_BIAS_IREFTRIM_MASK (0x1f << 0) +#define MG_PLL_BIAS(tc_port) _MMIO_PORT((tc_port), _MG_PLL_BIAS_PORT1, \ + _MG_PLL_BIAS_PORT2) + +#define _MG_PLL_TDC_COLDST_BIAS_PORT1 0x168A18 +#define _MG_PLL_TDC_COLDST_BIAS_PORT2 0x169A18 +#define MG_PLL_TDC_COLDST_IREFINT_EN (1 << 27) +#define MG_PLL_TDC_COLDST_REFBIAS_START_PULSE_W(x) ((x) << 17) +#define MG_PLL_TDC_COLDST_COLDSTART (1 << 16) +#define MG_PLL_TDC_TDCOVCCORR_EN (1 << 2) +#define MG_PLL_TDC_TDCSEL(x) ((x) << 0) +#define MG_PLL_TDC_COLDST_BIAS(tc_port) _MMIO_PORT((tc_port), \ + _MG_PLL_TDC_COLDST_BIAS_PORT1, \ + _MG_PLL_TDC_COLDST_BIAS_PORT2) + +#endif /* __INTEL_MG_PHY_REGS__ */ diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index 8cecd41ed003..351709725cd0 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -9,8 +9,8 @@ #include "intel_display_power_map.h" #include "intel_display_types.h" #include "intel_dp_mst.h" +#include "intel_mg_phy_regs.h" #include "intel_tc.h" -#include "intel_tc_phy_regs.h" static const char *tc_port_mode_name(enum tc_port_mode mode) { diff --git a/drivers/gpu/drm/i915/display/intel_tc_phy_regs.h b/drivers/gpu/drm/i915/display/intel_tc_phy_regs.h deleted file mode 100644 index 5a545086f959..000000000000 --- a/drivers/gpu/drm/i915/display/intel_tc_phy_regs.h +++ /dev/null @@ -1,280 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * Copyright © 2022 Intel Corporation - */ - -#ifndef __INTEL_TC_PHY_REGS__ -#define __INTEL_TC_PHY_REGS__ - -#include "i915_reg_defs.h" - -#define MG_PHY_PORT_LN(ln, tc_port, ln0p1, ln0p2, ln1p1) \ - _MMIO(_PORT(tc_port, ln0p1, ln0p2) + (ln) * ((ln1p1) - (ln0p1))) - -#define MG_TX_LINK_PARAMS_TX1LN0_PORT1 0x16812C -#define MG_TX_LINK_PARAMS_TX1LN1_PORT1 0x16852C -#define MG_TX_LINK_PARAMS_TX1LN0_PORT2 0x16912C -#define MG_TX_LINK_PARAMS_TX1LN1_PORT2 0x16952C -#define MG_TX1_LINK_PARAMS(ln, tc_port) \ - MG_PHY_PORT_LN(ln, tc_port, MG_TX_LINK_PARAMS_TX1LN0_PORT1, \ - MG_TX_LINK_PARAMS_TX1LN0_PORT2, \ - MG_TX_LINK_PARAMS_TX1LN1_PORT1) - -#define MG_TX_LINK_PARAMS_TX2LN0_PORT1 0x1680AC -#define MG_TX_LINK_PARAMS_TX2LN1_PORT1 0x1684AC -#define MG_TX_LINK_PARAMS_TX2LN0_PORT2 0x1690AC -#define MG_TX_LINK_PARAMS_TX2LN1_PORT2 0x1694AC -#define MG_TX2_LINK_PARAMS(ln, tc_port) \ - MG_PHY_PORT_LN(ln, tc_port, MG_TX_LINK_PARAMS_TX2LN0_PORT1, \ - MG_TX_LINK_PARAMS_TX2LN0_PORT2, \ - MG_TX_LINK_PARAMS_TX2LN1_PORT1) -#define CRI_USE_FS32 (1 << 5) - -#define MG_TX_PISO_READLOAD_TX1LN0_PORT1 0x16814C -#define MG_TX_PISO_READLOAD_TX1LN1_PORT1 0x16854C -#define MG_TX_PISO_READLOAD_TX1LN0_PORT2 0x16914C -#define MG_TX_PISO_READLOAD_TX1LN1_PORT2 0x16954C -#define MG_TX1_PISO_READLOAD(ln, tc_port) \ - MG_PHY_PORT_LN(ln, tc_port, MG_TX_PISO_READLOAD_TX1LN0_PORT1, \ - MG_TX_PISO_READLOAD_TX1LN0_PORT2, \ - MG_TX_PISO_READLOAD_TX1LN1_PORT1) - -#define MG_TX_PISO_READLOAD_TX2LN0_PORT1 0x1680CC -#define MG_TX_PISO_READLOAD_TX2LN1_PORT1 0x1684CC -#define MG_TX_PISO_READLOAD_TX2LN0_PORT2 0x1690CC -#define MG_TX_PISO_READLOAD_TX2LN1_PORT2 0x1694CC -#define MG_TX2_PISO_READLOAD(ln, tc_port) \ - MG_PHY_PORT_LN(ln, tc_port, MG_TX_PISO_READLOAD_TX2LN0_PORT1, \ - MG_TX_PISO_READLOAD_TX2LN0_PORT2, \ - MG_TX_PISO_READLOAD_TX2LN1_PORT1) -#define CRI_CALCINIT (1 << 1) - -#define MG_TX_SWINGCTRL_TX1LN0_PORT1 0x168148 -#define MG_TX_SWINGCTRL_TX1LN1_PORT1 0x168548 -#define MG_TX_SWINGCTRL_TX1LN0_PORT2 0x169148 -#define MG_TX_SWINGCTRL_TX1LN1_PORT2 0x169548 -#define MG_TX1_SWINGCTRL(ln, tc_port) \ - MG_PHY_PORT_LN(ln, tc_port, MG_TX_SWINGCTRL_TX1LN0_PORT1, \ - MG_TX_SWINGCTRL_TX1LN0_PORT2, \ - MG_TX_SWINGCTRL_TX1LN1_PORT1) - -#define MG_TX_SWINGCTRL_TX2LN0_PORT1 0x1680C8 -#define MG_TX_SWINGCTRL_TX2LN1_PORT1 0x1684C8 -#define MG_TX_SWINGCTRL_TX2LN0_PORT2 0x1690C8 -#define MG_TX_SWINGCTRL_TX2LN1_PORT2 0x1694C8 -#define MG_TX2_SWINGCTRL(ln, tc_port) \ - MG_PHY_PORT_LN(ln, tc_port, MG_TX_SWINGCTRL_TX2LN0_PORT1, \ - MG_TX_SWINGCTRL_TX2LN0_PORT2, \ - MG_TX_SWINGCTRL_TX2LN1_PORT1) -#define CRI_TXDEEMPH_OVERRIDE_17_12(x) ((x) << 0) -#define CRI_TXDEEMPH_OVERRIDE_17_12_MASK (0x3F << 0) - -#define MG_TX_DRVCTRL_TX1LN0_TXPORT1 0x168144 -#define MG_TX_DRVCTRL_TX1LN1_TXPORT1 0x168544 -#define MG_TX_DRVCTRL_TX1LN0_TXPORT2 0x169144 -#define MG_TX_DRVCTRL_TX1LN1_TXPORT2 0x169544 -#define MG_TX_DRVCTRL_TX1LN0_TXPORT3 0x16A144 -#define MG_TX_DRVCTRL_TX1LN1_TXPORT3 0x16A544 -#define MG_TX_DRVCTRL_TX1LN0_TXPORT4 0x16B144 -#define MG_TX_DRVCTRL_TX1LN1_TXPORT4 0x16B544 -#define MG_TX1_DRVCTRL(ln, tc_port) \ - MG_PHY_PORT_LN(ln, tc_port, MG_TX_DRVCTRL_TX1LN0_TXPORT1, \ - MG_TX_DRVCTRL_TX1LN0_TXPORT2, \ - MG_TX_DRVCTRL_TX1LN1_TXPORT1) - -#define MG_TX_DRVCTRL_TX2LN0_PORT1 0x1680C4 -#define MG_TX_DRVCTRL_TX2LN1_PORT1 0x1684C4 -#define MG_TX_DRVCTRL_TX2LN0_PORT2 0x1690C4 -#define MG_TX_DRVCTRL_TX2LN1_PORT2 0x1694C4 -#define MG_TX2_DRVCTRL(ln, tc_port) \ - MG_PHY_PORT_LN(ln, tc_port, MG_TX_DRVCTRL_TX2LN0_PORT1, \ - MG_TX_DRVCTRL_TX2LN0_PORT2, \ - MG_TX_DRVCTRL_TX2LN1_PORT1) -#define CRI_TXDEEMPH_OVERRIDE_11_6(x) ((x) << 24) -#define CRI_TXDEEMPH_OVERRIDE_11_6_MASK (0x3F << 24) -#define CRI_TXDEEMPH_OVERRIDE_EN (1 << 22) -#define CRI_TXDEEMPH_OVERRIDE_5_0(x) ((x) << 16) -#define CRI_TXDEEMPH_OVERRIDE_5_0_MASK (0x3F << 16) -#define CRI_LOADGEN_SEL(x) ((x) << 12) -#define CRI_LOADGEN_SEL_MASK (0x3 << 12) - -#define MG_CLKHUB_LN0_PORT1 0x16839C -#define MG_CLKHUB_LN1_PORT1 0x16879C -#define MG_CLKHUB_LN0_PORT2 0x16939C -#define MG_CLKHUB_LN1_PORT2 0x16979C -#define MG_CLKHUB(ln, tc_port) \ - MG_PHY_PORT_LN(ln, tc_port, MG_CLKHUB_LN0_PORT1, \ - MG_CLKHUB_LN0_PORT2, \ - MG_CLKHUB_LN1_PORT1) -#define CFG_LOW_RATE_LKREN_EN (1 << 11) - -#define MG_TX_DCC_TX1LN0_PORT1 0x168110 -#define MG_TX_DCC_TX1LN1_PORT1 0x168510 -#define MG_TX_DCC_TX1LN0_PORT2 0x169110 -#define MG_TX_DCC_TX1LN1_PORT2 0x169510 -#define MG_TX1_DCC(ln, tc_port) \ - MG_PHY_PORT_LN(ln, tc_port, MG_TX_DCC_TX1LN0_PORT1, \ - MG_TX_DCC_TX1LN0_PORT2, \ - MG_TX_DCC_TX1LN1_PORT1) -#define MG_TX_DCC_TX2LN0_PORT1 0x168090 -#define MG_TX_DCC_TX2LN1_PORT1 0x168490 -#define MG_TX_DCC_TX2LN0_PORT2 0x169090 -#define MG_TX_DCC_TX2LN1_PORT2 0x169490 -#define MG_TX2_DCC(ln, tc_port) \ - MG_PHY_PORT_LN(ln, tc_port, MG_TX_DCC_TX2LN0_PORT1, \ - MG_TX_DCC_TX2LN0_PORT2, \ - MG_TX_DCC_TX2LN1_PORT1) -#define CFG_AMI_CK_DIV_OVERRIDE_VAL(x) ((x) << 25) -#define CFG_AMI_CK_DIV_OVERRIDE_VAL_MASK (0x3 << 25) -#define CFG_AMI_CK_DIV_OVERRIDE_EN (1 << 24) - -#define MG_DP_MODE_LN0_ACU_PORT1 0x1683A0 -#define MG_DP_MODE_LN1_ACU_PORT1 0x1687A0 -#define MG_DP_MODE_LN0_ACU_PORT2 0x1693A0 -#define MG_DP_MODE_LN1_ACU_PORT2 0x1697A0 -#define MG_DP_MODE(ln, tc_port) \ - MG_PHY_PORT_LN(ln, tc_port, MG_DP_MODE_LN0_ACU_PORT1, \ - MG_DP_MODE_LN0_ACU_PORT2, \ - MG_DP_MODE_LN1_ACU_PORT1) -#define MG_DP_MODE_CFG_DP_X2_MODE (1 << 7) -#define MG_DP_MODE_CFG_DP_X1_MODE (1 << 6) - -#define FIA1_BASE 0x163000 -#define FIA2_BASE 0x16E000 -#define FIA3_BASE 0x16F000 -#define _FIA(fia) _PICK((fia), FIA1_BASE, FIA2_BASE, FIA3_BASE) -#define _MMIO_FIA(fia, off) _MMIO(_FIA(fia) + (off)) - -/* ICL PHY DFLEX registers */ -#define PORT_TX_DFLEXDPMLE1(fia) _MMIO_FIA((fia), 0x008C0) -#define DFLEXDPMLE1_DPMLETC_MASK(idx) (0xf << (4 * (idx))) -#define DFLEXDPMLE1_DPMLETC_ML0(idx) (1 << (4 * (idx))) -#define DFLEXDPMLE1_DPMLETC_ML1_0(idx) (3 << (4 * (idx))) -#define DFLEXDPMLE1_DPMLETC_ML3(idx) (8 << (4 * (idx))) -#define DFLEXDPMLE1_DPMLETC_ML3_2(idx) (12 << (4 * (idx))) -#define DFLEXDPMLE1_DPMLETC_ML3_0(idx) (15 << (4 * (idx))) - -#define _MG_REFCLKIN_CTL_PORT1 0x16892C -#define _MG_REFCLKIN_CTL_PORT2 0x16992C -#define MG_REFCLKIN_CTL_OD_2_MUX(x) ((x) << 8) -#define MG_REFCLKIN_CTL_OD_2_MUX_MASK (0x7 << 8) -#define MG_REFCLKIN_CTL(tc_port) _MMIO_PORT((tc_port), \ - _MG_REFCLKIN_CTL_PORT1, \ - _MG_REFCLKIN_CTL_PORT2) - -#define _MG_CLKTOP2_CORECLKCTL1_PORT1 0x1688D8 -#define _MG_CLKTOP2_CORECLKCTL1_PORT2 0x1698D8 -#define MG_CLKTOP2_CORECLKCTL1_B_DIVRATIO(x) ((x) << 16) -#define MG_CLKTOP2_CORECLKCTL1_B_DIVRATIO_MASK (0xff << 16) -#define MG_CLKTOP2_CORECLKCTL1_A_DIVRATIO(x) ((x) << 8) -#define MG_CLKTOP2_CORECLKCTL1_A_DIVRATIO_MASK (0xff << 8) -#define MG_CLKTOP2_CORECLKCTL1(tc_port) _MMIO_PORT((tc_port), \ - _MG_CLKTOP2_CORECLKCTL1_PORT1, \ - _MG_CLKTOP2_CORECLKCTL1_PORT2) - -#define _MG_CLKTOP2_HSCLKCTL_PORT1 0x1688D4 -#define _MG_CLKTOP2_HSCLKCTL_PORT2 0x1698D4 -#define MG_CLKTOP2_HSCLKCTL_CORE_INPUTSEL(x) ((x) << 16) -#define MG_CLKTOP2_HSCLKCTL_CORE_INPUTSEL_MASK (0x1 << 16) -#define MG_CLKTOP2_HSCLKCTL_TLINEDRV_CLKSEL(x) ((x) << 14) -#define MG_CLKTOP2_HSCLKCTL_TLINEDRV_CLKSEL_MASK (0x3 << 14) -#define MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_MASK (0x3 << 12) -#define MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_2 (0 << 12) -#define MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_3 (1 << 12) -#define MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_5 (2 << 12) -#define MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_7 (3 << 12) -#define MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO(x) ((x) << 8) -#define MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_SHIFT 8 -#define MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_MASK (0xf << 8) -#define MG_CLKTOP2_HSCLKCTL(tc_port) _MMIO_PORT((tc_port), \ - _MG_CLKTOP2_HSCLKCTL_PORT1, \ - _MG_CLKTOP2_HSCLKCTL_PORT2) - -#define _MG_PLL_DIV0_PORT1 0x168A00 -#define _MG_PLL_DIV0_PORT2 0x169A00 -#define MG_PLL_DIV0_FRACNEN_H (1 << 30) -#define MG_PLL_DIV0_FBDIV_FRAC_MASK (0x3fffff << 8) -#define MG_PLL_DIV0_FBDIV_FRAC_SHIFT 8 -#define MG_PLL_DIV0_FBDIV_FRAC(x) ((x) << 8) -#define MG_PLL_DIV0_FBDIV_INT_MASK (0xff << 0) -#define MG_PLL_DIV0_FBDIV_INT(x) ((x) << 0) -#define MG_PLL_DIV0(tc_port) _MMIO_PORT((tc_port), _MG_PLL_DIV0_PORT1, \ - _MG_PLL_DIV0_PORT2) - -#define _MG_PLL_DIV1_PORT1 0x168A04 -#define _MG_PLL_DIV1_PORT2 0x169A04 -#define MG_PLL_DIV1_IREF_NDIVRATIO(x) ((x) << 16) -#define MG_PLL_DIV1_DITHER_DIV_1 (0 << 12) -#define MG_PLL_DIV1_DITHER_DIV_2 (1 << 12) -#define MG_PLL_DIV1_DITHER_DIV_4 (2 << 12) -#define MG_PLL_DIV1_DITHER_DIV_8 (3 << 12) -#define MG_PLL_DIV1_NDIVRATIO(x) ((x) << 4) -#define MG_PLL_DIV1_FBPREDIV_MASK (0xf << 0) -#define MG_PLL_DIV1_FBPREDIV(x) ((x) << 0) -#define MG_PLL_DIV1(tc_port) _MMIO_PORT((tc_port), _MG_PLL_DIV1_PORT1, \ - _MG_PLL_DIV1_PORT2) - -#define _MG_PLL_LF_PORT1 0x168A08 -#define _MG_PLL_LF_PORT2 0x169A08 -#define MG_PLL_LF_TDCTARGETCNT(x) ((x) << 24) -#define MG_PLL_LF_AFCCNTSEL_256 (0 << 20) -#define MG_PLL_LF_AFCCNTSEL_512 (1 << 20) -#define MG_PLL_LF_GAINCTRL(x) ((x) << 16) -#define MG_PLL_LF_INT_COEFF(x) ((x) << 8) -#define MG_PLL_LF_PROP_COEFF(x) ((x) << 0) -#define MG_PLL_LF(tc_port) _MMIO_PORT((tc_port), _MG_PLL_LF_PORT1, \ - _MG_PLL_LF_PORT2) - -#define _MG_PLL_FRAC_LOCK_PORT1 0x168A0C -#define _MG_PLL_FRAC_LOCK_PORT2 0x169A0C -#define MG_PLL_FRAC_LOCK_TRUELOCK_CRIT_32 (1 << 18) -#define MG_PLL_FRAC_LOCK_EARLYLOCK_CRIT_32 (1 << 16) -#define MG_PLL_FRAC_LOCK_LOCKTHRESH(x) ((x) << 11) -#define MG_PLL_FRAC_LOCK_DCODITHEREN (1 << 10) -#define MG_PLL_FRAC_LOCK_FEEDFWRDCAL_EN (1 << 8) -#define MG_PLL_FRAC_LOCK_FEEDFWRDGAIN(x) ((x) << 0) -#define MG_PLL_FRAC_LOCK(tc_port) _MMIO_PORT((tc_port), \ - _MG_PLL_FRAC_LOCK_PORT1, \ - _MG_PLL_FRAC_LOCK_PORT2) - -#define _MG_PLL_SSC_PORT1 0x168A10 -#define _MG_PLL_SSC_PORT2 0x169A10 -#define MG_PLL_SSC_EN (1 << 28) -#define MG_PLL_SSC_TYPE(x) ((x) << 26) -#define MG_PLL_SSC_STEPLENGTH(x) ((x) << 16) -#define MG_PLL_SSC_STEPNUM(x) ((x) << 10) -#define MG_PLL_SSC_FLLEN (1 << 9) -#define MG_PLL_SSC_STEPSIZE(x) ((x) << 0) -#define MG_PLL_SSC(tc_port) _MMIO_PORT((tc_port), _MG_PLL_SSC_PORT1, \ - _MG_PLL_SSC_PORT2) - -#define _MG_PLL_BIAS_PORT1 0x168A14 -#define _MG_PLL_BIAS_PORT2 0x169A14 -#define MG_PLL_BIAS_BIAS_GB_SEL(x) ((x) << 30) -#define MG_PLL_BIAS_BIAS_GB_SEL_MASK (0x3 << 30) -#define MG_PLL_BIAS_INIT_DCOAMP(x) ((x) << 24) -#define MG_PLL_BIAS_INIT_DCOAMP_MASK (0x3f << 24) -#define MG_PLL_BIAS_BIAS_BONUS(x) ((x) << 16) -#define MG_PLL_BIAS_BIAS_BONUS_MASK (0xff << 16) -#define MG_PLL_BIAS_BIASCAL_EN (1 << 15) -#define MG_PLL_BIAS_CTRIM(x) ((x) << 8) -#define MG_PLL_BIAS_CTRIM_MASK (0x1f << 8) -#define MG_PLL_BIAS_VREF_RDAC(x) ((x) << 5) -#define MG_PLL_BIAS_VREF_RDAC_MASK (0x7 << 5) -#define MG_PLL_BIAS_IREFTRIM(x) ((x) << 0) -#define MG_PLL_BIAS_IREFTRIM_MASK (0x1f << 0) -#define MG_PLL_BIAS(tc_port) _MMIO_PORT((tc_port), _MG_PLL_BIAS_PORT1, \ - _MG_PLL_BIAS_PORT2) - -#define _MG_PLL_TDC_COLDST_BIAS_PORT1 0x168A18 -#define _MG_PLL_TDC_COLDST_BIAS_PORT2 0x169A18 -#define MG_PLL_TDC_COLDST_IREFINT_EN (1 << 27) -#define MG_PLL_TDC_COLDST_REFBIAS_START_PULSE_W(x) ((x) << 17) -#define MG_PLL_TDC_COLDST_COLDSTART (1 << 16) -#define MG_PLL_TDC_TDCOVCCORR_EN (1 << 2) -#define MG_PLL_TDC_TDCSEL(x) ((x) << 0) -#define MG_PLL_TDC_COLDST_BIAS(tc_port) _MMIO_PORT((tc_port), \ - _MG_PLL_TDC_COLDST_BIAS_PORT1, \ - _MG_PLL_TDC_COLDST_BIAS_PORT2) - -#endif /* __INTEL_TC_PHY_REGS__ */ -- cgit From d69813c7640fdfd03360a300d24b08149bdc4c97 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 25 Oct 2022 14:44:56 +0300 Subject: drm/i915/tgl+: Move DKL PHY register definitions to intel_dkl_phy_regs.h Move the TypeC DKL PHY register definitions to intel_dkl_phy_regs.h. No functional changes. v2: - Move the definitions to a new intel_dkl_phy_regs.h file. (Jani). v3: - Rebase on latest patchset version. Cc: Jani Nikula Acked-by: Jani Nikula Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20221025114457.2191004-2-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 1 + .../drm/i915/display/intel_display_power_well.c | 1 + drivers/gpu/drm/i915/display/intel_dkl_phy.c | 1 + drivers/gpu/drm/i915/display/intel_dkl_phy_regs.h | 193 +++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_dpll_mgr.c | 1 + drivers/gpu/drm/i915/display/intel_tc.c | 1 + drivers/gpu/drm/i915/i915_reg.h | 179 ------------------- 7 files changed, 198 insertions(+), 179 deletions(-) create mode 100644 drivers/gpu/drm/i915/display/intel_dkl_phy_regs.h diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 37272c6e4269..54142ca3e694 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -44,6 +44,7 @@ #include "intel_display_power.h" #include "intel_display_types.h" #include "intel_dkl_phy.h" +#include "intel_dkl_phy_regs.h" #include "intel_dp.h" #include "intel_dp_link_training.h" #include "intel_dp_mst.h" diff --git a/drivers/gpu/drm/i915/display/intel_display_power_well.c b/drivers/gpu/drm/i915/display/intel_display_power_well.c index 1d18eee56253..86974c515206 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power_well.c +++ b/drivers/gpu/drm/i915/display/intel_display_power_well.c @@ -13,6 +13,7 @@ #include "intel_display_power_well.h" #include "intel_display_types.h" #include "intel_dkl_phy.h" +#include "intel_dkl_phy_regs.h" #include "intel_dmc.h" #include "intel_dpio_phy.h" #include "intel_dpll.h" diff --git a/drivers/gpu/drm/i915/display/intel_dkl_phy.c b/drivers/gpu/drm/i915/display/intel_dkl_phy.c index 710b030c7ed5..01781293ffdc 100644 --- a/drivers/gpu/drm/i915/display/intel_dkl_phy.c +++ b/drivers/gpu/drm/i915/display/intel_dkl_phy.c @@ -9,6 +9,7 @@ #include "intel_de.h" #include "intel_display.h" #include "intel_dkl_phy.h" +#include "intel_dkl_phy_regs.h" static void dkl_phy_set_hip_idx(struct drm_i915_private *i915, i915_reg_t reg, int idx) diff --git a/drivers/gpu/drm/i915/display/intel_dkl_phy_regs.h b/drivers/gpu/drm/i915/display/intel_dkl_phy_regs.h new file mode 100644 index 000000000000..7d0f3aab7f5c --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_dkl_phy_regs.h @@ -0,0 +1,193 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2022 Intel Corporation + */ + +#ifndef __INTEL_DKL_PHY_REGS__ +#define __INTEL_DKL_PHY_REGS__ + +#define _DKL_PHY1_BASE 0x168000 +#define _DKL_PHY2_BASE 0x169000 +#define _DKL_PHY3_BASE 0x16A000 +#define _DKL_PHY4_BASE 0x16B000 +#define _DKL_PHY5_BASE 0x16C000 +#define _DKL_PHY6_BASE 0x16D000 + +#define DKL_REG_TC_PORT(__reg) \ + (TC_PORT_1 + ((__reg).reg - _DKL_PHY1_BASE) / (_DKL_PHY2_BASE - _DKL_PHY1_BASE)) + +/* DEKEL PHY MMIO Address = Phy base + (internal address & ~index_mask) */ +#define _DKL_PCS_DW5 0x14 +#define DKL_PCS_DW5(tc_port) _MMIO(_PORT(tc_port, \ + _DKL_PHY1_BASE, \ + _DKL_PHY2_BASE) + \ + _DKL_PCS_DW5) +#define DKL_PCS_DW5_CORE_SOFTRESET REG_BIT(11) + +#define _DKL_PLL_DIV0 0x200 +#define DKL_PLL_DIV0(tc_port) _MMIO(_PORT(tc_port, \ + _DKL_PHY1_BASE, \ + _DKL_PHY2_BASE) + \ + _DKL_PLL_DIV0) +#define DKL_PLL_DIV0_AFC_STARTUP_MASK REG_GENMASK(27, 25) +#define DKL_PLL_DIV0_AFC_STARTUP(val) REG_FIELD_PREP(DKL_PLL_DIV0_AFC_STARTUP_MASK, (val)) +#define DKL_PLL_DIV0_INTEG_COEFF(x) ((x) << 16) +#define DKL_PLL_DIV0_INTEG_COEFF_MASK (0x1F << 16) +#define DKL_PLL_DIV0_PROP_COEFF(x) ((x) << 12) +#define DKL_PLL_DIV0_PROP_COEFF_MASK (0xF << 12) +#define DKL_PLL_DIV0_FBPREDIV_SHIFT (8) +#define DKL_PLL_DIV0_FBPREDIV(x) ((x) << DKL_PLL_DIV0_FBPREDIV_SHIFT) +#define DKL_PLL_DIV0_FBPREDIV_MASK (0xF << DKL_PLL_DIV0_FBPREDIV_SHIFT) +#define DKL_PLL_DIV0_FBDIV_INT(x) ((x) << 0) +#define DKL_PLL_DIV0_FBDIV_INT_MASK (0xFF << 0) +#define DKL_PLL_DIV0_MASK (DKL_PLL_DIV0_INTEG_COEFF_MASK | \ + DKL_PLL_DIV0_PROP_COEFF_MASK | \ + DKL_PLL_DIV0_FBPREDIV_MASK | \ + DKL_PLL_DIV0_FBDIV_INT_MASK) + +#define _DKL_PLL_DIV1 0x204 +#define DKL_PLL_DIV1(tc_port) _MMIO(_PORT(tc_port, \ + _DKL_PHY1_BASE, \ + _DKL_PHY2_BASE) + \ + _DKL_PLL_DIV1) +#define DKL_PLL_DIV1_IREF_TRIM(x) ((x) << 16) +#define DKL_PLL_DIV1_IREF_TRIM_MASK (0x1F << 16) +#define DKL_PLL_DIV1_TDC_TARGET_CNT(x) ((x) << 0) +#define DKL_PLL_DIV1_TDC_TARGET_CNT_MASK (0xFF << 0) + +#define _DKL_PLL_SSC 0x210 +#define DKL_PLL_SSC(tc_port) _MMIO(_PORT(tc_port, \ + _DKL_PHY1_BASE, \ + _DKL_PHY2_BASE) + \ + _DKL_PLL_SSC) +#define DKL_PLL_SSC_IREF_NDIV_RATIO(x) ((x) << 29) +#define DKL_PLL_SSC_IREF_NDIV_RATIO_MASK (0x7 << 29) +#define DKL_PLL_SSC_STEP_LEN(x) ((x) << 16) +#define DKL_PLL_SSC_STEP_LEN_MASK (0xFF << 16) +#define DKL_PLL_SSC_STEP_NUM(x) ((x) << 11) +#define DKL_PLL_SSC_STEP_NUM_MASK (0x7 << 11) +#define DKL_PLL_SSC_EN (1 << 9) + +#define _DKL_PLL_BIAS 0x214 +#define DKL_PLL_BIAS(tc_port) _MMIO(_PORT(tc_port, \ + _DKL_PHY1_BASE, \ + _DKL_PHY2_BASE) + \ + _DKL_PLL_BIAS) +#define DKL_PLL_BIAS_FRAC_EN_H (1 << 30) +#define DKL_PLL_BIAS_FBDIV_SHIFT (8) +#define DKL_PLL_BIAS_FBDIV_FRAC(x) ((x) << DKL_PLL_BIAS_FBDIV_SHIFT) +#define DKL_PLL_BIAS_FBDIV_FRAC_MASK (0x3FFFFF << DKL_PLL_BIAS_FBDIV_SHIFT) + +#define _DKL_PLL_TDC_COLDST_BIAS 0x218 +#define DKL_PLL_TDC_COLDST_BIAS(tc_port) _MMIO(_PORT(tc_port, \ + _DKL_PHY1_BASE, \ + _DKL_PHY2_BASE) + \ + _DKL_PLL_TDC_COLDST_BIAS) +#define DKL_PLL_TDC_SSC_STEP_SIZE(x) ((x) << 8) +#define DKL_PLL_TDC_SSC_STEP_SIZE_MASK (0xFF << 8) +#define DKL_PLL_TDC_FEED_FWD_GAIN(x) ((x) << 0) +#define DKL_PLL_TDC_FEED_FWD_GAIN_MASK (0xFF << 0) + +#define _DKL_REFCLKIN_CTL 0x12C +#define DKL_REFCLKIN_CTL(tc_port) _MMIO(_PORT(tc_port, \ + _DKL_PHY1_BASE, \ + _DKL_PHY2_BASE) + \ + _DKL_REFCLKIN_CTL) +/* Bits are the same as MG_REFCLKIN_CTL */ + +#define _DKL_CLKTOP2_HSCLKCTL 0xD4 +#define DKL_CLKTOP2_HSCLKCTL(tc_port) _MMIO(_PORT(tc_port, \ + _DKL_PHY1_BASE, \ + _DKL_PHY2_BASE) + \ + _DKL_CLKTOP2_HSCLKCTL) +/* Bits are the same as MG_CLKTOP2_HSCLKCTL */ + +#define _DKL_CLKTOP2_CORECLKCTL1 0xD8 +#define DKL_CLKTOP2_CORECLKCTL1(tc_port) _MMIO(_PORT(tc_port, \ + _DKL_PHY1_BASE, \ + _DKL_PHY2_BASE) + \ + _DKL_CLKTOP2_CORECLKCTL1) +/* Bits are the same as MG_CLKTOP2_CORECLKCTL1 */ + +#define _DKL_TX_DPCNTL0 0x2C0 +#define DKL_TX_DPCNTL0(tc_port) _MMIO(_PORT(tc_port, \ + _DKL_PHY1_BASE, \ + _DKL_PHY2_BASE) + \ + _DKL_TX_DPCNTL0) +#define DKL_TX_PRESHOOT_COEFF(x) ((x) << 13) +#define DKL_TX_PRESHOOT_COEFF_MASK (0x1f << 13) +#define DKL_TX_DE_EMPHASIS_COEFF(x) ((x) << 8) +#define DKL_TX_DE_EMPAHSIS_COEFF_MASK (0x1f << 8) +#define DKL_TX_VSWING_CONTROL(x) ((x) << 0) +#define DKL_TX_VSWING_CONTROL_MASK (0x7 << 0) + +#define _DKL_TX_DPCNTL1 0x2C4 +#define DKL_TX_DPCNTL1(tc_port) _MMIO(_PORT(tc_port, \ + _DKL_PHY1_BASE, \ + _DKL_PHY2_BASE) + \ + _DKL_TX_DPCNTL1) +/* Bits are the same as DKL_TX_DPCNTRL0 */ + +#define _DKL_TX_DPCNTL2 0x2C8 +#define DKL_TX_DPCNTL2(tc_port) _MMIO(_PORT(tc_port, \ + _DKL_PHY1_BASE, \ + _DKL_PHY2_BASE) + \ + _DKL_TX_DPCNTL2) +#define DKL_TX_DP20BITMODE REG_BIT(2) +#define DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX1_MASK REG_GENMASK(4, 3) +#define DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX1(val) REG_FIELD_PREP(DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX1_MASK, (val)) +#define DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2_MASK REG_GENMASK(6, 5) +#define DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2(val) REG_FIELD_PREP(DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2_MASK, (val)) + +#define _DKL_TX_FW_CALIB 0x2F8 +#define DKL_TX_FW_CALIB(tc_port) _MMIO(_PORT(tc_port, \ + _DKL_PHY1_BASE, \ + _DKL_PHY2_BASE) + \ + _DKL_TX_FW_CALIB) +#define DKL_TX_CFG_DISABLE_WAIT_INIT (1 << 7) + +#define _DKL_TX_PMD_LANE_SUS 0xD00 +#define DKL_TX_PMD_LANE_SUS(tc_port) _MMIO(_PORT(tc_port, \ + _DKL_PHY1_BASE, \ + _DKL_PHY2_BASE) + \ + _DKL_TX_PMD_LANE_SUS) + +#define _DKL_TX_DW17 0xDC4 +#define DKL_TX_DW17(tc_port) _MMIO(_PORT(tc_port, \ + _DKL_PHY1_BASE, \ + _DKL_PHY2_BASE) + \ + _DKL_TX_DW17) + +#define _DKL_TX_DW18 0xDC8 +#define DKL_TX_DW18(tc_port) _MMIO(_PORT(tc_port, \ + _DKL_PHY1_BASE, \ + _DKL_PHY2_BASE) + \ + _DKL_TX_DW18) + +#define _DKL_DP_MODE 0xA0 +#define DKL_DP_MODE(tc_port) _MMIO(_PORT(tc_port, \ + _DKL_PHY1_BASE, \ + _DKL_PHY2_BASE) + \ + _DKL_DP_MODE) + +#define _DKL_CMN_UC_DW27 0x36C +#define DKL_CMN_UC_DW_27(tc_port) _MMIO(_PORT(tc_port, \ + _DKL_PHY1_BASE, \ + _DKL_PHY2_BASE) + \ + _DKL_CMN_UC_DW27) +#define DKL_CMN_UC_DW27_UC_HEALTH (0x1 << 15) + +/* + * Each Dekel PHY is addressed through a 4KB aperture. Each PHY has more than + * 4KB of register space, so a separate index is programmed in HIP_INDEX_REG0 + * or HIP_INDEX_REG1, based on the port number, to set the upper 2 address + * bits that point the 4KB window into the full PHY register space. + */ +#define _HIP_INDEX_REG0 0x1010A0 +#define _HIP_INDEX_REG1 0x1010A4 +#define HIP_INDEX_REG(tc_port) _MMIO((tc_port) < 4 ? _HIP_INDEX_REG0 \ + : _HIP_INDEX_REG1) +#define _HIP_INDEX_SHIFT(tc_port) (8 * ((tc_port) % 4)) +#define HIP_INDEX_VAL(tc_port, val) ((val) << _HIP_INDEX_SHIFT(tc_port)) + +#endif /* __INTEL_DKL_PHY_REGS__ */ diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c index eb4decd8c68b..bb7c8aef8952 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c @@ -26,6 +26,7 @@ #include "intel_de.h" #include "intel_display_types.h" #include "intel_dkl_phy.h" +#include "intel_dkl_phy_regs.h" #include "intel_dpio_phy.h" #include "intel_dpll.h" #include "intel_dpll_mgr.h" diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index 351709725cd0..70624b4b2d38 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -8,6 +8,7 @@ #include "intel_display.h" #include "intel_display_power_map.h" #include "intel_display_types.h" +#include "intel_dkl_phy_regs.h" #include "intel_dp_mst.h" #include "intel_mg_phy_regs.h" #include "intel_tc.h" diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 959c2bd6707c..c5e180aec344 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -7418,185 +7418,6 @@ enum skl_power_gate { _ADLS_DPLL4_CFGCR1, \ _ADLS_DPLL3_CFGCR1) -#define _DKL_PHY1_BASE 0x168000 -#define _DKL_PHY2_BASE 0x169000 -#define _DKL_PHY3_BASE 0x16A000 -#define _DKL_PHY4_BASE 0x16B000 -#define _DKL_PHY5_BASE 0x16C000 -#define _DKL_PHY6_BASE 0x16D000 - -#define DKL_REG_TC_PORT(__reg) \ - (TC_PORT_1 + ((__reg).reg - _DKL_PHY1_BASE) / (_DKL_PHY2_BASE - _DKL_PHY1_BASE)) - -/* DEKEL PHY MMIO Address = Phy base + (internal address & ~index_mask) */ -#define _DKL_PCS_DW5 0x14 -#define DKL_PCS_DW5(tc_port) _MMIO(_PORT(tc_port, _DKL_PHY1_BASE, \ - _DKL_PHY2_BASE) + \ - _DKL_PCS_DW5) -#define DKL_PCS_DW5_CORE_SOFTRESET REG_BIT(11) - -#define _DKL_PLL_DIV0 0x200 -#define DKL_PLL_DIV0_AFC_STARTUP_MASK REG_GENMASK(27, 25) -#define DKL_PLL_DIV0_AFC_STARTUP(val) REG_FIELD_PREP(DKL_PLL_DIV0_AFC_STARTUP_MASK, (val)) -#define DKL_PLL_DIV0_INTEG_COEFF(x) ((x) << 16) -#define DKL_PLL_DIV0_INTEG_COEFF_MASK (0x1F << 16) -#define DKL_PLL_DIV0_PROP_COEFF(x) ((x) << 12) -#define DKL_PLL_DIV0_PROP_COEFF_MASK (0xF << 12) -#define DKL_PLL_DIV0_FBPREDIV_SHIFT (8) -#define DKL_PLL_DIV0_FBPREDIV(x) ((x) << DKL_PLL_DIV0_FBPREDIV_SHIFT) -#define DKL_PLL_DIV0_FBPREDIV_MASK (0xF << DKL_PLL_DIV0_FBPREDIV_SHIFT) -#define DKL_PLL_DIV0_FBDIV_INT(x) ((x) << 0) -#define DKL_PLL_DIV0_FBDIV_INT_MASK (0xFF << 0) -#define DKL_PLL_DIV0_MASK (DKL_PLL_DIV0_INTEG_COEFF_MASK | \ - DKL_PLL_DIV0_PROP_COEFF_MASK | \ - DKL_PLL_DIV0_FBPREDIV_MASK | \ - DKL_PLL_DIV0_FBDIV_INT_MASK) -#define DKL_PLL_DIV0(tc_port) _MMIO(_PORT(tc_port, _DKL_PHY1_BASE, \ - _DKL_PHY2_BASE) + \ - _DKL_PLL_DIV0) - -#define _DKL_PLL_DIV1 0x204 -#define DKL_PLL_DIV1_IREF_TRIM(x) ((x) << 16) -#define DKL_PLL_DIV1_IREF_TRIM_MASK (0x1F << 16) -#define DKL_PLL_DIV1_TDC_TARGET_CNT(x) ((x) << 0) -#define DKL_PLL_DIV1_TDC_TARGET_CNT_MASK (0xFF << 0) -#define DKL_PLL_DIV1(tc_port) _MMIO(_PORT(tc_port, _DKL_PHY1_BASE, \ - _DKL_PHY2_BASE) + \ - _DKL_PLL_DIV1) - -#define _DKL_PLL_SSC 0x210 -#define DKL_PLL_SSC_IREF_NDIV_RATIO(x) ((x) << 29) -#define DKL_PLL_SSC_IREF_NDIV_RATIO_MASK (0x7 << 29) -#define DKL_PLL_SSC_STEP_LEN(x) ((x) << 16) -#define DKL_PLL_SSC_STEP_LEN_MASK (0xFF << 16) -#define DKL_PLL_SSC_STEP_NUM(x) ((x) << 11) -#define DKL_PLL_SSC_STEP_NUM_MASK (0x7 << 11) -#define DKL_PLL_SSC_EN (1 << 9) -#define DKL_PLL_SSC(tc_port) _MMIO(_PORT(tc_port, _DKL_PHY1_BASE, \ - _DKL_PHY2_BASE) + \ - _DKL_PLL_SSC) - -#define _DKL_PLL_BIAS 0x214 -#define DKL_PLL_BIAS_FRAC_EN_H (1 << 30) -#define DKL_PLL_BIAS_FBDIV_SHIFT (8) -#define DKL_PLL_BIAS_FBDIV_FRAC(x) ((x) << DKL_PLL_BIAS_FBDIV_SHIFT) -#define DKL_PLL_BIAS_FBDIV_FRAC_MASK (0x3FFFFF << DKL_PLL_BIAS_FBDIV_SHIFT) -#define DKL_PLL_BIAS(tc_port) _MMIO(_PORT(tc_port, _DKL_PHY1_BASE, \ - _DKL_PHY2_BASE) + \ - _DKL_PLL_BIAS) - -#define _DKL_PLL_TDC_COLDST_BIAS 0x218 -#define DKL_PLL_TDC_SSC_STEP_SIZE(x) ((x) << 8) -#define DKL_PLL_TDC_SSC_STEP_SIZE_MASK (0xFF << 8) -#define DKL_PLL_TDC_FEED_FWD_GAIN(x) ((x) << 0) -#define DKL_PLL_TDC_FEED_FWD_GAIN_MASK (0xFF << 0) -#define DKL_PLL_TDC_COLDST_BIAS(tc_port) _MMIO(_PORT(tc_port, \ - _DKL_PHY1_BASE, \ - _DKL_PHY2_BASE) + \ - _DKL_PLL_TDC_COLDST_BIAS) - -#define _DKL_REFCLKIN_CTL 0x12C -/* Bits are the same as MG_REFCLKIN_CTL */ -#define DKL_REFCLKIN_CTL(tc_port) _MMIO(_PORT(tc_port, \ - _DKL_PHY1_BASE, \ - _DKL_PHY2_BASE) + \ - _DKL_REFCLKIN_CTL) - -#define _DKL_CLKTOP2_HSCLKCTL 0xD4 -/* Bits are the same as MG_CLKTOP2_HSCLKCTL */ -#define DKL_CLKTOP2_HSCLKCTL(tc_port) _MMIO(_PORT(tc_port, \ - _DKL_PHY1_BASE, \ - _DKL_PHY2_BASE) + \ - _DKL_CLKTOP2_HSCLKCTL) - -#define _DKL_CLKTOP2_CORECLKCTL1 0xD8 -/* Bits are the same as MG_CLKTOP2_CORECLKCTL1 */ -#define DKL_CLKTOP2_CORECLKCTL1(tc_port) _MMIO(_PORT(tc_port, \ - _DKL_PHY1_BASE, \ - _DKL_PHY2_BASE) + \ - _DKL_CLKTOP2_CORECLKCTL1) - -#define _DKL_TX_DPCNTL0 0x2C0 -#define DKL_TX_PRESHOOT_COEFF(x) ((x) << 13) -#define DKL_TX_PRESHOOT_COEFF_MASK (0x1f << 13) -#define DKL_TX_DE_EMPHASIS_COEFF(x) ((x) << 8) -#define DKL_TX_DE_EMPAHSIS_COEFF_MASK (0x1f << 8) -#define DKL_TX_VSWING_CONTROL(x) ((x) << 0) -#define DKL_TX_VSWING_CONTROL_MASK (0x7 << 0) -#define DKL_TX_DPCNTL0(tc_port) _MMIO(_PORT(tc_port, \ - _DKL_PHY1_BASE, \ - _DKL_PHY2_BASE) + \ - _DKL_TX_DPCNTL0) - -#define _DKL_TX_DPCNTL1 0x2C4 -/* Bits are the same as DKL_TX_DPCNTRL0 */ -#define DKL_TX_DPCNTL1(tc_port) _MMIO(_PORT(tc_port, \ - _DKL_PHY1_BASE, \ - _DKL_PHY2_BASE) + \ - _DKL_TX_DPCNTL1) - -#define _DKL_TX_DPCNTL2 0x2C8 -#define DKL_TX_DP20BITMODE REG_BIT(2) -#define DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX1_MASK REG_GENMASK(4, 3) -#define DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX1(val) REG_FIELD_PREP(DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX1_MASK, (val)) -#define DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2_MASK REG_GENMASK(6, 5) -#define DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2(val) REG_FIELD_PREP(DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2_MASK, (val)) -#define DKL_TX_DPCNTL2(tc_port) _MMIO(_PORT(tc_port, \ - _DKL_PHY1_BASE, \ - _DKL_PHY2_BASE) + \ - _DKL_TX_DPCNTL2) - -#define _DKL_TX_FW_CALIB 0x2F8 -#define DKL_TX_CFG_DISABLE_WAIT_INIT (1 << 7) -#define DKL_TX_FW_CALIB(tc_port) _MMIO(_PORT(tc_port, \ - _DKL_PHY1_BASE, \ - _DKL_PHY2_BASE) + \ - _DKL_TX_FW_CALIB) - -#define _DKL_TX_PMD_LANE_SUS 0xD00 -#define DKL_TX_PMD_LANE_SUS(tc_port) _MMIO(_PORT(tc_port, \ - _DKL_PHY1_BASE, \ - _DKL_PHY2_BASE) + \ - _DKL_TX_PMD_LANE_SUS) - -#define _DKL_TX_DW17 0xDC4 -#define DKL_TX_DW17(tc_port) _MMIO(_PORT(tc_port, \ - _DKL_PHY1_BASE, \ - _DKL_PHY2_BASE) + \ - _DKL_TX_DW17) - -#define _DKL_TX_DW18 0xDC8 -#define DKL_TX_DW18(tc_port) _MMIO(_PORT(tc_port, \ - _DKL_PHY1_BASE, \ - _DKL_PHY2_BASE) + \ - _DKL_TX_DW18) - -#define _DKL_DP_MODE 0xA0 -#define DKL_DP_MODE(tc_port) _MMIO(_PORT(tc_port, \ - _DKL_PHY1_BASE, \ - _DKL_PHY2_BASE) + \ - _DKL_DP_MODE) - -#define _DKL_CMN_UC_DW27 0x36C -#define DKL_CMN_UC_DW27_UC_HEALTH (0x1 << 15) -#define DKL_CMN_UC_DW_27(tc_port) _MMIO(_PORT(tc_port, \ - _DKL_PHY1_BASE, \ - _DKL_PHY2_BASE) + \ - _DKL_CMN_UC_DW27) - -/* - * Each Dekel PHY is addressed through a 4KB aperture. Each PHY has more than - * 4KB of register space, so a separate index is programmed in HIP_INDEX_REG0 - * or HIP_INDEX_REG1, based on the port number, to set the upper 2 address - * bits that point the 4KB window into the full PHY register space. - */ -#define _HIP_INDEX_REG0 0x1010A0 -#define _HIP_INDEX_REG1 0x1010A4 -#define HIP_INDEX_REG(tc_port) _MMIO((tc_port) < 4 ? _HIP_INDEX_REG0 \ - : _HIP_INDEX_REG1) -#define _HIP_INDEX_SHIFT(tc_port) (8 * ((tc_port) % 4)) -#define HIP_INDEX_VAL(tc_port, val) ((val) << _HIP_INDEX_SHIFT(tc_port)) - /* BXT display engine PLL */ #define BXT_DE_PLL_CTL _MMIO(0x6d000) #define BXT_DE_PLL_RATIO(x) (x) /* {60,65,100} * 19.2MHz */ -- cgit From b8ed55335ed86ab0a2b904ec1ee7bd121587dbe8 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 25 Oct 2022 14:44:57 +0300 Subject: drm/i915/tgl+: Sanitize DKL PHY register definitions Not all Dekel PHY registers have a lane instance, so having to specify this when using them is awkward. It makes more sense to define each PHY register with its full internal PHY offset where bits 15:12 is the lane for lane-instanced PHY registers and just a register bank index for other PHY registers. This way lane-instanced registers can be referred to with the (tc_port, lane) parameters, while other registers just with a tc_port parameter. An additional benefit of this change is to prevent passing a Dekel register to a generic MMIO access function or vice versa. v2: - Fix parameter reuse in the DKL_REG_MMIO definition. v3: - Rebase on latest patchset version. Cc: Jani Nikula Acked-by: Jani Nikula Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20221025114457.2191004-3-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 20 +-- .../drm/i915/display/intel_display_power_well.c | 2 +- drivers/gpu/drm/i915/display/intel_dkl_phy.c | 32 ++-- drivers/gpu/drm/i915/display/intel_dkl_phy.h | 10 +- drivers/gpu/drm/i915/display/intel_dkl_phy_regs.h | 199 +++++++++++---------- drivers/gpu/drm/i915/display/intel_dpll_mgr.c | 48 ++--- 6 files changed, 159 insertions(+), 152 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 54142ca3e694..e95bde5cf060 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -1264,11 +1264,11 @@ static void tgl_dkl_phy_set_signal_levels(struct intel_encoder *encoder, for (ln = 0; ln < 2; ln++) { int level; - intel_dkl_phy_write(dev_priv, DKL_TX_PMD_LANE_SUS(tc_port), ln, 0); + intel_dkl_phy_write(dev_priv, DKL_TX_PMD_LANE_SUS(tc_port, ln), 0); level = intel_ddi_level(encoder, crtc_state, 2*ln+0); - intel_dkl_phy_rmw(dev_priv, DKL_TX_DPCNTL0(tc_port), ln, + intel_dkl_phy_rmw(dev_priv, DKL_TX_DPCNTL0(tc_port, ln), DKL_TX_PRESHOOT_COEFF_MASK | DKL_TX_DE_EMPAHSIS_COEFF_MASK | DKL_TX_VSWING_CONTROL_MASK, @@ -1278,7 +1278,7 @@ static void tgl_dkl_phy_set_signal_levels(struct intel_encoder *encoder, level = intel_ddi_level(encoder, crtc_state, 2*ln+1); - intel_dkl_phy_rmw(dev_priv, DKL_TX_DPCNTL1(tc_port), ln, + intel_dkl_phy_rmw(dev_priv, DKL_TX_DPCNTL1(tc_port, ln), DKL_TX_PRESHOOT_COEFF_MASK | DKL_TX_DE_EMPAHSIS_COEFF_MASK | DKL_TX_VSWING_CONTROL_MASK, @@ -1286,7 +1286,7 @@ static void tgl_dkl_phy_set_signal_levels(struct intel_encoder *encoder, DKL_TX_DE_EMPHASIS_COEFF(trans->entries[level].dkl.de_emphasis) | DKL_TX_VSWING_CONTROL(trans->entries[level].dkl.vswing)); - intel_dkl_phy_rmw(dev_priv, DKL_TX_DPCNTL2(tc_port), ln, + intel_dkl_phy_rmw(dev_priv, DKL_TX_DPCNTL2(tc_port, ln), DKL_TX_DP20BITMODE, 0); if (IS_ALDERLAKE_P(dev_priv)) { @@ -1305,7 +1305,7 @@ static void tgl_dkl_phy_set_signal_levels(struct intel_encoder *encoder, val |= DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2(0); } - intel_dkl_phy_rmw(dev_priv, DKL_TX_DPCNTL2(tc_port), ln, + intel_dkl_phy_rmw(dev_priv, DKL_TX_DPCNTL2(tc_port, ln), DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX1_MASK | DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2_MASK, val); @@ -2018,8 +2018,8 @@ icl_program_mg_dp_mode(struct intel_digital_port *dig_port, return; if (DISPLAY_VER(dev_priv) >= 12) { - ln0 = intel_dkl_phy_read(dev_priv, DKL_DP_MODE(tc_port), 0); - ln1 = intel_dkl_phy_read(dev_priv, DKL_DP_MODE(tc_port), 1); + ln0 = intel_dkl_phy_read(dev_priv, DKL_DP_MODE(tc_port, 0)); + ln1 = intel_dkl_phy_read(dev_priv, DKL_DP_MODE(tc_port, 1)); } else { ln0 = intel_de_read(dev_priv, MG_DP_MODE(0, tc_port)); ln1 = intel_de_read(dev_priv, MG_DP_MODE(1, tc_port)); @@ -2080,8 +2080,8 @@ icl_program_mg_dp_mode(struct intel_digital_port *dig_port, } if (DISPLAY_VER(dev_priv) >= 12) { - intel_dkl_phy_write(dev_priv, DKL_DP_MODE(tc_port), 0, ln0); - intel_dkl_phy_write(dev_priv, DKL_DP_MODE(tc_port), 1, ln1); + intel_dkl_phy_write(dev_priv, DKL_DP_MODE(tc_port, 0), ln0); + intel_dkl_phy_write(dev_priv, DKL_DP_MODE(tc_port, 1), ln1); } else { intel_de_write(dev_priv, MG_DP_MODE(0, tc_port), ln0); intel_de_write(dev_priv, MG_DP_MODE(1, tc_port), ln1); @@ -3086,7 +3086,7 @@ static void adlp_tbt_to_dp_alt_switch_wa(struct intel_encoder *encoder) int ln; for (ln = 0; ln < 2; ln++) - intel_dkl_phy_rmw(i915, DKL_PCS_DW5(tc_port), ln, DKL_PCS_DW5_CORE_SOFTRESET, 0); + intel_dkl_phy_rmw(i915, DKL_PCS_DW5(tc_port, ln), DKL_PCS_DW5_CORE_SOFTRESET, 0); } static void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp, diff --git a/drivers/gpu/drm/i915/display/intel_display_power_well.c b/drivers/gpu/drm/i915/display/intel_display_power_well.c index 86974c515206..8710dd41ffd4 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power_well.c +++ b/drivers/gpu/drm/i915/display/intel_display_power_well.c @@ -532,7 +532,7 @@ icl_tc_phy_aux_power_well_enable(struct drm_i915_private *dev_priv, tc_port = TGL_AUX_PW_TO_TC_PORT(i915_power_well_instance(power_well)->hsw.idx); - if (wait_for(intel_dkl_phy_read(dev_priv, DKL_CMN_UC_DW_27(tc_port), 2) & + if (wait_for(intel_dkl_phy_read(dev_priv, DKL_CMN_UC_DW_27(tc_port)) & DKL_CMN_UC_DW27_UC_HEALTH, 1)) drm_warn(&dev_priv->drm, "Timeout waiting TC uC health\n"); diff --git a/drivers/gpu/drm/i915/display/intel_dkl_phy.c b/drivers/gpu/drm/i915/display/intel_dkl_phy.c index 01781293ffdc..57cc3edba016 100644 --- a/drivers/gpu/drm/i915/display/intel_dkl_phy.c +++ b/drivers/gpu/drm/i915/display/intel_dkl_phy.c @@ -12,7 +12,7 @@ #include "intel_dkl_phy_regs.h" static void -dkl_phy_set_hip_idx(struct drm_i915_private *i915, i915_reg_t reg, int idx) +dkl_phy_set_hip_idx(struct drm_i915_private *i915, struct intel_dkl_phy_reg reg) { enum tc_port tc_port = DKL_REG_TC_PORT(reg); @@ -20,28 +20,27 @@ dkl_phy_set_hip_idx(struct drm_i915_private *i915, i915_reg_t reg, int idx) intel_de_write(i915, HIP_INDEX_REG(tc_port), - HIP_INDEX_VAL(tc_port, idx)); + HIP_INDEX_VAL(tc_port, reg.bank_idx)); } /** * intel_dkl_phy_read - read a Dekel PHY register * @i915: i915 device instance * @reg: Dekel PHY register - * @ln: lane instance of @reg * * Read the @reg Dekel PHY register. * * Returns the read value. */ u32 -intel_dkl_phy_read(struct drm_i915_private *i915, i915_reg_t reg, int ln) +intel_dkl_phy_read(struct drm_i915_private *i915, struct intel_dkl_phy_reg reg) { u32 val; spin_lock(&i915->display.dkl.phy_lock); - dkl_phy_set_hip_idx(i915, reg, ln); - val = intel_de_read(i915, reg); + dkl_phy_set_hip_idx(i915, reg); + val = intel_de_read(i915, DKL_REG_MMIO(reg)); spin_unlock(&i915->display.dkl.phy_lock); @@ -52,18 +51,17 @@ intel_dkl_phy_read(struct drm_i915_private *i915, i915_reg_t reg, int ln) * intel_dkl_phy_write - write a Dekel PHY register * @i915: i915 device instance * @reg: Dekel PHY register - * @ln: lane instance of @reg * @val: value to write * * Write @val to the @reg Dekel PHY register. */ void -intel_dkl_phy_write(struct drm_i915_private *i915, i915_reg_t reg, int ln, u32 val) +intel_dkl_phy_write(struct drm_i915_private *i915, struct intel_dkl_phy_reg reg, u32 val) { spin_lock(&i915->display.dkl.phy_lock); - dkl_phy_set_hip_idx(i915, reg, ln); - intel_de_write(i915, reg, val); + dkl_phy_set_hip_idx(i915, reg); + intel_de_write(i915, DKL_REG_MMIO(reg), val); spin_unlock(&i915->display.dkl.phy_lock); } @@ -72,7 +70,6 @@ intel_dkl_phy_write(struct drm_i915_private *i915, i915_reg_t reg, int ln, u32 v * intel_dkl_phy_rmw - read-modify-write a Dekel PHY register * @i915: i915 device instance * @reg: Dekel PHY register - * @ln: lane instance of @reg * @clear: mask to clear * @set: mask to set * @@ -80,12 +77,12 @@ intel_dkl_phy_write(struct drm_i915_private *i915, i915_reg_t reg, int ln, u32 v * this value back to the register if the value differs from the read one. */ void -intel_dkl_phy_rmw(struct drm_i915_private *i915, i915_reg_t reg, int ln, u32 clear, u32 set) +intel_dkl_phy_rmw(struct drm_i915_private *i915, struct intel_dkl_phy_reg reg, u32 clear, u32 set) { spin_lock(&i915->display.dkl.phy_lock); - dkl_phy_set_hip_idx(i915, reg, ln); - intel_de_rmw(i915, reg, clear, set); + dkl_phy_set_hip_idx(i915, reg); + intel_de_rmw(i915, DKL_REG_MMIO(reg), clear, set); spin_unlock(&i915->display.dkl.phy_lock); } @@ -94,17 +91,16 @@ intel_dkl_phy_rmw(struct drm_i915_private *i915, i915_reg_t reg, int ln, u32 cle * intel_dkl_phy_posting_read - do a posting read from a Dekel PHY register * @i915: i915 device instance * @reg: Dekel PHY register - * @ln: lane instance of @reg * * Read the @reg Dekel PHY register without returning the read value. */ void -intel_dkl_phy_posting_read(struct drm_i915_private *i915, i915_reg_t reg, int ln) +intel_dkl_phy_posting_read(struct drm_i915_private *i915, struct intel_dkl_phy_reg reg) { spin_lock(&i915->display.dkl.phy_lock); - dkl_phy_set_hip_idx(i915, reg, ln); - intel_de_posting_read(i915, reg); + dkl_phy_set_hip_idx(i915, reg); + intel_de_posting_read(i915, DKL_REG_MMIO(reg)); spin_unlock(&i915->display.dkl.phy_lock); } diff --git a/drivers/gpu/drm/i915/display/intel_dkl_phy.h b/drivers/gpu/drm/i915/display/intel_dkl_phy.h index 260ad121a0b1..570ee36f9386 100644 --- a/drivers/gpu/drm/i915/display/intel_dkl_phy.h +++ b/drivers/gpu/drm/i915/display/intel_dkl_phy.h @@ -8,17 +8,17 @@ #include -#include "i915_reg_defs.h" +#include "intel_dkl_phy_regs.h" struct drm_i915_private; u32 -intel_dkl_phy_read(struct drm_i915_private *i915, i915_reg_t reg, int ln); +intel_dkl_phy_read(struct drm_i915_private *i915, struct intel_dkl_phy_reg reg); void -intel_dkl_phy_write(struct drm_i915_private *i915, i915_reg_t reg, int ln, u32 val); +intel_dkl_phy_write(struct drm_i915_private *i915, struct intel_dkl_phy_reg reg, u32 val); void -intel_dkl_phy_rmw(struct drm_i915_private *i915, i915_reg_t reg, int ln, u32 clear, u32 set); +intel_dkl_phy_rmw(struct drm_i915_private *i915, struct intel_dkl_phy_reg reg, u32 clear, u32 set); void -intel_dkl_phy_posting_read(struct drm_i915_private *i915, i915_reg_t reg, int ln); +intel_dkl_phy_posting_read(struct drm_i915_private *i915, struct intel_dkl_phy_reg reg); #endif /* __INTEL_DKL_PHY_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_dkl_phy_regs.h b/drivers/gpu/drm/i915/display/intel_dkl_phy_regs.h index 7d0f3aab7f5c..56085b32956d 100644 --- a/drivers/gpu/drm/i915/display/intel_dkl_phy_regs.h +++ b/drivers/gpu/drm/i915/display/intel_dkl_phy_regs.h @@ -6,6 +6,13 @@ #ifndef __INTEL_DKL_PHY_REGS__ #define __INTEL_DKL_PHY_REGS__ +#include + +struct intel_dkl_phy_reg { + u32 reg:24; + u32 bank_idx:4; +}; + #define _DKL_PHY1_BASE 0x168000 #define _DKL_PHY2_BASE 0x169000 #define _DKL_PHY3_BASE 0x16A000 @@ -17,18 +24,38 @@ (TC_PORT_1 + ((__reg).reg - _DKL_PHY1_BASE) / (_DKL_PHY2_BASE - _DKL_PHY1_BASE)) /* DEKEL PHY MMIO Address = Phy base + (internal address & ~index_mask) */ -#define _DKL_PCS_DW5 0x14 -#define DKL_PCS_DW5(tc_port) _MMIO(_PORT(tc_port, \ - _DKL_PHY1_BASE, \ - _DKL_PHY2_BASE) + \ - _DKL_PCS_DW5) +#define DKL_REG_MMIO(__reg) _MMIO((__reg).reg) + +#define _DKL_REG_PHY_BASE(tc_port) _PORT(tc_port, \ + _DKL_PHY1_BASE, \ + _DKL_PHY2_BASE) + +#define _DKL_BANK_SHIFT 12 +#define _DKL_REG_BANK_OFFSET(phy_offset) \ + ((phy_offset) & ((1 << _DKL_BANK_SHIFT) - 1)) +#define _DKL_REG_BANK_IDX(phy_offset) \ + (((phy_offset) >> _DKL_BANK_SHIFT) & 0xf) + +#define _DKL_REG(tc_port, phy_offset) \ + ((const struct intel_dkl_phy_reg) { \ + .reg = _DKL_REG_PHY_BASE(tc_port) + \ + _DKL_REG_BANK_OFFSET(phy_offset), \ + .bank_idx = _DKL_REG_BANK_IDX(phy_offset), \ + }) + +#define _DKL_REG_LN(tc_port, ln_idx, ln0_offs, ln1_offs) \ + _DKL_REG(tc_port, (ln0_offs) + (ln_idx) * ((ln1_offs) - (ln0_offs))) + +#define _DKL_PCS_DW5_LN0 0x0014 +#define _DKL_PCS_DW5_LN1 0x1014 +#define DKL_PCS_DW5(tc_port, ln) _DKL_REG_LN(tc_port, ln, \ + _DKL_PCS_DW5_LN0, \ + _DKL_PCS_DW5_LN1) #define DKL_PCS_DW5_CORE_SOFTRESET REG_BIT(11) -#define _DKL_PLL_DIV0 0x200 -#define DKL_PLL_DIV0(tc_port) _MMIO(_PORT(tc_port, \ - _DKL_PHY1_BASE, \ - _DKL_PHY2_BASE) + \ - _DKL_PLL_DIV0) +#define _DKL_PLL_DIV0 0x2200 +#define DKL_PLL_DIV0(tc_port) _DKL_REG(tc_port, \ + _DKL_PLL_DIV0) #define DKL_PLL_DIV0_AFC_STARTUP_MASK REG_GENMASK(27, 25) #define DKL_PLL_DIV0_AFC_STARTUP(val) REG_FIELD_PREP(DKL_PLL_DIV0_AFC_STARTUP_MASK, (val)) #define DKL_PLL_DIV0_INTEG_COEFF(x) ((x) << 16) @@ -45,21 +72,17 @@ DKL_PLL_DIV0_FBPREDIV_MASK | \ DKL_PLL_DIV0_FBDIV_INT_MASK) -#define _DKL_PLL_DIV1 0x204 -#define DKL_PLL_DIV1(tc_port) _MMIO(_PORT(tc_port, \ - _DKL_PHY1_BASE, \ - _DKL_PHY2_BASE) + \ - _DKL_PLL_DIV1) +#define _DKL_PLL_DIV1 0x2204 +#define DKL_PLL_DIV1(tc_port) _DKL_REG(tc_port, \ + _DKL_PLL_DIV1) #define DKL_PLL_DIV1_IREF_TRIM(x) ((x) << 16) #define DKL_PLL_DIV1_IREF_TRIM_MASK (0x1F << 16) #define DKL_PLL_DIV1_TDC_TARGET_CNT(x) ((x) << 0) #define DKL_PLL_DIV1_TDC_TARGET_CNT_MASK (0xFF << 0) -#define _DKL_PLL_SSC 0x210 -#define DKL_PLL_SSC(tc_port) _MMIO(_PORT(tc_port, \ - _DKL_PHY1_BASE, \ - _DKL_PHY2_BASE) + \ - _DKL_PLL_SSC) +#define _DKL_PLL_SSC 0x2210 +#define DKL_PLL_SSC(tc_port) _DKL_REG(tc_port, \ + _DKL_PLL_SSC) #define DKL_PLL_SSC_IREF_NDIV_RATIO(x) ((x) << 29) #define DKL_PLL_SSC_IREF_NDIV_RATIO_MASK (0x7 << 29) #define DKL_PLL_SSC_STEP_LEN(x) ((x) << 16) @@ -68,52 +91,42 @@ #define DKL_PLL_SSC_STEP_NUM_MASK (0x7 << 11) #define DKL_PLL_SSC_EN (1 << 9) -#define _DKL_PLL_BIAS 0x214 -#define DKL_PLL_BIAS(tc_port) _MMIO(_PORT(tc_port, \ - _DKL_PHY1_BASE, \ - _DKL_PHY2_BASE) + \ - _DKL_PLL_BIAS) +#define _DKL_PLL_BIAS 0x2214 +#define DKL_PLL_BIAS(tc_port) _DKL_REG(tc_port, \ + _DKL_PLL_BIAS) #define DKL_PLL_BIAS_FRAC_EN_H (1 << 30) #define DKL_PLL_BIAS_FBDIV_SHIFT (8) #define DKL_PLL_BIAS_FBDIV_FRAC(x) ((x) << DKL_PLL_BIAS_FBDIV_SHIFT) #define DKL_PLL_BIAS_FBDIV_FRAC_MASK (0x3FFFFF << DKL_PLL_BIAS_FBDIV_SHIFT) -#define _DKL_PLL_TDC_COLDST_BIAS 0x218 -#define DKL_PLL_TDC_COLDST_BIAS(tc_port) _MMIO(_PORT(tc_port, \ - _DKL_PHY1_BASE, \ - _DKL_PHY2_BASE) + \ - _DKL_PLL_TDC_COLDST_BIAS) +#define _DKL_PLL_TDC_COLDST_BIAS 0x2218 +#define DKL_PLL_TDC_COLDST_BIAS(tc_port) _DKL_REG(tc_port, \ + _DKL_PLL_TDC_COLDST_BIAS) #define DKL_PLL_TDC_SSC_STEP_SIZE(x) ((x) << 8) #define DKL_PLL_TDC_SSC_STEP_SIZE_MASK (0xFF << 8) #define DKL_PLL_TDC_FEED_FWD_GAIN(x) ((x) << 0) #define DKL_PLL_TDC_FEED_FWD_GAIN_MASK (0xFF << 0) -#define _DKL_REFCLKIN_CTL 0x12C -#define DKL_REFCLKIN_CTL(tc_port) _MMIO(_PORT(tc_port, \ - _DKL_PHY1_BASE, \ - _DKL_PHY2_BASE) + \ - _DKL_REFCLKIN_CTL) +#define _DKL_REFCLKIN_CTL 0x212C +#define DKL_REFCLKIN_CTL(tc_port) _DKL_REG(tc_port, \ + _DKL_REFCLKIN_CTL) /* Bits are the same as MG_REFCLKIN_CTL */ -#define _DKL_CLKTOP2_HSCLKCTL 0xD4 -#define DKL_CLKTOP2_HSCLKCTL(tc_port) _MMIO(_PORT(tc_port, \ - _DKL_PHY1_BASE, \ - _DKL_PHY2_BASE) + \ - _DKL_CLKTOP2_HSCLKCTL) +#define _DKL_CLKTOP2_HSCLKCTL 0x20D4 +#define DKL_CLKTOP2_HSCLKCTL(rc_port) _DKL_REG(tc_port, \ + _DKL_CLKTOP2_HSCLKCTL) /* Bits are the same as MG_CLKTOP2_HSCLKCTL */ -#define _DKL_CLKTOP2_CORECLKCTL1 0xD8 -#define DKL_CLKTOP2_CORECLKCTL1(tc_port) _MMIO(_PORT(tc_port, \ - _DKL_PHY1_BASE, \ - _DKL_PHY2_BASE) + \ - _DKL_CLKTOP2_CORECLKCTL1) +#define _DKL_CLKTOP2_CORECLKCTL1 0x20D8 +#define DKL_CLKTOP2_CORECLKCTL1(tc_port) _DKL_REG(tc_port, \ + _DKL_CLKTOP2_CORECLKCTL1) /* Bits are the same as MG_CLKTOP2_CORECLKCTL1 */ -#define _DKL_TX_DPCNTL0 0x2C0 -#define DKL_TX_DPCNTL0(tc_port) _MMIO(_PORT(tc_port, \ - _DKL_PHY1_BASE, \ - _DKL_PHY2_BASE) + \ - _DKL_TX_DPCNTL0) +#define _DKL_TX_DPCNTL0_LN0 0x02C0 +#define _DKL_TX_DPCNTL0_LN1 0x12C0 +#define DKL_TX_DPCNTL0(tc_port, ln) _DKL_REG_LN(tc_port, ln, \ + _DKL_TX_DPCNTL0_LN0, \ + _DKL_TX_DPCNTL0_LN1) #define DKL_TX_PRESHOOT_COEFF(x) ((x) << 13) #define DKL_TX_PRESHOOT_COEFF_MASK (0x1f << 13) #define DKL_TX_DE_EMPHASIS_COEFF(x) ((x) << 8) @@ -121,60 +134,58 @@ #define DKL_TX_VSWING_CONTROL(x) ((x) << 0) #define DKL_TX_VSWING_CONTROL_MASK (0x7 << 0) -#define _DKL_TX_DPCNTL1 0x2C4 -#define DKL_TX_DPCNTL1(tc_port) _MMIO(_PORT(tc_port, \ - _DKL_PHY1_BASE, \ - _DKL_PHY2_BASE) + \ - _DKL_TX_DPCNTL1) +#define _DKL_TX_DPCNTL1_LN0 0x02C4 +#define _DKL_TX_DPCNTL1_LN1 0x12C4 +#define DKL_TX_DPCNTL1(tc_port, ln) _DKL_REG_LN(tc_port, ln, \ + _DKL_TX_DPCNTL1_LN0, \ + _DKL_TX_DPCNTL1_LN1) /* Bits are the same as DKL_TX_DPCNTRL0 */ -#define _DKL_TX_DPCNTL2 0x2C8 -#define DKL_TX_DPCNTL2(tc_port) _MMIO(_PORT(tc_port, \ - _DKL_PHY1_BASE, \ - _DKL_PHY2_BASE) + \ - _DKL_TX_DPCNTL2) +#define _DKL_TX_DPCNTL2_LN0 0x02C8 +#define _DKL_TX_DPCNTL2_LN1 0x12C8 +#define DKL_TX_DPCNTL2(tc_port, ln) _DKL_REG_LN(tc_port, ln, \ + _DKL_TX_DPCNTL2_LN0, \ + _DKL_TX_DPCNTL2_LN1) #define DKL_TX_DP20BITMODE REG_BIT(2) #define DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX1_MASK REG_GENMASK(4, 3) #define DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX1(val) REG_FIELD_PREP(DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX1_MASK, (val)) #define DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2_MASK REG_GENMASK(6, 5) #define DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2(val) REG_FIELD_PREP(DKL_TX_DPCNTL2_CFG_LOADGENSELECT_TX2_MASK, (val)) -#define _DKL_TX_FW_CALIB 0x2F8 -#define DKL_TX_FW_CALIB(tc_port) _MMIO(_PORT(tc_port, \ - _DKL_PHY1_BASE, \ - _DKL_PHY2_BASE) + \ - _DKL_TX_FW_CALIB) +#define _DKL_TX_FW_CALIB_LN0 0x02F8 +#define _DKL_TX_FW_CALIB_LN1 0x12F8 +#define DKL_TX_FW_CALIB(tc_port, ln) _DKL_REG_LN(tc_port, ln, \ + _DKL_TX_FW_CALIB_LN0, \ + _DKL_TX_FW_CALIB_LN1) #define DKL_TX_CFG_DISABLE_WAIT_INIT (1 << 7) -#define _DKL_TX_PMD_LANE_SUS 0xD00 -#define DKL_TX_PMD_LANE_SUS(tc_port) _MMIO(_PORT(tc_port, \ - _DKL_PHY1_BASE, \ - _DKL_PHY2_BASE) + \ - _DKL_TX_PMD_LANE_SUS) - -#define _DKL_TX_DW17 0xDC4 -#define DKL_TX_DW17(tc_port) _MMIO(_PORT(tc_port, \ - _DKL_PHY1_BASE, \ - _DKL_PHY2_BASE) + \ - _DKL_TX_DW17) - -#define _DKL_TX_DW18 0xDC8 -#define DKL_TX_DW18(tc_port) _MMIO(_PORT(tc_port, \ - _DKL_PHY1_BASE, \ - _DKL_PHY2_BASE) + \ - _DKL_TX_DW18) - -#define _DKL_DP_MODE 0xA0 -#define DKL_DP_MODE(tc_port) _MMIO(_PORT(tc_port, \ - _DKL_PHY1_BASE, \ - _DKL_PHY2_BASE) + \ - _DKL_DP_MODE) - -#define _DKL_CMN_UC_DW27 0x36C -#define DKL_CMN_UC_DW_27(tc_port) _MMIO(_PORT(tc_port, \ - _DKL_PHY1_BASE, \ - _DKL_PHY2_BASE) + \ - _DKL_CMN_UC_DW27) +#define _DKL_TX_PMD_LANE_SUS_LN0 0x0D00 +#define _DKL_TX_PMD_LANE_SUS_LN1 0x1D00 +#define DKL_TX_PMD_LANE_SUS(tc_port, ln) _DKL_REG_LN(tc_port, ln, \ + _DKL_TX_PMD_LANE_SUS_LN0, \ + _DKL_TX_PMD_LANE_SUS_LN1) + +#define _DKL_TX_DW17_LN0 0x0DC4 +#define _DKL_TX_DW17_LN1 0x1DC4 +#define DKL_TX_DW17(tc_port, ln) _DKL_REG_LN(tc_port, ln, \ + _DKL_TX_DW17_LN0, \ + _DKL_TX_DW17_LN1) + +#define _DKL_TX_DW18_LN0 0x0DC8 +#define _DKL_TX_DW18_LN1 0x1DC8 +#define DKL_TX_DW18(tc_port, ln) _DKL_REG_LN(tc_port, ln, \ + _DKL_TX_DW18_LN0, \ + _DKL_TX_DW18_LN1) + +#define _DKL_DP_MODE_LN0 0x00A0 +#define _DKL_DP_MODE_LN1 0x10A0 +#define DKL_DP_MODE(tc_port, ln) _DKL_REG_LN(tc_port, ln, \ + _DKL_DP_MODE_LN0, \ + _DKL_DP_MODE_LN1) + +#define _DKL_CMN_UC_DW27 0x236C +#define DKL_CMN_UC_DW_27(tc_port) _DKL_REG(tc_port, \ + _DKL_CMN_UC_DW27) #define DKL_CMN_UC_DW27_UC_HEALTH (0x1 << 15) /* diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c index bb7c8aef8952..7c6c094a0a01 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c @@ -3489,11 +3489,11 @@ static bool dkl_pll_get_hw_state(struct drm_i915_private *dev_priv, * they are on different building blocks */ hw_state->mg_refclkin_ctl = intel_dkl_phy_read(dev_priv, - DKL_REFCLKIN_CTL(tc_port), 2); + DKL_REFCLKIN_CTL(tc_port)); hw_state->mg_refclkin_ctl &= MG_REFCLKIN_CTL_OD_2_MUX_MASK; hw_state->mg_clktop2_hsclkctl = - intel_dkl_phy_read(dev_priv, DKL_CLKTOP2_HSCLKCTL(tc_port), 2); + intel_dkl_phy_read(dev_priv, DKL_CLKTOP2_HSCLKCTL(tc_port)); hw_state->mg_clktop2_hsclkctl &= MG_CLKTOP2_HSCLKCTL_TLINEDRV_CLKSEL_MASK | MG_CLKTOP2_HSCLKCTL_CORE_INPUTSEL_MASK | @@ -3501,32 +3501,32 @@ static bool dkl_pll_get_hw_state(struct drm_i915_private *dev_priv, MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_MASK; hw_state->mg_clktop2_coreclkctl1 = - intel_dkl_phy_read(dev_priv, DKL_CLKTOP2_CORECLKCTL1(tc_port), 2); + intel_dkl_phy_read(dev_priv, DKL_CLKTOP2_CORECLKCTL1(tc_port)); hw_state->mg_clktop2_coreclkctl1 &= MG_CLKTOP2_CORECLKCTL1_A_DIVRATIO_MASK; - hw_state->mg_pll_div0 = intel_dkl_phy_read(dev_priv, DKL_PLL_DIV0(tc_port), 2); + hw_state->mg_pll_div0 = intel_dkl_phy_read(dev_priv, DKL_PLL_DIV0(tc_port)); val = DKL_PLL_DIV0_MASK; if (dev_priv->display.vbt.override_afc_startup) val |= DKL_PLL_DIV0_AFC_STARTUP_MASK; hw_state->mg_pll_div0 &= val; - hw_state->mg_pll_div1 = intel_dkl_phy_read(dev_priv, DKL_PLL_DIV1(tc_port), 2); + hw_state->mg_pll_div1 = intel_dkl_phy_read(dev_priv, DKL_PLL_DIV1(tc_port)); hw_state->mg_pll_div1 &= (DKL_PLL_DIV1_IREF_TRIM_MASK | DKL_PLL_DIV1_TDC_TARGET_CNT_MASK); - hw_state->mg_pll_ssc = intel_dkl_phy_read(dev_priv, DKL_PLL_SSC(tc_port), 2); + hw_state->mg_pll_ssc = intel_dkl_phy_read(dev_priv, DKL_PLL_SSC(tc_port)); hw_state->mg_pll_ssc &= (DKL_PLL_SSC_IREF_NDIV_RATIO_MASK | DKL_PLL_SSC_STEP_LEN_MASK | DKL_PLL_SSC_STEP_NUM_MASK | DKL_PLL_SSC_EN); - hw_state->mg_pll_bias = intel_dkl_phy_read(dev_priv, DKL_PLL_BIAS(tc_port), 2); + hw_state->mg_pll_bias = intel_dkl_phy_read(dev_priv, DKL_PLL_BIAS(tc_port)); hw_state->mg_pll_bias &= (DKL_PLL_BIAS_FRAC_EN_H | DKL_PLL_BIAS_FBDIV_FRAC_MASK); hw_state->mg_pll_tdc_coldst_bias = - intel_dkl_phy_read(dev_priv, DKL_PLL_TDC_COLDST_BIAS(tc_port), 2); + intel_dkl_phy_read(dev_priv, DKL_PLL_TDC_COLDST_BIAS(tc_port)); hw_state->mg_pll_tdc_coldst_bias &= (DKL_PLL_TDC_SSC_STEP_SIZE_MASK | DKL_PLL_TDC_FEED_FWD_GAIN_MASK); @@ -3715,57 +3715,57 @@ static void dkl_pll_write(struct drm_i915_private *dev_priv, * though on different building block */ /* All the registers are RMW */ - val = intel_dkl_phy_read(dev_priv, DKL_REFCLKIN_CTL(tc_port), 2); + val = intel_dkl_phy_read(dev_priv, DKL_REFCLKIN_CTL(tc_port)); val &= ~MG_REFCLKIN_CTL_OD_2_MUX_MASK; val |= hw_state->mg_refclkin_ctl; - intel_dkl_phy_write(dev_priv, DKL_REFCLKIN_CTL(tc_port), 2, val); + intel_dkl_phy_write(dev_priv, DKL_REFCLKIN_CTL(tc_port), val); - val = intel_dkl_phy_read(dev_priv, DKL_CLKTOP2_CORECLKCTL1(tc_port), 2); + val = intel_dkl_phy_read(dev_priv, DKL_CLKTOP2_CORECLKCTL1(tc_port)); val &= ~MG_CLKTOP2_CORECLKCTL1_A_DIVRATIO_MASK; val |= hw_state->mg_clktop2_coreclkctl1; - intel_dkl_phy_write(dev_priv, DKL_CLKTOP2_CORECLKCTL1(tc_port), 2, val); + intel_dkl_phy_write(dev_priv, DKL_CLKTOP2_CORECLKCTL1(tc_port), val); - val = intel_dkl_phy_read(dev_priv, DKL_CLKTOP2_HSCLKCTL(tc_port), 2); + val = intel_dkl_phy_read(dev_priv, DKL_CLKTOP2_HSCLKCTL(tc_port)); val &= ~(MG_CLKTOP2_HSCLKCTL_TLINEDRV_CLKSEL_MASK | MG_CLKTOP2_HSCLKCTL_CORE_INPUTSEL_MASK | MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_MASK | MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_MASK); val |= hw_state->mg_clktop2_hsclkctl; - intel_dkl_phy_write(dev_priv, DKL_CLKTOP2_HSCLKCTL(tc_port), 2, val); + intel_dkl_phy_write(dev_priv, DKL_CLKTOP2_HSCLKCTL(tc_port), val); val = DKL_PLL_DIV0_MASK; if (dev_priv->display.vbt.override_afc_startup) val |= DKL_PLL_DIV0_AFC_STARTUP_MASK; - intel_dkl_phy_rmw(dev_priv, DKL_PLL_DIV0(tc_port), 2, val, + intel_dkl_phy_rmw(dev_priv, DKL_PLL_DIV0(tc_port), val, hw_state->mg_pll_div0); - val = intel_dkl_phy_read(dev_priv, DKL_PLL_DIV1(tc_port), 2); + val = intel_dkl_phy_read(dev_priv, DKL_PLL_DIV1(tc_port)); val &= ~(DKL_PLL_DIV1_IREF_TRIM_MASK | DKL_PLL_DIV1_TDC_TARGET_CNT_MASK); val |= hw_state->mg_pll_div1; - intel_dkl_phy_write(dev_priv, DKL_PLL_DIV1(tc_port), 2, val); + intel_dkl_phy_write(dev_priv, DKL_PLL_DIV1(tc_port), val); - val = intel_dkl_phy_read(dev_priv, DKL_PLL_SSC(tc_port), 2); + val = intel_dkl_phy_read(dev_priv, DKL_PLL_SSC(tc_port)); val &= ~(DKL_PLL_SSC_IREF_NDIV_RATIO_MASK | DKL_PLL_SSC_STEP_LEN_MASK | DKL_PLL_SSC_STEP_NUM_MASK | DKL_PLL_SSC_EN); val |= hw_state->mg_pll_ssc; - intel_dkl_phy_write(dev_priv, DKL_PLL_SSC(tc_port), 2, val); + intel_dkl_phy_write(dev_priv, DKL_PLL_SSC(tc_port), val); - val = intel_dkl_phy_read(dev_priv, DKL_PLL_BIAS(tc_port), 2); + val = intel_dkl_phy_read(dev_priv, DKL_PLL_BIAS(tc_port)); val &= ~(DKL_PLL_BIAS_FRAC_EN_H | DKL_PLL_BIAS_FBDIV_FRAC_MASK); val |= hw_state->mg_pll_bias; - intel_dkl_phy_write(dev_priv, DKL_PLL_BIAS(tc_port), 2, val); + intel_dkl_phy_write(dev_priv, DKL_PLL_BIAS(tc_port), val); - val = intel_dkl_phy_read(dev_priv, DKL_PLL_TDC_COLDST_BIAS(tc_port), 2); + val = intel_dkl_phy_read(dev_priv, DKL_PLL_TDC_COLDST_BIAS(tc_port)); val &= ~(DKL_PLL_TDC_SSC_STEP_SIZE_MASK | DKL_PLL_TDC_FEED_FWD_GAIN_MASK); val |= hw_state->mg_pll_tdc_coldst_bias; - intel_dkl_phy_write(dev_priv, DKL_PLL_TDC_COLDST_BIAS(tc_port), 2, val); + intel_dkl_phy_write(dev_priv, DKL_PLL_TDC_COLDST_BIAS(tc_port), val); - intel_dkl_phy_posting_read(dev_priv, DKL_PLL_TDC_COLDST_BIAS(tc_port), 2); + intel_dkl_phy_posting_read(dev_priv, DKL_PLL_TDC_COLDST_BIAS(tc_port)); } static void icl_pll_power_enable(struct drm_i915_private *dev_priv, -- cgit From e62f31e1739d33a1a377cc77b0e89aff21f23c4c Mon Sep 17 00:00:00 2001 From: Gustavo Sousa Date: Wed, 19 Oct 2022 13:13:34 -0300 Subject: drm/i915/xelp: Add Wa_1806527549 Workaround to be applied to platforms using XE_LP graphics. BSpec: 52890 Signed-off-by: Gustavo Sousa Reviewed-by: Lucas De Marchi Signed-off-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20221019161334.119885-1-gustavo.sousa@intel.com --- drivers/gpu/drm/i915/gt/intel_gt_regs.h | 1 + drivers/gpu/drm/i915/gt/intel_workarounds.c | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_regs.h b/drivers/gpu/drm/i915/gt/intel_gt_regs.h index 1c3a46ee876d..a9c409eb131c 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_regs.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_regs.h @@ -440,6 +440,7 @@ #define HIZ_CHICKEN _MMIO(0x7018) #define CHV_HZ_8X8_MODE_IN_1X REG_BIT(15) #define DG1_HZ_READ_SUPPRESSION_OPTIMIZATION_DISABLE REG_BIT(14) +#define HZ_DEPTH_TEST_LE_GE_OPT_DISABLE REG_BIT(13) #define BDW_HIZ_POWER_COMPILER_CLOCK_GATING_DISABLE REG_BIT(3) #define GEN8_L3CNTLREG _MMIO(0x7034) diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c index bae960486872..f87d4bde761b 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds.c +++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c @@ -660,6 +660,8 @@ static void gen12_ctx_gt_tuning_init(struct intel_engine_cs *engine, static void gen12_ctx_workarounds_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) { + struct drm_i915_private *i915 = engine->i915; + gen12_ctx_gt_tuning_init(engine, wal); /* @@ -693,6 +695,10 @@ static void gen12_ctx_workarounds_init(struct intel_engine_cs *engine, FF_MODE2_GS_TIMER_MASK, FF_MODE2_GS_TIMER_224, 0, false); + + if (!IS_DG1(i915)) + /* Wa_1806527549 */ + wa_masked_en(wal, HIZ_CHICKEN, HZ_DEPTH_TEST_LE_GE_OPT_DISABLE); } static void dg1_ctx_workarounds_init(struct intel_engine_cs *engine, -- cgit From f864a29afc32d3c0c2d7a34d71b49a8f92306aaa Mon Sep 17 00:00:00 2001 From: Vinay Belgaumkar Date: Mon, 24 Oct 2022 10:11:08 -0700 Subject: drm/i915/slpc: Optmize waitboost for SLPC Waitboost (when SLPC is enabled) results in a H2G message. This can result in thousands of messages during a stress test and fill up an already full CTB. There is no need to request for boost if min softlimit is equal or greater than it. v2: Add the tracing back, and check requested freq in the worker thread (Tvrtko) v3: Check requested freq in dec_waiters as well v4: Only check min_softlimit against boost_freq. Limit this optimization for server parts for now. v5: min_softlimit can be greater than boost (Ashutosh) Reviewed-by: Ashutosh Dixit Signed-off-by: Vinay Belgaumkar Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20221024171108.14373-1-vinay.belgaumkar@intel.com --- drivers/gpu/drm/i915/gt/intel_rps.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gt/intel_rps.c b/drivers/gpu/drm/i915/gt/intel_rps.c index 070005dd0da4..6c34a83c24b3 100644 --- a/drivers/gpu/drm/i915/gt/intel_rps.c +++ b/drivers/gpu/drm/i915/gt/intel_rps.c @@ -1014,9 +1014,15 @@ void intel_rps_boost(struct i915_request *rq) if (rps_uses_slpc(rps)) { slpc = rps_to_slpc(rps); + if (slpc->min_freq_softlimit >= slpc->boost_freq) + return; + /* Return if old value is non zero */ - if (!atomic_fetch_inc(&slpc->num_waiters)) + if (!atomic_fetch_inc(&slpc->num_waiters)) { + GT_TRACE(rps_to_gt(rps), "boost fence:%llx:%llx\n", + rq->fence.context, rq->fence.seqno); schedule_work(&slpc->boost_work); + } return; } -- cgit From c74b644f26e9c0600573521aefd486d9c9dfc566 Mon Sep 17 00:00:00 2001 From: Anusha Srivatsa Date: Tue, 25 Oct 2022 15:30:39 -0700 Subject: drm/i915/display: Change terminology for cdclk actions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No functional changes. Changing terminology in some print statements. s/has_cdclk_squasher/has_cdclk_squash, s/crawler/crawl and s/squasher/squash. Cc: Balasubramani Vivekanandan Cc: Ville Syrjälä Signed-off-by: Anusha Srivatsa Reviewed-by: Balasubramani Vivekanandan Link: https://patchwork.freedesktop.org/patch/msgid/20221025223042.138810-1-anusha.srivatsa@intel.com --- drivers/gpu/drm/i915/display/intel_cdclk.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index ad401357ab66..0f5add2fc51b 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -1220,7 +1220,7 @@ static void skl_cdclk_uninit_hw(struct drm_i915_private *dev_priv) skl_set_cdclk(dev_priv, &cdclk_config, INVALID_PIPE); } -static bool has_cdclk_squasher(struct drm_i915_private *i915) +static bool has_cdclk_squash(struct drm_i915_private *i915) { return IS_DG2(i915); } @@ -1520,7 +1520,7 @@ static void bxt_get_cdclk(struct drm_i915_private *dev_priv, return; } - if (has_cdclk_squasher(dev_priv)) + if (has_cdclk_squash(dev_priv)) squash_ctl = intel_de_read(dev_priv, CDCLK_SQUASH_CTL); if (squash_ctl & CDCLK_SQUASH_ENABLE) { @@ -1747,7 +1747,7 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv, else clock = cdclk; - if (has_cdclk_squasher(dev_priv)) { + if (has_cdclk_squash(dev_priv)) { u32 squash_ctl = 0; if (waveform) @@ -1845,7 +1845,7 @@ static void bxt_sanitize_cdclk(struct drm_i915_private *dev_priv) expected = skl_cdclk_decimal(cdclk); /* Figure out what CD2X divider we should be using for this cdclk */ - if (has_cdclk_squasher(dev_priv)) + if (has_cdclk_squash(dev_priv)) clock = dev_priv->display.cdclk.hw.vco / 2; else clock = dev_priv->display.cdclk.hw.cdclk; @@ -1976,7 +1976,7 @@ static bool intel_cdclk_can_squash(struct drm_i915_private *dev_priv, * the moment all platforms with squasher use a fixed cd2x * divider. */ - if (!has_cdclk_squasher(dev_priv)) + if (!has_cdclk_squash(dev_priv)) return false; return a->cdclk != b->cdclk && @@ -2028,7 +2028,7 @@ static bool intel_cdclk_can_cd2x_update(struct drm_i915_private *dev_priv, * the moment all platforms with squasher use a fixed cd2x * divider. */ - if (has_cdclk_squasher(dev_priv)) + if (has_cdclk_squash(dev_priv)) return false; return a->cdclk != b->cdclk && @@ -2754,12 +2754,12 @@ int intel_modeset_calc_cdclk(struct intel_atomic_state *state) &old_cdclk_state->actual, &new_cdclk_state->actual)) { drm_dbg_kms(&dev_priv->drm, - "Can change cdclk via squasher\n"); + "Can change cdclk via squashing\n"); } else if (intel_cdclk_can_crawl(dev_priv, &old_cdclk_state->actual, &new_cdclk_state->actual)) { drm_dbg_kms(&dev_priv->drm, - "Can change cdclk via crawl\n"); + "Can change cdclk via crawling\n"); } else if (pipe != INVALID_PIPE) { new_cdclk_state->pipe = pipe; -- cgit From 1d32f5d6e416768fdfc0d6f9b8659f57c0f779f3 Mon Sep 17 00:00:00 2001 From: Anusha Srivatsa Date: Tue, 25 Oct 2022 15:30:40 -0700 Subject: drm/i915/display: Introduce HAS_CDCLK_SQUASH macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Driver had discrepancy in how cdclk squash and crawl support were checked. Like crawl, add squash as a 1 bit feature flag to the display section of DG2. Cc: Balasubramani Vivekanandan Cc: Ville Syrjälä Signed-off-by: Anusha Srivatsa Reviewed-by: Balasubramani Vivekanandan Link: https://patchwork.freedesktop.org/patch/msgid/20221025223042.138810-2-anusha.srivatsa@intel.com --- drivers/gpu/drm/i915/display/intel_cdclk.c | 15 +++++---------- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_pci.c | 1 + drivers/gpu/drm/i915/intel_device_info.h | 1 + 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index 0f5add2fc51b..45babbc6290f 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -1220,11 +1220,6 @@ static void skl_cdclk_uninit_hw(struct drm_i915_private *dev_priv) skl_set_cdclk(dev_priv, &cdclk_config, INVALID_PIPE); } -static bool has_cdclk_squash(struct drm_i915_private *i915) -{ - return IS_DG2(i915); -} - struct intel_cdclk_vals { u32 cdclk; u16 refclk; @@ -1520,7 +1515,7 @@ static void bxt_get_cdclk(struct drm_i915_private *dev_priv, return; } - if (has_cdclk_squash(dev_priv)) + if (HAS_CDCLK_SQUASH(dev_priv)) squash_ctl = intel_de_read(dev_priv, CDCLK_SQUASH_CTL); if (squash_ctl & CDCLK_SQUASH_ENABLE) { @@ -1747,7 +1742,7 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv, else clock = cdclk; - if (has_cdclk_squash(dev_priv)) { + if (HAS_CDCLK_SQUASH(dev_priv)) { u32 squash_ctl = 0; if (waveform) @@ -1845,7 +1840,7 @@ static void bxt_sanitize_cdclk(struct drm_i915_private *dev_priv) expected = skl_cdclk_decimal(cdclk); /* Figure out what CD2X divider we should be using for this cdclk */ - if (has_cdclk_squash(dev_priv)) + if (HAS_CDCLK_SQUASH(dev_priv)) clock = dev_priv->display.cdclk.hw.vco / 2; else clock = dev_priv->display.cdclk.hw.cdclk; @@ -1976,7 +1971,7 @@ static bool intel_cdclk_can_squash(struct drm_i915_private *dev_priv, * the moment all platforms with squasher use a fixed cd2x * divider. */ - if (!has_cdclk_squash(dev_priv)) + if (!HAS_CDCLK_SQUASH(dev_priv)) return false; return a->cdclk != b->cdclk && @@ -2028,7 +2023,7 @@ static bool intel_cdclk_can_cd2x_update(struct drm_i915_private *dev_priv, * the moment all platforms with squasher use a fixed cd2x * divider. */ - if (has_cdclk_squash(dev_priv)) + if (HAS_CDCLK_SQUASH(dev_priv)) return false; return a->cdclk != b->cdclk && diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e18b66b8640b..59125a3d0c25 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -865,6 +865,7 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915, #define HAS_DOUBLE_BUFFERED_M_N(dev_priv) (DISPLAY_VER(dev_priv) >= 9 || IS_BROADWELL(dev_priv)) #define HAS_CDCLK_CRAWL(dev_priv) (INTEL_INFO(dev_priv)->display.has_cdclk_crawl) +#define HAS_CDCLK_SQUASH(dev_priv) (INTEL_INFO(dev_priv)->display.has_cdclk_squash) #define HAS_DDI(dev_priv) (INTEL_INFO(dev_priv)->display.has_ddi) #define HAS_FPGA_DBG_UNCLAIMED(dev_priv) (INTEL_INFO(dev_priv)->display.has_fpga_dbg) #define HAS_PSR(dev_priv) (INTEL_INFO(dev_priv)->display.has_psr) diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c index 99624c71b732..7676ce5f7379 100644 --- a/drivers/gpu/drm/i915/i915_pci.c +++ b/drivers/gpu/drm/i915/i915_pci.c @@ -1063,6 +1063,7 @@ static const struct intel_device_info xehpsdv_info = { .has_heci_pxp = 1, \ .needs_compact_pt = 1, \ .has_media_ratio_mode = 1, \ + .display.has_cdclk_squash = 1, \ .__runtime.platform_engine_mask = \ BIT(RCS0) | BIT(BCS0) | \ BIT(VECS0) | BIT(VECS1) | \ diff --git a/drivers/gpu/drm/i915/intel_device_info.h b/drivers/gpu/drm/i915/intel_device_info.h index 4da73f4e4751..3b2c8618abc6 100644 --- a/drivers/gpu/drm/i915/intel_device_info.h +++ b/drivers/gpu/drm/i915/intel_device_info.h @@ -179,6 +179,7 @@ enum intel_ppgtt_type { /* Keep in alphabetical order */ \ func(cursor_needs_physical); \ func(has_cdclk_crawl); \ + func(has_cdclk_squash); \ func(has_ddi); \ func(has_dp_mst); \ func(has_dsb); \ -- cgit From 6688b6b100cc573b83f6e00cf329b69cc7c46272 Mon Sep 17 00:00:00 2001 From: Anusha Srivatsa Date: Tue, 25 Oct 2022 15:30:41 -0700 Subject: drm/i915/display: Move chunks of code out of bxt_set_cdclk() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No functional change. Moving segments out to simplify bxt_set_cdlck() v2: s/bxt_cdclk_pll/bxt_cdclk_pll_update (Jani) Cc: Jani Nikula Cc: Balasubramani Vivekanandan Cc: Ville Syrjälä Signed-off-by: Anusha Srivatsa Reviewed-by: Balasubramani Vivekanandan Link: https://patchwork.freedesktop.org/patch/msgid/20221025223042.138810-3-anusha.srivatsa@intel.com --- drivers/gpu/drm/i915/display/intel_cdclk.c | 39 ++++++++++++++++++------------ 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index 45babbc6290f..9cd02b85ee51 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -1684,6 +1684,26 @@ static u32 cdclk_squash_waveform(struct drm_i915_private *dev_priv, return 0xffff; } +static void icl_cdclk_pll_update(struct drm_i915_private *i915, int vco) +{ + if (i915->display.cdclk.hw.vco != 0 && + i915->display.cdclk.hw.vco != vco) + icl_cdclk_pll_disable(i915); + + if (i915->display.cdclk.hw.vco != vco) + icl_cdclk_pll_enable(i915, vco); +} + +static void bxt_cdclk_pll_update(struct drm_i915_private *i915, int vco) +{ + if (i915->display.cdclk.hw.vco != 0 && + i915->display.cdclk.hw.vco != vco) + bxt_de_pll_disable(i915); + + if (i915->display.cdclk.hw.vco != vco) + bxt_de_pll_enable(i915, vco); +} + static void bxt_set_cdclk(struct drm_i915_private *dev_priv, const struct intel_cdclk_config *cdclk_config, enum pipe pipe) @@ -1719,21 +1739,10 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv, if (HAS_CDCLK_CRAWL(dev_priv) && dev_priv->display.cdclk.hw.vco > 0 && vco > 0) { if (dev_priv->display.cdclk.hw.vco != vco) adlp_cdclk_pll_crawl(dev_priv, vco); - } else if (DISPLAY_VER(dev_priv) >= 11) { - if (dev_priv->display.cdclk.hw.vco != 0 && - dev_priv->display.cdclk.hw.vco != vco) - icl_cdclk_pll_disable(dev_priv); - - if (dev_priv->display.cdclk.hw.vco != vco) - icl_cdclk_pll_enable(dev_priv, vco); - } else { - if (dev_priv->display.cdclk.hw.vco != 0 && - dev_priv->display.cdclk.hw.vco != vco) - bxt_de_pll_disable(dev_priv); - - if (dev_priv->display.cdclk.hw.vco != vco) - bxt_de_pll_enable(dev_priv, vco); - } + } else if (DISPLAY_VER(dev_priv) >= 11) + icl_cdclk_pll_update(dev_priv, vco); + else + bxt_cdclk_pll_update(dev_priv, vco); waveform = cdclk_squash_waveform(dev_priv, cdclk); -- cgit From fcfe55f214f5d1ae18332a055e83ddd840eef2f2 Mon Sep 17 00:00:00 2001 From: Anusha Srivatsa Date: Tue, 25 Oct 2022 15:30:42 -0700 Subject: drm/i915/display: Move squash_ctl register programming to its own function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No functional change. Introduce dg2_cdclk_squash_program and move squash_ctl register programming bits to this. v2: s/dg2_cdclk_squash_programming/dg2_cdclk_squash_program (Jani) Cc: Jani Nikula Cc: Balasubramani Vivekanandan Cc: Ville Syrjälä Signed-off-by: Anusha Srivatsa Reviewed-by: Balasubramani Vivekanandan Link: https://patchwork.freedesktop.org/patch/msgid/20221025223042.138810-4-anusha.srivatsa@intel.com --- drivers/gpu/drm/i915/display/intel_cdclk.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index 9cd02b85ee51..eada931cb1c8 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -1704,6 +1704,18 @@ static void bxt_cdclk_pll_update(struct drm_i915_private *i915, int vco) bxt_de_pll_enable(i915, vco); } +static void dg2_cdclk_squash_program(struct drm_i915_private *i915, + u16 waveform) +{ + u32 squash_ctl = 0; + + if (waveform) + squash_ctl = CDCLK_SQUASH_ENABLE | + CDCLK_SQUASH_WINDOW_SIZE(0xf) | waveform; + + intel_de_write(i915, CDCLK_SQUASH_CTL, squash_ctl); +} + static void bxt_set_cdclk(struct drm_i915_private *dev_priv, const struct intel_cdclk_config *cdclk_config, enum pipe pipe) @@ -1751,15 +1763,8 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv, else clock = cdclk; - if (HAS_CDCLK_SQUASH(dev_priv)) { - u32 squash_ctl = 0; - - if (waveform) - squash_ctl = CDCLK_SQUASH_ENABLE | - CDCLK_SQUASH_WINDOW_SIZE(0xf) | waveform; - - intel_de_write(dev_priv, CDCLK_SQUASH_CTL, squash_ctl); - } + if (HAS_CDCLK_SQUASH(dev_priv)) + dg2_cdclk_squash_program(dev_priv, waveform); val = bxt_cdclk_cd2x_div_sel(dev_priv, clock, vco) | bxt_cdclk_cd2x_pipe(dev_priv, pipe) | -- cgit From 37d52e446e8210a5ac56404434bd83e0e1eff6ba Mon Sep 17 00:00:00 2001 From: Vinay Belgaumkar Date: Mon, 24 Oct 2022 15:54:53 -0700 Subject: drm/i915/slpc: Use platform limits for min/max frequency GuC will set the min/max frequencies to theoretical max on ATS-M. This will break kernel ABI, so limit min/max frequency to RP0(platform max) instead. Also modify the SLPC selftest to update the min frequency when we have a server part so that we can iterate between platform min and max. v2: Check softlimits instead of platform limits (Riana) v3: More review comments (Ashutosh) v4: No need to use saved_min_freq and other comments (Ashutosh) Bug: https://gitlab.freedesktop.org/drm/intel/-/issues/7030 Acked-by: Nirmoy Das Reviewed-by: Riana Tauro Signed-off-by: Vinay Belgaumkar Reviewed-by: Ashutosh Dixit Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20221024225453.4856-1-vinay.belgaumkar@intel.com --- drivers/gpu/drm/i915/gt/selftest_slpc.c | 20 ++++++------ drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c | 37 +++++++++++++++++++++++ drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.h | 2 ++ drivers/gpu/drm/i915/gt/uc/intel_guc_slpc_types.h | 3 ++ 4 files changed, 53 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/selftest_slpc.c b/drivers/gpu/drm/i915/gt/selftest_slpc.c index 4c6e9257e593..82ec95a299f6 100644 --- a/drivers/gpu/drm/i915/gt/selftest_slpc.c +++ b/drivers/gpu/drm/i915/gt/selftest_slpc.c @@ -239,6 +239,11 @@ static int run_test(struct intel_gt *gt, int test_type) if (!intel_uc_uses_guc_slpc(>->uc)) return 0; + if (slpc->min_freq == slpc->rp0_freq) { + pr_err("Min/Max are fused to the same value\n"); + return -EINVAL; + } + if (igt_spinner_init(&spin, gt)) return -ENOMEM; @@ -253,17 +258,14 @@ static int run_test(struct intel_gt *gt, int test_type) } /* - * FIXME: With efficient frequency enabled, GuC can request - * frequencies higher than the SLPC max. While this is fixed - * in GuC, we level set these tests with RPn as min. + * Set min frequency to RPn so that we can test the whole + * range of RPn-RP0. This also turns off efficient freq + * usage and makes results more predictable. */ err = slpc_set_min_freq(slpc, slpc->min_freq); - if (err) + if (err) { + pr_err("Unable to update min freq!"); return err; - - if (slpc->min_freq == slpc->rp0_freq) { - pr_err("Min/Max are fused to the same value\n"); - return -EINVAL; } intel_gt_pm_wait_for_idle(gt); @@ -330,7 +332,7 @@ static int run_test(struct intel_gt *gt, int test_type) engine->name, max_act_freq); /* Actual frequency should rise above min */ - if (max_act_freq <= slpc_min_freq) { + if (max_act_freq <= slpc->min_freq) { pr_err("Actual freq did not rise above min\n"); pr_err("Perf Limit Reasons: 0x%x\n", intel_uncore_read(gt->uncore, GT0_PERF_LIMIT_REASONS)); diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c index fdd895f73f9f..c7e568af1e9c 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c @@ -263,6 +263,7 @@ int intel_guc_slpc_init(struct intel_guc_slpc *slpc) slpc->max_freq_softlimit = 0; slpc->min_freq_softlimit = 0; + slpc->min_is_rpmax = false; slpc->boost_freq = 0; atomic_set(&slpc->num_waiters, 0); @@ -588,6 +589,39 @@ static int slpc_set_softlimits(struct intel_guc_slpc *slpc) return 0; } +static bool is_slpc_min_freq_rpmax(struct intel_guc_slpc *slpc) +{ + struct drm_i915_private *i915 = slpc_to_i915(slpc); + int slpc_min_freq; + int ret; + + ret = intel_guc_slpc_get_min_freq(slpc, &slpc_min_freq); + if (ret) { + drm_err(&i915->drm, + "Failed to get min freq: (%d)\n", + ret); + return false; + } + + if (slpc_min_freq == SLPC_MAX_FREQ_MHZ) + return true; + else + return false; +} + +static void update_server_min_softlimit(struct intel_guc_slpc *slpc) +{ + /* For server parts, SLPC min will be at RPMax. + * Use min softlimit to clamp it to RP0 instead. + */ + if (!slpc->min_freq_softlimit && + is_slpc_min_freq_rpmax(slpc)) { + slpc->min_is_rpmax = true; + slpc->min_freq_softlimit = slpc->rp0_freq; + (slpc_to_gt(slpc))->defaults.min_freq = slpc->min_freq_softlimit; + } +} + static int slpc_use_fused_rp0(struct intel_guc_slpc *slpc) { /* Force SLPC to used platform rp0 */ @@ -647,6 +681,9 @@ int intel_guc_slpc_enable(struct intel_guc_slpc *slpc) slpc_get_rp_values(slpc); + /* Handle the case where min=max=RPmax */ + update_server_min_softlimit(slpc); + /* Set SLPC max limit to RP0 */ ret = slpc_use_fused_rp0(slpc); if (unlikely(ret)) { diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.h index 82a98f78f96c..11975a31c9d0 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.h @@ -9,6 +9,8 @@ #include "intel_guc_submission.h" #include "intel_guc_slpc_types.h" +#define SLPC_MAX_FREQ_MHZ 4250 + struct intel_gt; struct drm_printer; diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc_types.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc_types.h index 73d208123528..a6ef53b04e04 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc_types.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc_types.h @@ -19,6 +19,9 @@ struct intel_guc_slpc { bool supported; bool selected; + /* Indicates this is a server part */ + bool min_is_rpmax; + /* platform frequency limits */ u32 min_freq; u32 rp0_freq; -- cgit From befb231d5de2773f6c6f6cf918234e2e709110a5 Mon Sep 17 00:00:00 2001 From: Alan Previn Date: Tue, 25 Oct 2022 23:05:06 -0700 Subject: drm/i915/guc: Fix GuC error capture sizing estimation and reporting During GuC error capture initialization, we estimate the amount of size we need for the error-capture-region of the shared GuC-log-buffer. This calculation was incorrect so fix that. With the fixed calculation we can reduce the allocation of error-capture region from 4MB to 1MB (see note2 below for reasoning). Additionally, switch from drm_notice to drm_debug for the 3X spare size check since that would be impossible to hit without redesigning gpu_coredump framework to hold multiple captures. NOTE1: Even for 1x the min size estimation case, actually running out of space is a corner case because it can only occur if all engine instances get reset all at once and i915 isn't able extract the capture data fast enough within G2H handler worker. NOTE2: With the corrected calculation, a DG2 part required ~77K and a PVC required ~115K (1X min-est-size that is calculated as one-shot all-engine- reset scenario). Fixes: d7c15d76a554 ("drm/i915/guc: Check sizing of guc_capture output") Cc: Alan Previn Cc: Matthew Brost Cc: Lucas De Marchi Cc: John Harrison Cc: Umesh Nerlige Ramappa Cc: Balasubramani Vivekanandan Cc: Matt Roper Cc: Jani Nikula Cc: Joonas Lahtinen Cc: Chris Wilson Signed-off-by: Alan Previn Reviewed-by: John Harrison Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20221026060506.1007830-2-alan.previn.teres.alexis@intel.com --- drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c | 29 ++++++++++++++++---------- drivers/gpu/drm/i915/gt/uc/intel_guc_log.c | 6 +++--- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c index c4bee3bc15a9..4e6dca707d94 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c @@ -559,8 +559,9 @@ guc_capture_getlistsize(struct intel_guc *guc, u32 owner, u32 type, u32 classid, if (!num_regs) return -ENODATA; - *size = PAGE_ALIGN((sizeof(struct guc_debug_capture_list)) + - (num_regs * sizeof(struct guc_mmio_reg))); + if (size) + *size = PAGE_ALIGN((sizeof(struct guc_debug_capture_list)) + + (num_regs * sizeof(struct guc_mmio_reg))); return 0; } @@ -670,7 +671,7 @@ guc_capture_output_min_size_est(struct intel_guc *guc) struct intel_gt *gt = guc_to_gt(guc); struct intel_engine_cs *engine; enum intel_engine_id id; - int worst_min_size = 0, num_regs = 0; + int worst_min_size = 0; size_t tmp = 0; if (!guc->capture) @@ -692,20 +693,18 @@ guc_capture_output_min_size_est(struct intel_guc *guc) (3 * sizeof(struct guc_state_capture_header_t)); if (!guc_capture_getlistsize(guc, 0, GUC_CAPTURE_LIST_TYPE_GLOBAL, 0, &tmp, true)) - num_regs += tmp; + worst_min_size += tmp; if (!guc_capture_getlistsize(guc, 0, GUC_CAPTURE_LIST_TYPE_ENGINE_CLASS, engine->class, &tmp, true)) { - num_regs += tmp; + worst_min_size += tmp; } if (!guc_capture_getlistsize(guc, 0, GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE, engine->class, &tmp, true)) { - num_regs += tmp; + worst_min_size += tmp; } } - worst_min_size += (num_regs * sizeof(struct guc_mmio_reg)); - return worst_min_size; } @@ -722,15 +721,23 @@ static void check_guc_capture_size(struct intel_guc *guc) int spare_size = min_size * GUC_CAPTURE_OVERBUFFER_MULTIPLIER; u32 buffer_size = intel_guc_log_section_size_capture(&guc->log); + /* + * NOTE: min_size is much smaller than the capture region allocation (DG2: <80K vs 1MB) + * Additionally, its based on space needed to fit all engines getting reset at once + * within the same G2H handler task slot. This is very unlikely. However, if GuC really + * does run out of space for whatever reason, we will see an separate warning message + * when processing the G2H event capture-notification, search for: + * INTEL_GUC_STATE_CAPTURE_EVENT_STATUS_NOSPACE. + */ if (min_size < 0) drm_warn(&i915->drm, "Failed to calculate GuC error state capture buffer minimum size: %d!\n", min_size); else if (min_size > buffer_size) - drm_warn(&i915->drm, "GuC error state capture buffer is too small: %d < %d\n", + drm_warn(&i915->drm, "GuC error state capture buffer maybe small: %d < %d\n", buffer_size, min_size); else if (spare_size > buffer_size) - drm_notice(&i915->drm, "GuC error state capture buffer maybe too small: %d < %d (min = %d)\n", - buffer_size, spare_size, min_size); + drm_dbg(&i915->drm, "GuC error state capture buffer lacks spare size: %d < %d (min = %d)\n", + buffer_size, spare_size, min_size); } /* diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c index 55d3ef93e86f..68331c538b0a 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c @@ -16,15 +16,15 @@ #if defined(CONFIG_DRM_I915_DEBUG_GUC) #define GUC_LOG_DEFAULT_CRASH_BUFFER_SIZE SZ_2M #define GUC_LOG_DEFAULT_DEBUG_BUFFER_SIZE SZ_16M -#define GUC_LOG_DEFAULT_CAPTURE_BUFFER_SIZE SZ_4M +#define GUC_LOG_DEFAULT_CAPTURE_BUFFER_SIZE SZ_1M #elif defined(CONFIG_DRM_I915_DEBUG_GEM) #define GUC_LOG_DEFAULT_CRASH_BUFFER_SIZE SZ_1M #define GUC_LOG_DEFAULT_DEBUG_BUFFER_SIZE SZ_2M -#define GUC_LOG_DEFAULT_CAPTURE_BUFFER_SIZE SZ_4M +#define GUC_LOG_DEFAULT_CAPTURE_BUFFER_SIZE SZ_1M #else #define GUC_LOG_DEFAULT_CRASH_BUFFER_SIZE SZ_8K #define GUC_LOG_DEFAULT_DEBUG_BUFFER_SIZE SZ_64K -#define GUC_LOG_DEFAULT_CAPTURE_BUFFER_SIZE SZ_2M +#define GUC_LOG_DEFAULT_CAPTURE_BUFFER_SIZE SZ_1M #endif static void guc_log_copy_debuglogs_for_relay(struct intel_guc_log *log); -- cgit From 833210943099f5cfd9bd054ce9c5ec2e971bcc89 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Thu, 6 Oct 2022 15:51:20 -0700 Subject: drm/i915/guc: Delay disabling guc_id scheduling for better hysteresis Add a delay, configurable via debugfs (default 34ms), to disable scheduling of a context after the pin count goes to zero. Disable scheduling is a costly operation as it requires synchronizing with the GuC. So the idea is that a delay allows the user to resubmit something before doing this operation. This delay is only done if the context isn't closed and less than a given threshold (default is 3/4) of the guc_ids are in use. Alan Previn: Matt Brost first introduced this patch back in Oct 2021. However no real world workload with measured performance impact was available to prove the intended results. Today, this series is being republished in response to a real world workload that benefited greatly from it along with measured performance improvement. Workload description: 36 containers were created on a DG2 device where each container was performing a combination of 720p 3d game rendering and 30fps video encoding. The workload density was configured in a way that guaranteed each container to ALWAYS be able to render and encode no less than 30fps with a predefined maximum render + encode latency time. That means the totality of all 36 containers and their workloads were not saturating the engines to their max (in order to maintain just enough headrooom to meet the min fps and max latencies of incoming container submissions). Problem statement: It was observed that the CPU core processing the i915 soft IRQ work was experiencing severe load. Using tracelogs and an instrumentation patch to count specific i915 IRQ events, it was confirmed that the majority of the CPU cycles were caused by the gen11_other_irq_handler() -> guc_irq_handler() code path. The vast majority of the cycles was determined to be processing a specific G2H IRQ: i.e. INTEL_GUC_ACTION_SCHED_CONTEXT_MODE_DONE. These IRQs are sent by GuC in response to i915 KMD sending H2G requests: INTEL_GUC_ACTION_SCHED_CONTEXT_MODE_SET. Those H2G requests are sent whenever a context goes idle so that we can unpin the context from GuC. The high CPU utilization % symptom was limiting density scaling. Root Cause Analysis: Because the incoming execution buffers were spread across 36 different containers (each with multiple contexts) but the system in totality was NOT saturated to the max, it was assumed that each context was constantly idling between submissions. This was causing a thrashing of unpinning contexts from GuC at one moment, followed quickly by repinning them due to incoming workload the very next moment. These event-pairs were being triggered across multiple contexts per container, across all containers at the rate of > 30 times per sec per context. Metrics: When running this workload without this patch, we measured an average of ~69K INTEL_GUC_ACTION_SCHED_CONTEXT_MODE_DONE events every 10 seconds or ~10 million times over ~25+ mins. With this patch, the count reduced to ~480 every 10 seconds or about ~28K over ~10 mins. The improvement observed is ~99% for the average counts per 10 seconds. Design awareness: Selftest impact. As temporary WA disable this feature for the selftests. Selftests are very timing sensitive and any change in timing can cause failure. A follow up patch will fixup the selftests to understand this delay. Design awareness: Race between guc_request_alloc and guc_context_close. If a context close is issued while there is a request submission in flight and a delayed schedule disable is pending, guc_context_close and guc_request_alloc will race to cancel the delayed disable. To close the race, make sure that guc_request_alloc waits for guc_context_close to finish running before checking any state. Design awareness: GT Reset event. If a gt reset is triggered, as preparation steps, add an additional step to ensure all contexts that have a pending delay-disable-schedule task be flushed of it. Move them directly into the closed state after cancelling the worker. This is okay because the existing flow flushes all yet-to-arrive G2H's dropping them anyway. Signed-off-by: Matthew Brost Signed-off-by: Alan Previn Signed-off-by: Daniele Ceraolo Spurio Reviewed-by: John Harrison Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20221006225121.826257-2-alan.previn.teres.alexis@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_context.c | 2 +- drivers/gpu/drm/i915/gt/intel_context.h | 8 + drivers/gpu/drm/i915/gt/intel_context_types.h | 7 + drivers/gpu/drm/i915/gt/uc/intel_guc.h | 16 ++ drivers/gpu/drm/i915/gt/uc/intel_guc_debugfs.c | 61 +++++++ drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c | 205 +++++++++++++++++++--- drivers/gpu/drm/i915/i915_selftest.h | 2 + 7 files changed, 274 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c index 1e29b1e6d186..d0a537b15ebb 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c @@ -1452,7 +1452,7 @@ static void engines_idle_release(struct i915_gem_context *ctx, int err; /* serialises with execbuf */ - set_bit(CONTEXT_CLOSED_BIT, &ce->flags); + intel_context_close(ce); if (!intel_context_pin_if_active(ce)) continue; diff --git a/drivers/gpu/drm/i915/gt/intel_context.h b/drivers/gpu/drm/i915/gt/intel_context.h index be09fb2e883a..fb62b7b8cbcd 100644 --- a/drivers/gpu/drm/i915/gt/intel_context.h +++ b/drivers/gpu/drm/i915/gt/intel_context.h @@ -276,6 +276,14 @@ static inline bool intel_context_is_barrier(const struct intel_context *ce) return test_bit(CONTEXT_BARRIER_BIT, &ce->flags); } +static inline void intel_context_close(struct intel_context *ce) +{ + set_bit(CONTEXT_CLOSED_BIT, &ce->flags); + + if (ce->ops->close) + ce->ops->close(ce); +} + static inline bool intel_context_is_closed(const struct intel_context *ce) { return test_bit(CONTEXT_CLOSED_BIT, &ce->flags); diff --git a/drivers/gpu/drm/i915/gt/intel_context_types.h b/drivers/gpu/drm/i915/gt/intel_context_types.h index 04eacae1aca5..6a49fa7e119f 100644 --- a/drivers/gpu/drm/i915/gt/intel_context_types.h +++ b/drivers/gpu/drm/i915/gt/intel_context_types.h @@ -43,6 +43,8 @@ struct intel_context_ops { void (*revoke)(struct intel_context *ce, struct i915_request *rq, unsigned int preempt_timeout_ms); + void (*close)(struct intel_context *ce); + int (*pre_pin)(struct intel_context *ce, struct i915_gem_ww_ctx *ww, void **vaddr); int (*pin)(struct intel_context *ce, void *vaddr); void (*unpin)(struct intel_context *ce); @@ -208,6 +210,11 @@ struct intel_context { * each priority bucket */ u32 prio_count[GUC_CLIENT_PRIORITY_NUM]; + /** + * @sched_disable_delay_work: worker to disable scheduling on this + * context + */ + struct delayed_work sched_disable_delay_work; } guc_state; struct { diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.h b/drivers/gpu/drm/i915/gt/uc/intel_guc.h index 804133df1ac9..357873ef692b 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.h @@ -112,6 +112,10 @@ struct intel_guc { * refs */ struct list_head guc_id_list; + /** + * @guc_ids_in_use: Number single-lrc guc_ids in use + */ + unsigned int guc_ids_in_use; /** * @destroyed_contexts: list of contexts waiting to be destroyed * (deregistered with the GuC) @@ -132,6 +136,16 @@ struct intel_guc { * @reset_fail_mask: mask of engines that failed to reset */ intel_engine_mask_t reset_fail_mask; + /** + * @sched_disable_delay_ms: schedule disable delay, in ms, for + * contexts + */ + unsigned int sched_disable_delay_ms; + /** + * @sched_disable_gucid_threshold: threshold of min remaining available + * guc_ids before we start bypassing the schedule disable delay + */ + unsigned int sched_disable_gucid_threshold; } submission_state; /** @@ -466,4 +480,6 @@ void intel_guc_write_barrier(struct intel_guc *guc); void intel_guc_dump_time_info(struct intel_guc *guc, struct drm_printer *p); +int intel_guc_sched_disable_gucid_threshold_max(struct intel_guc *guc); + #endif diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_debugfs.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_debugfs.c index 25f09a420561..7269eb0bbedf 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_debugfs.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_debugfs.c @@ -71,12 +71,73 @@ static bool intel_eval_slpc_support(void *data) return intel_guc_slpc_is_used(guc); } +static int guc_sched_disable_delay_ms_get(void *data, u64 *val) +{ + struct intel_guc *guc = data; + + if (!intel_guc_submission_is_used(guc)) + return -ENODEV; + + *val = (u64)guc->submission_state.sched_disable_delay_ms; + + return 0; +} + +static int guc_sched_disable_delay_ms_set(void *data, u64 val) +{ + struct intel_guc *guc = data; + + if (!intel_guc_submission_is_used(guc)) + return -ENODEV; + + /* clamp to a practical limit, 1 minute is reasonable for a longest delay */ + guc->submission_state.sched_disable_delay_ms = min_t(u64, val, 60000); + + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(guc_sched_disable_delay_ms_fops, + guc_sched_disable_delay_ms_get, + guc_sched_disable_delay_ms_set, "%lld\n"); + +static int guc_sched_disable_gucid_threshold_get(void *data, u64 *val) +{ + struct intel_guc *guc = data; + + if (!intel_guc_submission_is_used(guc)) + return -ENODEV; + + *val = guc->submission_state.sched_disable_gucid_threshold; + return 0; +} + +static int guc_sched_disable_gucid_threshold_set(void *data, u64 val) +{ + struct intel_guc *guc = data; + + if (!intel_guc_submission_is_used(guc)) + return -ENODEV; + + if (val > intel_guc_sched_disable_gucid_threshold_max(guc)) + guc->submission_state.sched_disable_gucid_threshold = + intel_guc_sched_disable_gucid_threshold_max(guc); + else + guc->submission_state.sched_disable_gucid_threshold = val; + + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(guc_sched_disable_gucid_threshold_fops, + guc_sched_disable_gucid_threshold_get, + guc_sched_disable_gucid_threshold_set, "%lld\n"); + void intel_guc_debugfs_register(struct intel_guc *guc, struct dentry *root) { static const struct intel_gt_debugfs_file files[] = { { "guc_info", &guc_info_fops, NULL }, { "guc_registered_contexts", &guc_registered_contexts_fops, NULL }, { "guc_slpc_info", &guc_slpc_info_fops, &intel_eval_slpc_support}, + { "guc_sched_disable_delay_ms", &guc_sched_disable_delay_ms_fops, NULL }, + { "guc_sched_disable_gucid_threshold", &guc_sched_disable_gucid_threshold_fops, + NULL }, }; if (!intel_guc_is_supported(guc)) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index c433d35ae41a..e8c934f8aa3c 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -66,7 +66,13 @@ * corresponding G2H returns indicating the scheduling disable operation has * completed it is safe to unpin the context. While a disable is in flight it * isn't safe to resubmit the context so a fence is used to stall all future - * requests of that context until the G2H is returned. + * requests of that context until the G2H is returned. Because this interaction + * with the GuC takes a non-zero amount of time we delay the disabling of + * scheduling after the pin count goes to zero by a configurable period of time + * (see SCHED_DISABLE_DELAY_MS). The thought is this gives the user a window of + * time to resubmit something on the context before doing this costly operation. + * This delay is only done if the context isn't closed and the guc_id usage is + * less than a threshold (see NUM_SCHED_DISABLE_GUC_IDS_THRESHOLD). * * Context deregistration: * Before a context can be destroyed or if we steal its guc_id we must @@ -164,7 +170,8 @@ guc_create_parallel(struct intel_engine_cs **engines, #define SCHED_STATE_PENDING_ENABLE BIT(5) #define SCHED_STATE_REGISTERED BIT(6) #define SCHED_STATE_POLICY_REQUIRED BIT(7) -#define SCHED_STATE_BLOCKED_SHIFT 8 +#define SCHED_STATE_CLOSED BIT(8) +#define SCHED_STATE_BLOCKED_SHIFT 9 #define SCHED_STATE_BLOCKED BIT(SCHED_STATE_BLOCKED_SHIFT) #define SCHED_STATE_BLOCKED_MASK (0xfff << SCHED_STATE_BLOCKED_SHIFT) @@ -174,12 +181,20 @@ static inline void init_sched_state(struct intel_context *ce) ce->guc_state.sched_state &= SCHED_STATE_BLOCKED_MASK; } +/* + * Kernel contexts can have SCHED_STATE_REGISTERED after suspend. + * A context close can race with the submission path, so SCHED_STATE_CLOSED + * can be set immediately before we try to register. + */ +#define SCHED_STATE_VALID_INIT \ + (SCHED_STATE_BLOCKED_MASK | \ + SCHED_STATE_CLOSED | \ + SCHED_STATE_REGISTERED) + __maybe_unused static bool sched_state_is_init(struct intel_context *ce) { - /* Kernel contexts can have SCHED_STATE_REGISTERED after suspend. */ - return !(ce->guc_state.sched_state & - ~(SCHED_STATE_BLOCKED_MASK | SCHED_STATE_REGISTERED)); + return !(ce->guc_state.sched_state & ~SCHED_STATE_VALID_INIT); } static inline bool @@ -320,6 +335,17 @@ static inline void clr_context_policy_required(struct intel_context *ce) ce->guc_state.sched_state &= ~SCHED_STATE_POLICY_REQUIRED; } +static inline bool context_close_done(struct intel_context *ce) +{ + return ce->guc_state.sched_state & SCHED_STATE_CLOSED; +} + +static inline void set_context_close_done(struct intel_context *ce) +{ + lockdep_assert_held(&ce->guc_state.lock); + ce->guc_state.sched_state |= SCHED_STATE_CLOSED; +} + static inline u32 context_blocked(struct intel_context *ce) { return (ce->guc_state.sched_state & SCHED_STATE_BLOCKED_MASK) >> @@ -1068,6 +1094,12 @@ static void scrub_guc_desc_for_outstanding_g2h(struct intel_guc *guc) xa_unlock(&guc->context_lookup); + if (test_bit(CONTEXT_GUC_INIT, &ce->flags) && + (cancel_delayed_work(&ce->guc_state.sched_disable_delay_work))) { + /* successful cancel so jump straight to close it */ + intel_context_sched_disable_unpin(ce); + } + spin_lock(&ce->guc_state.lock); /* @@ -1995,6 +2027,9 @@ static int new_guc_id(struct intel_guc *guc, struct intel_context *ce) if (unlikely(ret < 0)) return ret; + if (!intel_context_is_parent(ce)) + ++guc->submission_state.guc_ids_in_use; + ce->guc_id.id = ret; return 0; } @@ -2004,14 +2039,16 @@ static void __release_guc_id(struct intel_guc *guc, struct intel_context *ce) GEM_BUG_ON(intel_context_is_child(ce)); if (!context_guc_id_invalid(ce)) { - if (intel_context_is_parent(ce)) + if (intel_context_is_parent(ce)) { bitmap_release_region(guc->submission_state.guc_ids_bitmap, ce->guc_id.id, order_base_2(ce->parallel.number_children + 1)); - else + } else { + --guc->submission_state.guc_ids_in_use; ida_simple_remove(&guc->submission_state.guc_ids, ce->guc_id.id); + } clr_ctx_id_mapping(guc, ce->guc_id.id); set_context_guc_id_invalid(ce); } @@ -3007,41 +3044,104 @@ guc_context_revoke(struct intel_context *ce, struct i915_request *rq, } } -static void guc_context_sched_disable(struct intel_context *ce) +static void do_sched_disable(struct intel_guc *guc, struct intel_context *ce, + unsigned long flags) + __releases(ce->guc_state.lock) { - struct intel_guc *guc = ce_to_guc(ce); - unsigned long flags; struct intel_runtime_pm *runtime_pm = &ce->engine->gt->i915->runtime_pm; intel_wakeref_t wakeref; u16 guc_id; + lockdep_assert_held(&ce->guc_state.lock); + guc_id = prep_context_pending_disable(ce); + + spin_unlock_irqrestore(&ce->guc_state.lock, flags); + + with_intel_runtime_pm(runtime_pm, wakeref) + __guc_context_sched_disable(guc, ce, guc_id); +} + +static bool bypass_sched_disable(struct intel_guc *guc, + struct intel_context *ce) +{ + lockdep_assert_held(&ce->guc_state.lock); GEM_BUG_ON(intel_context_is_child(ce)); + if (submission_disabled(guc) || context_guc_id_invalid(ce) || + !ctx_id_mapped(guc, ce->guc_id.id)) { + clr_context_enabled(ce); + return true; + } + + return !context_enabled(ce); +} + +static void __delay_sched_disable(struct work_struct *wrk) +{ + struct intel_context *ce = + container_of(wrk, typeof(*ce), guc_state.sched_disable_delay_work.work); + struct intel_guc *guc = ce_to_guc(ce); + unsigned long flags; + spin_lock_irqsave(&ce->guc_state.lock, flags); + if (bypass_sched_disable(guc, ce)) { + spin_unlock_irqrestore(&ce->guc_state.lock, flags); + intel_context_sched_disable_unpin(ce); + } else { + do_sched_disable(guc, ce, flags); + } +} + +static bool guc_id_pressure(struct intel_guc *guc, struct intel_context *ce) +{ /* - * We have to check if the context has been disabled by another thread, - * check if submssion has been disabled to seal a race with reset and - * finally check if any more requests have been committed to the - * context ensursing that a request doesn't slip through the - * 'context_pending_disable' fence. + * parent contexts are perma-pinned, if we are unpinning do schedule + * disable immediately. */ - if (unlikely(!context_enabled(ce) || submission_disabled(guc) || - context_has_committed_requests(ce))) { - clr_context_enabled(ce); + if (intel_context_is_parent(ce)) + return true; + + /* + * If we are beyond the threshold for avail guc_ids, do schedule disable immediately. + */ + return guc->submission_state.guc_ids_in_use > + guc->submission_state.sched_disable_gucid_threshold; +} + +static void guc_context_sched_disable(struct intel_context *ce) +{ + struct intel_guc *guc = ce_to_guc(ce); + u64 delay = guc->submission_state.sched_disable_delay_ms; + unsigned long flags; + + spin_lock_irqsave(&ce->guc_state.lock, flags); + + if (bypass_sched_disable(guc, ce)) { + spin_unlock_irqrestore(&ce->guc_state.lock, flags); + intel_context_sched_disable_unpin(ce); + } else if (!intel_context_is_closed(ce) && !guc_id_pressure(guc, ce) && + delay) { spin_unlock_irqrestore(&ce->guc_state.lock, flags); - goto unpin; + mod_delayed_work(system_unbound_wq, + &ce->guc_state.sched_disable_delay_work, + msecs_to_jiffies(delay)); + } else { + do_sched_disable(guc, ce, flags); } - guc_id = prep_context_pending_disable(ce); +} - spin_unlock_irqrestore(&ce->guc_state.lock, flags); +static void guc_context_close(struct intel_context *ce) +{ + unsigned long flags; - with_intel_runtime_pm(runtime_pm, wakeref) - __guc_context_sched_disable(guc, ce, guc_id); + if (test_bit(CONTEXT_GUC_INIT, &ce->flags) && + cancel_delayed_work(&ce->guc_state.sched_disable_delay_work)) + __delay_sched_disable(&ce->guc_state.sched_disable_delay_work.work); - return; -unpin: - intel_context_sched_disable_unpin(ce); + spin_lock_irqsave(&ce->guc_state.lock, flags); + set_context_close_done(ce); + spin_unlock_irqrestore(&ce->guc_state.lock, flags); } static inline void guc_lrc_desc_unpin(struct intel_context *ce) @@ -3360,6 +3460,8 @@ static void remove_from_context(struct i915_request *rq) static const struct intel_context_ops guc_context_ops = { .alloc = guc_context_alloc, + .close = guc_context_close, + .pre_pin = guc_context_pre_pin, .pin = guc_context_pin, .unpin = guc_context_unpin, @@ -3442,6 +3544,10 @@ static void guc_context_init(struct intel_context *ce) rcu_read_unlock(); ce->guc_state.prio = map_i915_prio_to_guc_prio(prio); + + INIT_DELAYED_WORK(&ce->guc_state.sched_disable_delay_work, + __delay_sched_disable); + set_bit(CONTEXT_GUC_INIT, &ce->flags); } @@ -3479,6 +3585,26 @@ static int guc_request_alloc(struct i915_request *rq) if (unlikely(!test_bit(CONTEXT_GUC_INIT, &ce->flags))) guc_context_init(ce); + /* + * If the context gets closed while the execbuf is ongoing, the context + * close code will race with the below code to cancel the delayed work. + * If the context close wins the race and cancels the work, it will + * immediately call the sched disable (see guc_context_close), so there + * is a chance we can get past this check while the sched_disable code + * is being executed. To make sure that code completes before we check + * the status further down, we wait for the close process to complete. + * Else, this code path could send a request down thinking that the + * context is still in a schedule-enable mode while the GuC ends up + * dropping the request completely because the disable did go from the + * context_close path right to GuC just prior. In the event the CT is + * full, we could potentially need to wait up to 1.5 seconds. + */ + if (cancel_delayed_work_sync(&ce->guc_state.sched_disable_delay_work)) + intel_context_sched_disable_unpin(ce); + else if (intel_context_is_closed(ce)) + if (wait_for(context_close_done(ce), 1500)) + drm_warn(&guc_to_gt(guc)->i915->drm, + "timed out waiting on context sched close before realloc\n"); /* * Call pin_guc_id here rather than in the pinning step as with * dma_resv, contexts can be repeatedly pinned / unpinned trashing the @@ -3609,6 +3735,8 @@ static int guc_virtual_context_alloc(struct intel_context *ce) static const struct intel_context_ops virtual_guc_context_ops = { .alloc = guc_virtual_context_alloc, + .close = guc_context_close, + .pre_pin = guc_virtual_context_pre_pin, .pin = guc_virtual_context_pin, .unpin = guc_virtual_context_unpin, @@ -3698,6 +3826,8 @@ static void guc_child_context_destroy(struct kref *kref) static const struct intel_context_ops virtual_parent_context_ops = { .alloc = guc_virtual_context_alloc, + .close = guc_context_close, + .pre_pin = guc_context_pre_pin, .pin = guc_parent_context_pin, .unpin = guc_parent_context_unpin, @@ -4321,6 +4451,26 @@ static bool __guc_submission_selected(struct intel_guc *guc) return i915->params.enable_guc & ENABLE_GUC_SUBMISSION; } +int intel_guc_sched_disable_gucid_threshold_max(struct intel_guc *guc) +{ + return guc->submission_state.num_guc_ids - NUMBER_MULTI_LRC_GUC_ID(guc); +} + +/* + * This default value of 33 milisecs (+1 milisec round up) ensures 30fps or higher + * workloads are able to enjoy the latency reduction when delaying the schedule-disable + * operation. This matches the 30fps game-render + encode (real world) workload this + * knob was tested against. + */ +#define SCHED_DISABLE_DELAY_MS 34 + +/* + * A threshold of 75% is a reasonable starting point considering that real world apps + * generally don't get anywhere near this. + */ +#define NUM_SCHED_DISABLE_GUCIDS_DEFAULT_THRESHOLD(__guc) \ + (((intel_guc_sched_disable_gucid_threshold_max(guc)) * 3) / 4) + void intel_guc_submission_init_early(struct intel_guc *guc) { xa_init_flags(&guc->context_lookup, XA_FLAGS_LOCK_IRQ); @@ -4337,7 +4487,10 @@ void intel_guc_submission_init_early(struct intel_guc *guc) spin_lock_init(&guc->timestamp.lock); INIT_DELAYED_WORK(&guc->timestamp.work, guc_timestamp_ping); + guc->submission_state.sched_disable_delay_ms = SCHED_DISABLE_DELAY_MS; guc->submission_state.num_guc_ids = GUC_MAX_CONTEXT_ID; + guc->submission_state.sched_disable_gucid_threshold = + NUM_SCHED_DISABLE_GUCIDS_DEFAULT_THRESHOLD(guc); guc->submission_supported = __guc_submission_supported(guc); guc->submission_selected = __guc_submission_selected(guc); } diff --git a/drivers/gpu/drm/i915/i915_selftest.h b/drivers/gpu/drm/i915/i915_selftest.h index f54de0499be7..bdf3e22c0a34 100644 --- a/drivers/gpu/drm/i915/i915_selftest.h +++ b/drivers/gpu/drm/i915/i915_selftest.h @@ -92,12 +92,14 @@ int __i915_subtests(const char *caller, T, ARRAY_SIZE(T), data) #define i915_live_subtests(T, data) ({ \ typecheck(struct drm_i915_private *, data); \ + (data)->gt[0]->uc.guc.submission_state.sched_disable_delay_ms = 0; \ __i915_subtests(__func__, \ __i915_live_setup, __i915_live_teardown, \ T, ARRAY_SIZE(T), data); \ }) #define intel_gt_live_subtests(T, data) ({ \ typecheck(struct intel_gt *, data); \ + (data)->uc.guc.submission_state.sched_disable_delay_ms = 0; \ __i915_subtests(__func__, \ __intel_gt_live_setup, __intel_gt_live_teardown, \ T, ARRAY_SIZE(T), data); \ -- cgit From a7ac9d84b82c74c50eb11ed5eba7496291aebf6a Mon Sep 17 00:00:00 2001 From: Alan Previn Date: Thu, 6 Oct 2022 15:51:21 -0700 Subject: drm/i915/guc: Remove intel_context:number_committed_requests counter With the introduction of the delayed disable-sched behavior, we use the GuC's xarray of valid guc-id's as a way to identify if new requests had been added to a context when the said context is being checked for closure. Additionally that prior change also closes the race for when a new incoming request fails to cancel the pending delayed disable-sched worker. With these two complementary checks, we see no more use for intel_context:guc_state:number_committed_requests. Signed-off-by: Alan Previn Reviewed-by: John Harrison Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20221006225121.826257-3-alan.previn.teres.alexis@intel.com --- drivers/gpu/drm/i915/gt/intel_context_types.h | 2 -- drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c | 23 ----------------------- 2 files changed, 25 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_context_types.h b/drivers/gpu/drm/i915/gt/intel_context_types.h index 6a49fa7e119f..e36670f2e626 100644 --- a/drivers/gpu/drm/i915/gt/intel_context_types.h +++ b/drivers/gpu/drm/i915/gt/intel_context_types.h @@ -199,8 +199,6 @@ struct intel_context { * context's submissions is complete. */ struct i915_sw_fence blocked; - /** @number_committed_requests: number of committed requests */ - int number_committed_requests; /** @requests: list of active requests on this context */ struct list_head requests; /** @prio: the context's current guc priority */ diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index e8c934f8aa3c..4ccb29f9ac55 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -370,25 +370,6 @@ static inline void decr_context_blocked(struct intel_context *ce) ce->guc_state.sched_state -= SCHED_STATE_BLOCKED; } -static inline bool context_has_committed_requests(struct intel_context *ce) -{ - return !!ce->guc_state.number_committed_requests; -} - -static inline void incr_context_committed_requests(struct intel_context *ce) -{ - lockdep_assert_held(&ce->guc_state.lock); - ++ce->guc_state.number_committed_requests; - GEM_BUG_ON(ce->guc_state.number_committed_requests < 0); -} - -static inline void decr_context_committed_requests(struct intel_context *ce) -{ - lockdep_assert_held(&ce->guc_state.lock); - --ce->guc_state.number_committed_requests; - GEM_BUG_ON(ce->guc_state.number_committed_requests < 0); -} - static struct intel_context * request_to_scheduling_context(struct i915_request *rq) { @@ -3180,7 +3161,6 @@ static void __guc_context_destroy(struct intel_context *ce) ce->guc_state.prio_count[GUC_CLIENT_PRIORITY_HIGH] || ce->guc_state.prio_count[GUC_CLIENT_PRIORITY_KMD_NORMAL] || ce->guc_state.prio_count[GUC_CLIENT_PRIORITY_NORMAL]); - GEM_BUG_ON(ce->guc_state.number_committed_requests); lrc_fini(ce); intel_context_fini(ce); @@ -3449,8 +3429,6 @@ static void remove_from_context(struct i915_request *rq) guc_prio_fini(rq, ce); - decr_context_committed_requests(ce); - spin_unlock_irq(&ce->guc_state.lock); atomic_dec(&ce->guc_id.ref); @@ -3659,7 +3637,6 @@ out: list_add_tail(&rq->guc_fence_link, &ce->guc_state.fences); } - incr_context_committed_requests(ce); spin_unlock_irqrestore(&ce->guc_state.lock, flags); return 0; -- cgit From b0feda9ce756aa62dbfc29372f819734ffa195f9 Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Mon, 24 Oct 2022 11:19:46 +0100 Subject: Revert "drm/i915/uapi: expose GTT alignment" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The process for merging uAPI is to have UMD side ready and reviewed and merged before merging. Revert for now until that is ready. This reverts commit d54576a074a29d4901d0a693cd84e1a89057f694. Reported-by: Joonas Lahtinen Signed-off-by: Matthew Auld Cc: Lionel Landwerlin Cc: Michal Mrozek Cc: Thomas Hellström Cc: Stuart Summers Cc: Jordan Justen Cc: Yang A Shi Cc: Nirmoy Das Cc: Niranjana Vishwanathapura Reviewed-by: Nirmoy Das Link: https://patchwork.freedesktop.org/patch/msgid/20221024101946.28974-1-matthew.auld@intel.com --- drivers/gpu/drm/i915/i915_query.c | 1 - include/uapi/drm/i915_drm.h | 29 ++--------------------------- 2 files changed, 2 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_query.c b/drivers/gpu/drm/i915/i915_query.c index 111377f210ed..6ec9c9fb7b0d 100644 --- a/drivers/gpu/drm/i915/i915_query.c +++ b/drivers/gpu/drm/i915/i915_query.c @@ -498,7 +498,6 @@ static int query_memregion_info(struct drm_i915_private *i915, info.region.memory_class = mr->type; info.region.memory_instance = mr->instance; info.probed_size = mr->total; - info.gtt_alignment = mr->min_page_size; if (mr->type == INTEL_MEMORY_LOCAL) info.probed_cpu_visible_size = mr->io_size; diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index 2e613109356b..08d69e36fb66 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -3346,33 +3346,8 @@ struct drm_i915_memory_region_info { /** @region: The class:instance pair encoding */ struct drm_i915_gem_memory_class_instance region; - union { - /** @rsvd0: MBZ */ - __u32 rsvd0; - /** - * @gtt_alignment: - * - * The minimum required GTT alignment for this type of memory. - * When allocating a GTT address it must be aligned to this - * value or larger. On some platforms the kernel might opt to - * using 64K pages for I915_MEMORY_CLASS_DEVICE, where 64K GTT - * pages can then be used if we also use 64K GTT alignment. - * - * NOTE: If this is zero then this must be an older - * kernel which lacks support for this field. - * - * Side note: For larger objects (especially for - * I915_MEMORY_CLASS_DEVICE), like 2M+ in size, userspace should - * consider potentially bumping the GTT alignment to say 2M, - * which could potentially increase the likelihood of the kernel - * being able to utilise 2M GTT pages underneath, if the layout - * of the physical pages allows it. On some configurations we - * can then also use a more efficient page-table layout, if we - * can't use the more desirable 2M GTT page, so long as we know - * that the entire page-table will be used by this object. - */ - __u32 gtt_alignment; - }; + /** @rsvd0: MBZ */ + __u32 rsvd0; /** * @probed_size: Memory probed by the driver -- cgit From 78a07fe777c42800bd1adaec12abe5dcee43919e Mon Sep 17 00:00:00 2001 From: Robert Beckett Date: Thu, 20 Oct 2022 13:03:08 +0200 Subject: drm/i915: stop abusing swiotlb_max_segment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit swiotlb_max_segment used to return either the maximum size that swiotlb could bounce, or for Xen PV PAGE_SIZE even if swiotlb could bounce buffer larger mappings. This made i915 on Xen PV work as it bypasses the coherency aspect of the DMA API and can't cope with bounce buffering and this avoided bounce buffering for the Xen/PV case. So instead of adding this hack back, check for Xen/PV directly in i915 for the Xen case and otherwise use the proper DMA API helper to query the maximum mapping size. Replace swiotlb_max_segment() calls with dma_max_mapping_size(). In i915_gem_object_get_pages_internal() no longer consider max_segment only if CONFIG_SWIOTLB is enabled. There can be other (iommu related) causes of specific max segment sizes. Fixes: a2daa27c0c61 ("swiotlb: simplify swiotlb_max_segment") Reported-by: Marek Marczykowski-Górecki Signed-off-by: Robert Beckett Signed-off-by: Christoph Hellwig [hch: added the Xen hack, rewrote the changelog] Reviewed-by: Tvrtko Ursulin Signed-off-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20221020110308.1582518-1-hch@lst.de --- drivers/gpu/drm/i915/gem/i915_gem_internal.c | 19 ++++------------ drivers/gpu/drm/i915/gem/i915_gem_shmem.c | 2 +- drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 4 ++-- drivers/gpu/drm/i915/gem/i915_gem_userptr.c | 2 +- drivers/gpu/drm/i915/i915_scatterlist.h | 34 +++++++++++++++++----------- 5 files changed, 29 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_internal.c b/drivers/gpu/drm/i915/gem/i915_gem_internal.c index c698f95af15f..629acb403a2c 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_internal.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_internal.c @@ -6,7 +6,6 @@ #include #include -#include #include "i915_drv.h" #include "i915_gem.h" @@ -38,22 +37,12 @@ static int i915_gem_object_get_pages_internal(struct drm_i915_gem_object *obj) struct scatterlist *sg; unsigned int sg_page_sizes; unsigned int npages; - int max_order; + int max_order = MAX_ORDER; + unsigned int max_segment; gfp_t gfp; - max_order = MAX_ORDER; -#ifdef CONFIG_SWIOTLB - if (is_swiotlb_active(obj->base.dev->dev)) { - unsigned int max_segment; - - max_segment = swiotlb_max_segment(); - if (max_segment) { - max_segment = max_t(unsigned int, max_segment, - PAGE_SIZE) >> PAGE_SHIFT; - max_order = min(max_order, ilog2(max_segment)); - } - } -#endif + max_segment = i915_sg_segment_size(i915->drm.dev) >> PAGE_SHIFT; + max_order = min(max_order, get_order(max_segment)); gfp = GFP_KERNEL | __GFP_HIGHMEM | __GFP_RECLAIMABLE; if (IS_I965GM(i915) || IS_I965G(i915)) { diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c index f42ca1179f37..11125c32dd35 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c @@ -194,7 +194,7 @@ static int shmem_get_pages(struct drm_i915_gem_object *obj) struct intel_memory_region *mem = obj->mm.region; struct address_space *mapping = obj->base.filp->f_mapping; const unsigned long page_count = obj->base.size / PAGE_SIZE; - unsigned int max_segment = i915_sg_segment_size(); + unsigned int max_segment = i915_sg_segment_size(i915->drm.dev); struct sg_table *st; struct sgt_iter sgt_iter; struct page *page; diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c index 84c91a4228a1..e4ecfd3e8ee3 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c @@ -189,7 +189,7 @@ static int i915_ttm_tt_shmem_populate(struct ttm_device *bdev, struct drm_i915_private *i915 = container_of(bdev, typeof(*i915), bdev); struct intel_memory_region *mr = i915->mm.regions[INTEL_MEMORY_SYSTEM]; struct i915_ttm_tt *i915_tt = container_of(ttm, typeof(*i915_tt), ttm); - const unsigned int max_segment = i915_sg_segment_size(); + const unsigned int max_segment = i915_sg_segment_size(i915->drm.dev); const size_t size = (size_t)ttm->num_pages << PAGE_SHIFT; struct file *filp = i915_tt->filp; struct sgt_iter sgt_iter; @@ -538,7 +538,7 @@ static struct i915_refct_sgt *i915_ttm_tt_get_st(struct ttm_tt *ttm) ret = sg_alloc_table_from_pages_segment(st, ttm->pages, ttm->num_pages, 0, (unsigned long)ttm->num_pages << PAGE_SHIFT, - i915_sg_segment_size(), GFP_KERNEL); + i915_sg_segment_size(i915_tt->dev), GFP_KERNEL); if (ret) { st->sgl = NULL; return ERR_PTR(ret); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_userptr.c b/drivers/gpu/drm/i915/gem/i915_gem_userptr.c index 1c60818ed2f1..9b7d101cf47a 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_userptr.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_userptr.c @@ -129,7 +129,7 @@ static void i915_gem_object_userptr_drop_ref(struct drm_i915_gem_object *obj) static int i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj) { const unsigned long num_pages = obj->base.size >> PAGE_SHIFT; - unsigned int max_segment = i915_sg_segment_size(); + unsigned int max_segment = i915_sg_segment_size(obj->base.dev->dev); struct sg_table *st; unsigned int sg_page_sizes; struct page **pvec; diff --git a/drivers/gpu/drm/i915/i915_scatterlist.h b/drivers/gpu/drm/i915/i915_scatterlist.h index 9ddb3e743a3e..b0a1db44f895 100644 --- a/drivers/gpu/drm/i915/i915_scatterlist.h +++ b/drivers/gpu/drm/i915/i915_scatterlist.h @@ -9,7 +9,8 @@ #include #include -#include +#include +#include #include "i915_gem.h" @@ -127,19 +128,26 @@ static inline unsigned int i915_sg_dma_sizes(struct scatterlist *sg) return page_sizes; } -static inline unsigned int i915_sg_segment_size(void) +static inline unsigned int i915_sg_segment_size(struct device *dev) { - unsigned int size = swiotlb_max_segment(); - - if (size == 0) - size = UINT_MAX; - - size = rounddown(size, PAGE_SIZE); - /* swiotlb_max_segment_size can return 1 byte when it means one page. */ - if (size < PAGE_SIZE) - size = PAGE_SIZE; - - return size; + size_t max = min_t(size_t, UINT_MAX, dma_max_mapping_size(dev)); + + /* + * For Xen PV guests pages aren't contiguous in DMA (machine) address + * space. The DMA API takes care of that both in dma_alloc_* (by + * calling into the hypervisor to make the pages contiguous) and in + * dma_map_* (by bounce buffering). But i915 abuses ignores the + * coherency aspects of the DMA API and thus can't cope with bounce + * buffering actually happening, so add a hack here to force small + * allocations and mappings when running in PV mode on Xen. + * + * Note this will still break if bounce buffering is required for other + * reasons, like confidential computing hypervisors or PCIe root ports + * with addressing limitations. + */ + if (xen_pv_domain()) + max = PAGE_SIZE; + return round_down(max, PAGE_SIZE); } bool i915_sg_trim(struct sg_table *orig_st); -- cgit From e3c92eb4a84fb0f00442e6b5cabf4f11b0eaaf41 Mon Sep 17 00:00:00 2001 From: Somalapuram Amaranath Date: Thu, 27 Oct 2022 14:42:37 +0530 Subject: drm/ttm: rework on ttm_resource to use size_t type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change ttm_resource structure from num_pages to size_t size in bytes. v1 -> v2: change PFN_UP(dst_mem->size) to ttm->num_pages v1 -> v2: change bo->resource->size to bo->base.size at some places v1 -> v2: remove the local variable v1 -> v2: cleanup cmp_size_smaller_first() v2 -> v3: adding missing PFN_UP in ttm_bo_vm_fault_reserved Signed-off-by: Somalapuram Amaranath Link: https://patchwork.freedesktop.org/patch/msgid/20221027091237.983582-1-Amaranath.Somalapuram@amd.com Reviewed-by: Christian König Signed-off-by: Christian König --- drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 3 ++- drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h | 4 ++-- drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 6 +++--- drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c | 8 ++++---- drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 2 +- drivers/gpu/drm/i915/i915_scatterlist.c | 4 ++-- drivers/gpu/drm/i915/i915_ttm_buddy_manager.c | 12 ++++++------ drivers/gpu/drm/i915/intel_region_ttm.c | 2 +- drivers/gpu/drm/nouveau/nouveau_bo.c | 4 ++-- drivers/gpu/drm/nouveau/nouveau_bo0039.c | 4 ++-- drivers/gpu/drm/nouveau/nouveau_bo5039.c | 2 +- drivers/gpu/drm/nouveau/nouveau_bo74c1.c | 2 +- drivers/gpu/drm/nouveau/nouveau_bo85b5.c | 4 ++-- drivers/gpu/drm/nouveau/nouveau_bo9039.c | 4 ++-- drivers/gpu/drm/nouveau/nouveau_bo90b5.c | 4 ++-- drivers/gpu/drm/nouveau/nouveau_boa0b5.c | 2 +- drivers/gpu/drm/nouveau/nouveau_gem.c | 5 ++--- drivers/gpu/drm/nouveau/nouveau_mem.c | 4 ++-- drivers/gpu/drm/nouveau/nouveau_ttm.c | 2 +- drivers/gpu/drm/radeon/radeon_cs.c | 7 +++++-- drivers/gpu/drm/radeon/radeon_object.c | 4 ++-- drivers/gpu/drm/radeon/radeon_trace.h | 2 +- drivers/gpu/drm/radeon/radeon_ttm.c | 4 ++-- drivers/gpu/drm/ttm/ttm_bo.c | 3 --- drivers/gpu/drm/ttm/ttm_bo_util.c | 6 +++--- drivers/gpu/drm/ttm/ttm_bo_vm.c | 4 ++-- drivers/gpu/drm/ttm/ttm_range_manager.c | 2 +- drivers/gpu/drm/ttm/ttm_resource.c | 14 ++++++-------- drivers/gpu/drm/vmwgfx/vmwgfx_blit.c | 4 ++-- drivers/gpu/drm/vmwgfx/vmwgfx_bo.c | 6 +++--- drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c | 6 +++--- drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c | 6 +++--- include/drm/ttm/ttm_resource.h | 4 ++-- 37 files changed, 78 insertions(+), 80 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c index 1f3302aebeff..44367f03316f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c @@ -144,7 +144,7 @@ static int amdgpu_gtt_mgr_new(struct ttm_resource_manager *man, node->base.start = node->mm_nodes[0].start; } else { node->mm_nodes[0].start = 0; - node->mm_nodes[0].size = node->base.num_pages; + node->mm_nodes[0].size = PFN_UP(node->base.size); node->base.start = AMDGPU_BO_INVALID_OFFSET; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 2e8f6cd7a729..974e85d8b6cc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -542,6 +542,7 @@ int amdgpu_bo_create(struct amdgpu_device *adev, /* GWS and OA don't need any alignment. */ page_align = bp->byte_align; size <<= PAGE_SHIFT; + } else if (bp->domain & AMDGPU_GEM_DOMAIN_GDS) { /* Both size and alignment must be a multiple of 4. */ page_align = ALIGN(bp->byte_align, 4); @@ -776,7 +777,7 @@ int amdgpu_bo_kmap(struct amdgpu_bo *bo, void **ptr) return 0; } - r = ttm_bo_kmap(&bo->tbo, 0, bo->tbo.resource->num_pages, &bo->kmap); + r = ttm_bo_kmap(&bo->tbo, 0, PFN_UP(bo->tbo.base.size), &bo->kmap); if (r) return r; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h index 6546552e596c..5c4f93ee0c57 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h @@ -62,7 +62,7 @@ static inline void amdgpu_res_first(struct ttm_resource *res, if (!res) goto fallback; - BUG_ON(start + size > res->num_pages << PAGE_SHIFT); + BUG_ON(start + size > res->size); cur->mem_type = res->mem_type; @@ -110,7 +110,7 @@ fallback: cur->size = size; cur->remaining = size; cur->node = NULL; - WARN_ON(res && start + size > res->num_pages << PAGE_SHIFT); + WARN_ON(res && start + size > res->size); return; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h index 5e6ddc7e101c..677ad2016976 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h @@ -127,7 +127,7 @@ TRACE_EVENT(amdgpu_bo_create, TP_fast_assign( __entry->bo = bo; - __entry->pages = bo->tbo.resource->num_pages; + __entry->pages = PFN_UP(bo->tbo.resource->size); __entry->type = bo->tbo.resource->mem_type; __entry->prefer = bo->preferred_domains; __entry->allow = bo->allowed_domains; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index dc262d2c2925..36066965346f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -381,7 +381,7 @@ static int amdgpu_move_blit(struct ttm_buffer_object *bo, dst.offset = 0; r = amdgpu_ttm_copy_mem_to_mem(adev, &src, &dst, - new_mem->num_pages << PAGE_SHIFT, + new_mem->size, amdgpu_bo_encrypted(abo), bo->base.resv, &fence); if (r) @@ -424,7 +424,7 @@ error: static bool amdgpu_mem_visible(struct amdgpu_device *adev, struct ttm_resource *mem) { - u64 mem_size = (u64)mem->num_pages << PAGE_SHIFT; + u64 mem_size = (u64)mem->size; struct amdgpu_res_cursor cursor; u64 end; @@ -568,7 +568,7 @@ static int amdgpu_ttm_io_mem_reserve(struct ttm_device *bdev, struct ttm_resource *mem) { struct amdgpu_device *adev = amdgpu_ttm_adev(bdev); - size_t bus_size = (size_t)mem->num_pages << PAGE_SHIFT; + size_t bus_size = (size_t)mem->size; switch (mem->mem_type) { case TTM_PL_SYSTEM: diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c index 73a517bcf5c1..18c1a173d187 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c @@ -439,7 +439,7 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man, /* Allocate blocks in desired range */ vres->flags |= DRM_BUDDY_RANGE_ALLOCATION; - remaining_size = (u64)vres->base.num_pages << PAGE_SHIFT; + remaining_size = (u64)vres->base.size; mutex_lock(&mgr->lock); while (remaining_size) { @@ -498,7 +498,7 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man, LIST_HEAD(temp); trim_list = &vres->blocks; - original_size = (u64)vres->base.num_pages << PAGE_SHIFT; + original_size = (u64)vres->base.size; /* * If size value is rounded up to min_block_size, trim the last @@ -533,8 +533,8 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man, amdgpu_vram_mgr_block_size(block); start >>= PAGE_SHIFT; - if (start > vres->base.num_pages) - start -= vres->base.num_pages; + if (start > PFN_UP(vres->base.size)) + start -= PFN_UP(vres->base.size); else start = 0; vres->base.start = max(vres->base.start, start); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c index 4f861782c3e8..7a1e92c11946 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c @@ -649,7 +649,7 @@ bool i915_ttm_resource_mappable(struct ttm_resource *res) if (!i915_ttm_cpu_maps_iomem(res)) return true; - return bman_res->used_visible_size == bman_res->base.num_pages; + return bman_res->used_visible_size == PFN_UP(bman_res->base.size); } static int i915_ttm_io_mem_reserve(struct ttm_device *bdev, struct ttm_resource *mem) diff --git a/drivers/gpu/drm/i915/i915_scatterlist.c b/drivers/gpu/drm/i915/i915_scatterlist.c index dcc081874ec8..114e5e39aa72 100644 --- a/drivers/gpu/drm/i915/i915_scatterlist.c +++ b/drivers/gpu/drm/i915/i915_scatterlist.c @@ -158,7 +158,7 @@ struct i915_refct_sgt *i915_rsgt_from_buddy_resource(struct ttm_resource *res, u32 page_alignment) { struct i915_ttm_buddy_resource *bman_res = to_ttm_buddy_resource(res); - const u64 size = res->num_pages << PAGE_SHIFT; + const u64 size = res->size; const u32 max_segment = round_down(UINT_MAX, page_alignment); struct drm_buddy *mm = bman_res->mm; struct list_head *blocks = &bman_res->blocks; @@ -177,7 +177,7 @@ struct i915_refct_sgt *i915_rsgt_from_buddy_resource(struct ttm_resource *res, i915_refct_sgt_init(rsgt, size); st = &rsgt->table; - if (sg_alloc_table(st, res->num_pages, GFP_KERNEL)) { + if (sg_alloc_table(st, PFN_UP(res->size), GFP_KERNEL)) { i915_refct_sgt_put(rsgt); return ERR_PTR(-ENOMEM); } diff --git a/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c b/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c index e19452f0e100..7e611476c7a4 100644 --- a/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c +++ b/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c @@ -62,8 +62,8 @@ static int i915_ttm_buddy_man_alloc(struct ttm_resource_manager *man, if (place->fpfn || lpfn != man->size) bman_res->flags |= DRM_BUDDY_RANGE_ALLOCATION; - GEM_BUG_ON(!bman_res->base.num_pages); - size = bman_res->base.num_pages << PAGE_SHIFT; + GEM_BUG_ON(!bman_res->base.size); + size = bman_res->base.size; min_page_size = bman->default_page_size; if (bo->page_alignment) @@ -72,7 +72,7 @@ static int i915_ttm_buddy_man_alloc(struct ttm_resource_manager *man, GEM_BUG_ON(min_page_size < mm->chunk_size); GEM_BUG_ON(!IS_ALIGNED(size, min_page_size)); - if (place->fpfn + bman_res->base.num_pages != place->lpfn && + if (place->fpfn + PFN_UP(bman_res->base.size) != place->lpfn && place->flags & TTM_PL_FLAG_CONTIGUOUS) { unsigned long pages; @@ -108,7 +108,7 @@ static int i915_ttm_buddy_man_alloc(struct ttm_resource_manager *man, goto err_free_blocks; if (place->flags & TTM_PL_FLAG_CONTIGUOUS) { - u64 original_size = (u64)bman_res->base.num_pages << PAGE_SHIFT; + u64 original_size = (u64)bman_res->base.size; drm_buddy_block_trim(mm, original_size, @@ -116,7 +116,7 @@ static int i915_ttm_buddy_man_alloc(struct ttm_resource_manager *man, } if (lpfn <= bman->visible_size) { - bman_res->used_visible_size = bman_res->base.num_pages; + bman_res->used_visible_size = PFN_UP(bman_res->base.size); } else { struct drm_buddy_block *block; @@ -228,7 +228,7 @@ static bool i915_ttm_buddy_man_compatible(struct ttm_resource_manager *man, if (!place->fpfn && place->lpfn == i915_ttm_buddy_man_visible_size(man)) - return bman_res->used_visible_size == res->num_pages; + return bman_res->used_visible_size == PFN_UP(res->size); /* Check each drm buddy block individually */ list_for_each_entry(block, &bman_res->blocks, link) { diff --git a/drivers/gpu/drm/i915/intel_region_ttm.c b/drivers/gpu/drm/i915/intel_region_ttm.c index 575d67bc6ffe..cf89d0c2a2d9 100644 --- a/drivers/gpu/drm/i915/intel_region_ttm.c +++ b/drivers/gpu/drm/i915/intel_region_ttm.c @@ -244,7 +244,7 @@ void intel_region_ttm_resource_free(struct intel_memory_region *mem, struct ttm_resource_manager *man = mem->region_private; struct ttm_buffer_object mock_bo = {}; - mock_bo.base.size = res->num_pages << PAGE_SHIFT; + mock_bo.base.size = res->size; mock_bo.bdev = &mem->i915->bdev; res->bo = &mock_bo; diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 126b3c6e12f9..813937ad1dc2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -532,7 +532,7 @@ nouveau_bo_map(struct nouveau_bo *nvbo) if (ret) return ret; - ret = ttm_bo_kmap(&nvbo->bo, 0, nvbo->bo.resource->num_pages, &nvbo->kmap); + ret = ttm_bo_kmap(&nvbo->bo, 0, PFN_UP(nvbo->bo.base.size), &nvbo->kmap); ttm_bo_unreserve(&nvbo->bo); return ret; @@ -1236,7 +1236,7 @@ vm_fault_t nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo) } else { /* make sure bo is in mappable vram */ if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA || - bo->resource->start + bo->resource->num_pages < mappable) + bo->resource->start + PFN_UP(bo->resource->size) < mappable) return 0; for (i = 0; i < nvbo->placement.num_placement; ++i) { diff --git a/drivers/gpu/drm/nouveau/nouveau_bo0039.c b/drivers/gpu/drm/nouveau/nouveau_bo0039.c index 7390132129fe..e2ce44adaa5c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo0039.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo0039.c @@ -52,7 +52,7 @@ nv04_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, u32 src_offset = old_reg->start << PAGE_SHIFT; u32 dst_ctxdma = nouveau_bo_mem_ctxdma(bo, chan, new_reg); u32 dst_offset = new_reg->start << PAGE_SHIFT; - u32 page_count = new_reg->num_pages; + u32 page_count = PFN_UP(new_reg->size); int ret; ret = PUSH_WAIT(push, 3); @@ -62,7 +62,7 @@ nv04_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, PUSH_MTHD(push, NV039, SET_CONTEXT_DMA_BUFFER_IN, src_ctxdma, SET_CONTEXT_DMA_BUFFER_OUT, dst_ctxdma); - page_count = new_reg->num_pages; + page_count = PFN_UP(new_reg->size); while (page_count) { int line_count = (page_count > 2047) ? 2047 : page_count; diff --git a/drivers/gpu/drm/nouveau/nouveau_bo5039.c b/drivers/gpu/drm/nouveau/nouveau_bo5039.c index 4c75c7b3804c..c6cf3629a9f9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo5039.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo5039.c @@ -41,7 +41,7 @@ nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, { struct nouveau_mem *mem = nouveau_mem(old_reg); struct nvif_push *push = chan->chan.push; - u64 length = (new_reg->num_pages << PAGE_SHIFT); + u64 length = new_reg->size; u64 src_offset = mem->vma[0].addr; u64 dst_offset = mem->vma[1].addr; int src_tiled = !!mem->kind; diff --git a/drivers/gpu/drm/nouveau/nouveau_bo74c1.c b/drivers/gpu/drm/nouveau/nouveau_bo74c1.c index ed6c09d67840..9b7ba31fae13 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo74c1.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo74c1.c @@ -44,7 +44,7 @@ nv84_bo_move_exec(struct nouveau_channel *chan, struct ttm_buffer_object *bo, if (ret) return ret; - PUSH_NVSQ(push, NV74C1, 0x0304, new_reg->num_pages << PAGE_SHIFT, + PUSH_NVSQ(push, NV74C1, 0x0304, new_reg->size, 0x0308, upper_32_bits(mem->vma[0].addr), 0x030c, lower_32_bits(mem->vma[0].addr), 0x0310, upper_32_bits(mem->vma[1].addr), diff --git a/drivers/gpu/drm/nouveau/nouveau_bo85b5.c b/drivers/gpu/drm/nouveau/nouveau_bo85b5.c index dec29b2d8bb2..a15a38a87a95 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo85b5.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo85b5.c @@ -44,10 +44,10 @@ nva3_bo_move_copy(struct nouveau_channel *chan, struct ttm_buffer_object *bo, struct nvif_push *push = chan->chan.push; u64 src_offset = mem->vma[0].addr; u64 dst_offset = mem->vma[1].addr; - u32 page_count = new_reg->num_pages; + u32 page_count = PFN_UP(new_reg->size); int ret; - page_count = new_reg->num_pages; + page_count = PFN_UP(new_reg->size); while (page_count) { int line_count = (page_count > 8191) ? 8191 : page_count; diff --git a/drivers/gpu/drm/nouveau/nouveau_bo9039.c b/drivers/gpu/drm/nouveau/nouveau_bo9039.c index 776b04976cdf..d2bb2687d401 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo9039.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo9039.c @@ -42,10 +42,10 @@ nvc0_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, struct nouveau_mem *mem = nouveau_mem(old_reg); u64 src_offset = mem->vma[0].addr; u64 dst_offset = mem->vma[1].addr; - u32 page_count = new_reg->num_pages; + u32 page_count = PFN_UP(new_reg->size); int ret; - page_count = new_reg->num_pages; + page_count = PFN_UP(new_reg->size); while (page_count) { int line_count = (page_count > 2047) ? 2047 : page_count; diff --git a/drivers/gpu/drm/nouveau/nouveau_bo90b5.c b/drivers/gpu/drm/nouveau/nouveau_bo90b5.c index 8499f58213e3..4618f4f5ab56 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo90b5.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo90b5.c @@ -37,10 +37,10 @@ nvc0_bo_move_copy(struct nouveau_channel *chan, struct ttm_buffer_object *bo, struct nvif_push *push = chan->chan.push; u64 src_offset = mem->vma[0].addr; u64 dst_offset = mem->vma[1].addr; - u32 page_count = new_reg->num_pages; + u32 page_count = PFN_UP(new_reg->size); int ret; - page_count = new_reg->num_pages; + page_count = PFN_UP(new_reg->size); while (page_count) { int line_count = (page_count > 8191) ? 8191 : page_count; diff --git a/drivers/gpu/drm/nouveau/nouveau_boa0b5.c b/drivers/gpu/drm/nouveau/nouveau_boa0b5.c index 575212472e7a..07a5c6302c98 100644 --- a/drivers/gpu/drm/nouveau/nouveau_boa0b5.c +++ b/drivers/gpu/drm/nouveau/nouveau_boa0b5.c @@ -58,7 +58,7 @@ nve0_bo_move_copy(struct nouveau_channel *chan, struct ttm_buffer_object *bo, PITCH_IN, PAGE_SIZE, PITCH_OUT, PAGE_SIZE, LINE_LENGTH_IN, PAGE_SIZE, - LINE_COUNT, new_reg->num_pages); + LINE_COUNT, PFN_UP(new_reg->size)); PUSH_IMMD(push, NVA0B5, LAUNCH_DMA, NVDEF(NVA0B5, LAUNCH_DMA, DATA_TRANSFER_TYPE, NON_PIPELINED) | diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index fab542a758ff..ac5793c96957 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -679,7 +679,7 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli, } if (!nvbo->kmap.virtual) { - ret = ttm_bo_kmap(&nvbo->bo, 0, nvbo->bo.resource->num_pages, + ret = ttm_bo_kmap(&nvbo->bo, 0, PFN_UP(nvbo->bo.base.size), &nvbo->kmap); if (ret) { NV_PRINTK(err, cli, "failed kmap for reloc\n"); @@ -868,8 +868,7 @@ revalidate: if (unlikely(cmd != req->suffix0)) { if (!nvbo->kmap.virtual) { ret = ttm_bo_kmap(&nvbo->bo, 0, - nvbo->bo.resource-> - num_pages, + PFN_UP(nvbo->bo.base.size), &nvbo->kmap); if (ret) { WIND_RING(chan); diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 76f8edefa637..1fde3a5d7c32 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -115,7 +115,7 @@ nouveau_mem_host(struct ttm_resource *reg, struct ttm_tt *tt) mutex_lock(&drm->master.lock); ret = nvif_mem_ctor_type(mmu, "ttmHostMem", cli->mem->oclass, type, PAGE_SHIFT, - reg->num_pages << PAGE_SHIFT, + reg->size, &args, sizeof(args), &mem->mem); mutex_unlock(&drm->master.lock); return ret; @@ -128,7 +128,7 @@ nouveau_mem_vram(struct ttm_resource *reg, bool contig, u8 page) struct nouveau_cli *cli = mem->cli; struct nouveau_drm *drm = cli->drm; struct nvif_mmu *mmu = &cli->mmu; - u64 size = ALIGN(reg->num_pages << PAGE_SHIFT, 1 << page); + u64 size = ALIGN(reg->size, 1 << page); int ret; mutex_lock(&drm->master.lock); diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c index 9602c30928f2..1469a88910e4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ttm.c +++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c @@ -139,7 +139,7 @@ nv04_gart_manager_new(struct ttm_resource_manager *man, mem = nouveau_mem(*res); ttm_resource_init(bo, place, *res); ret = nvif_vmm_get(&mem->cli->vmm.vmm, PTES, false, 12, 0, - (long)(*res)->num_pages << PAGE_SHIFT, &mem->vma[0]); + (long)(*res)->size, &mem->vma[0]); if (ret) { nouveau_mem_del(man, *res); return ret; diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index 446f7bae54c4..46a27ebf4588 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -400,8 +400,11 @@ static int cmp_size_smaller_first(void *priv, const struct list_head *a, struct radeon_bo_list *lb = list_entry(b, struct radeon_bo_list, tv.head); /* Sort A before B if A is smaller. */ - return (int)la->robj->tbo.resource->num_pages - - (int)lb->robj->tbo.resource->num_pages; + if (la->robj->tbo.base.size > lb->robj->tbo.base.size) + return 1; + if (la->robj->tbo.base.size < lb->robj->tbo.base.size) + return -1; + return 0; } /** diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 00c33b24d5d3..10c0fbd9d2b4 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -232,7 +232,7 @@ int radeon_bo_kmap(struct radeon_bo *bo, void **ptr) } return 0; } - r = ttm_bo_kmap(&bo->tbo, 0, bo->tbo.resource->num_pages, &bo->kmap); + r = ttm_bo_kmap(&bo->tbo, 0, PFN_UP(bo->tbo.base.size), &bo->kmap); if (r) { return r; } @@ -737,7 +737,7 @@ vm_fault_t radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo) if (bo->resource->mem_type != TTM_PL_VRAM) return 0; - size = bo->resource->num_pages << PAGE_SHIFT; + size = bo->resource->size; offset = bo->resource->start << PAGE_SHIFT; if ((offset + size) <= rdev->mc.visible_vram_size) return 0; diff --git a/drivers/gpu/drm/radeon/radeon_trace.h b/drivers/gpu/drm/radeon/radeon_trace.h index c9fed5f2b870..22676617e1a5 100644 --- a/drivers/gpu/drm/radeon/radeon_trace.h +++ b/drivers/gpu/drm/radeon/radeon_trace.h @@ -22,7 +22,7 @@ TRACE_EVENT(radeon_bo_create, TP_fast_assign( __entry->bo = bo; - __entry->pages = bo->tbo.resource->num_pages; + __entry->pages = PFN_UP(bo->tbo.resource->size); ), TP_printk("bo=%p, pages=%u", __entry->bo, __entry->pages) ); diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index d33fec488713..fff48306c05f 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -181,7 +181,7 @@ static int radeon_move_blit(struct ttm_buffer_object *bo, BUILD_BUG_ON((PAGE_SIZE % RADEON_GPU_PAGE_SIZE) != 0); - num_pages = new_mem->num_pages * (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); + num_pages = PFN_UP(new_mem->size) * (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); fence = radeon_copy(rdev, old_start, new_start, num_pages, bo->base.resv); if (IS_ERR(fence)) return PTR_ERR(fence); @@ -268,7 +268,7 @@ out: static int radeon_ttm_io_mem_reserve(struct ttm_device *bdev, struct ttm_resource *mem) { struct radeon_device *rdev = radeon_get_rdev(bdev); - size_t bus_size = (size_t)mem->num_pages << PAGE_SHIFT; + size_t bus_size = (size_t)mem->size; switch (mem->mem_type) { case TTM_PL_SYSTEM: diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 7c8e8be774f1..c3f4b33136e5 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -51,9 +51,6 @@ static void ttm_bo_mem_space_debug(struct ttm_buffer_object *bo, struct ttm_resource_manager *man; int i, mem_type; - drm_printf(&p, "No space for %p (%lu pages, %zuK, %zuM)\n", - bo, bo->resource->num_pages, bo->base.size >> 10, - bo->base.size >> 20); for (i = 0; i < placement->num_placement; i++) { mem_type = placement->placement[i].mem_type; drm_printf(&p, " placement[%d]=0x%08X (%d)\n", diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index fa04e62202c1..ba3aa0a0fc43 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c @@ -173,7 +173,7 @@ int ttm_bo_move_memcpy(struct ttm_buffer_object *bo, clear = src_iter->ops->maps_tt && (!ttm || !ttm_tt_is_populated(ttm)); if (!(clear && ttm && !(ttm->page_flags & TTM_TT_FLAG_ZERO_ALLOC))) - ttm_move_memcpy(clear, dst_mem->num_pages, dst_iter, src_iter); + ttm_move_memcpy(clear, ttm->num_pages, dst_iter, src_iter); if (!src_iter->ops->maps_tt) ttm_kmap_iter_linear_io_fini(&_src_iter.io, bdev, src_mem); @@ -357,9 +357,9 @@ int ttm_bo_kmap(struct ttm_buffer_object *bo, map->virtual = NULL; map->bo = bo; - if (num_pages > bo->resource->num_pages) + if (num_pages > PFN_UP(bo->resource->size)) return -EINVAL; - if ((start_page + num_pages) > bo->resource->num_pages) + if ((start_page + num_pages) > PFN_UP(bo->resource->size)) return -EINVAL; ret = ttm_mem_io_reserve(bo->bdev, bo->resource); diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c index 38119311284d..5a3e4b891377 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_vm.c +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c @@ -217,7 +217,7 @@ vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf, page_last = vma_pages(vma) + vma->vm_pgoff - drm_vma_node_start(&bo->base.vma_node); - if (unlikely(page_offset >= bo->resource->num_pages)) + if (unlikely(page_offset >= PFN_UP(bo->base.size))) return VM_FAULT_SIGBUS; prot = ttm_io_prot(bo, bo->resource, prot); @@ -412,7 +412,7 @@ int ttm_bo_vm_access(struct vm_area_struct *vma, unsigned long addr, << PAGE_SHIFT); int ret; - if (len < 1 || (offset + len) >> PAGE_SHIFT > bo->resource->num_pages) + if (len < 1 || (offset + len) > bo->base.size) return -EIO; ret = ttm_bo_reserve(bo, true, false, NULL); diff --git a/drivers/gpu/drm/ttm/ttm_range_manager.c b/drivers/gpu/drm/ttm/ttm_range_manager.c index f7c16c46cfbc..0a8bc0b7f380 100644 --- a/drivers/gpu/drm/ttm/ttm_range_manager.c +++ b/drivers/gpu/drm/ttm/ttm_range_manager.c @@ -83,7 +83,7 @@ static int ttm_range_man_alloc(struct ttm_resource_manager *man, spin_lock(&rman->lock); ret = drm_mm_insert_node_in_range(mm, &node->mm_nodes[0], - node->base.num_pages, + PFN_UP(node->base.size), bo->page_alignment, 0, place->fpfn, lpfn, mode); spin_unlock(&rman->lock); diff --git a/drivers/gpu/drm/ttm/ttm_resource.c b/drivers/gpu/drm/ttm/ttm_resource.c index a729c32a1e48..328391bb1d87 100644 --- a/drivers/gpu/drm/ttm/ttm_resource.c +++ b/drivers/gpu/drm/ttm/ttm_resource.c @@ -177,7 +177,7 @@ void ttm_resource_init(struct ttm_buffer_object *bo, struct ttm_resource_manager *man; res->start = 0; - res->num_pages = PFN_UP(bo->base.size); + res->size = bo->base.size; res->mem_type = place->mem_type; res->placement = place->flags; res->bus.addr = NULL; @@ -192,7 +192,7 @@ void ttm_resource_init(struct ttm_buffer_object *bo, list_add_tail(&res->lru, &bo->bdev->pinned); else list_add_tail(&res->lru, &man->lru[bo->priority]); - man->usage += res->num_pages << PAGE_SHIFT; + man->usage += res->size; spin_unlock(&bo->bdev->lru_lock); } EXPORT_SYMBOL(ttm_resource_init); @@ -214,7 +214,7 @@ void ttm_resource_fini(struct ttm_resource_manager *man, spin_lock(&bdev->lru_lock); list_del_init(&res->lru); - man->usage -= res->num_pages << PAGE_SHIFT; + man->usage -= res->size; spin_unlock(&bdev->lru_lock); } EXPORT_SYMBOL(ttm_resource_fini); @@ -665,17 +665,15 @@ ttm_kmap_iter_linear_io_init(struct ttm_kmap_iter_linear_io *iter_io, iosys_map_set_vaddr(&iter_io->dmap, mem->bus.addr); iter_io->needs_unmap = false; } else { - size_t bus_size = (size_t)mem->num_pages << PAGE_SHIFT; - iter_io->needs_unmap = true; memset(&iter_io->dmap, 0, sizeof(iter_io->dmap)); if (mem->bus.caching == ttm_write_combined) iosys_map_set_vaddr_iomem(&iter_io->dmap, ioremap_wc(mem->bus.offset, - bus_size)); + mem->size)); else if (mem->bus.caching == ttm_cached) iosys_map_set_vaddr(&iter_io->dmap, - memremap(mem->bus.offset, bus_size, + memremap(mem->bus.offset, mem->size, MEMREMAP_WB | MEMREMAP_WT | MEMREMAP_WC)); @@ -684,7 +682,7 @@ ttm_kmap_iter_linear_io_init(struct ttm_kmap_iter_linear_io *iter_io, if (iosys_map_is_null(&iter_io->dmap)) iosys_map_set_vaddr_iomem(&iter_io->dmap, ioremap(mem->bus.offset, - bus_size)); + mem->size)); if (iosys_map_is_null(&iter_io->dmap)) { ret = -ENOMEM; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_blit.c b/drivers/gpu/drm/vmwgfx/vmwgfx_blit.c index 09fe20e918f9..c52c7bf1485b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_blit.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_blit.c @@ -483,8 +483,8 @@ int vmw_bo_cpu_blit(struct ttm_buffer_object *dst, d.src_addr = NULL; d.dst_pages = dst->ttm->pages; d.src_pages = src->ttm->pages; - d.dst_num_pages = dst->resource->num_pages; - d.src_num_pages = src->resource->num_pages; + d.dst_num_pages = PFN_UP(dst->resource->size); + d.src_num_pages = PFN_UP(src->resource->size); d.dst_prot = ttm_io_prot(dst, dst->resource, PAGE_KERNEL); d.src_prot = ttm_io_prot(src, src->resource, PAGE_KERNEL); d.diff = diff; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c index d218b15953e0..321c551784a1 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c @@ -194,7 +194,7 @@ int vmw_bo_pin_in_start_of_vram(struct vmw_private *dev_priv, int ret = 0; place = vmw_vram_placement.placement[0]; - place.lpfn = bo->resource->num_pages; + place.lpfn = PFN_UP(bo->resource->size); placement.num_placement = 1; placement.placement = &place; placement.num_busy_placement = 1; @@ -211,7 +211,7 @@ int vmw_bo_pin_in_start_of_vram(struct vmw_private *dev_priv, * that situation. */ if (bo->resource->mem_type == TTM_PL_VRAM && - bo->resource->start < bo->resource->num_pages && + bo->resource->start < PFN_UP(bo->resource->size) && bo->resource->start > 0 && buf->base.pin_count == 0) { ctx.interruptible = false; @@ -352,7 +352,7 @@ void *vmw_bo_map_and_cache(struct vmw_buffer_object *vbo) if (virtual) return virtual; - ret = ttm_bo_kmap(bo, 0, bo->resource->num_pages, &vbo->map); + ret = ttm_bo_kmap(bo, 0, PFN_UP(bo->base.size), &vbo->map); if (ret) DRM_ERROR("Buffer object map failed: %d.\n", ret); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c index 0422b6b89cc1..b78a10312fad 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c @@ -443,7 +443,7 @@ static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size) * Do a page by page copy of COTables. This eliminates slow vmap()s. * This should really be a TTM utility. */ - for (i = 0; i < old_bo->resource->num_pages; ++i) { + for (i = 0; i < PFN_UP(old_bo->resource->size); ++i) { bool dummy; ret = ttm_bo_kmap(old_bo, i, 1, &old_map); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index f16fc489d725..a5379f6fb5ab 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -1047,7 +1047,7 @@ static int vmw_query_bo_switch_prepare(struct vmw_private *dev_priv, if (unlikely(new_query_bo != sw_context->cur_query_bo)) { - if (unlikely(new_query_bo->base.resource->num_pages > 4)) { + if (unlikely(PFN_UP(new_query_bo->base.resource->size) > 4)) { VMW_DEBUG_USER("Query buffer too large.\n"); return -EINVAL; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c b/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c index 60e3cc537f36..abd5e3323ebf 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c @@ -71,7 +71,7 @@ static int vmw_gmrid_man_get_node(struct ttm_resource_manager *man, spin_lock(&gman->lock); if (gman->max_gmr_pages > 0) { - gman->used_gmr_pages += (*res)->num_pages; + gman->used_gmr_pages += PFN_UP((*res)->size); /* * Because the graphics memory is a soft limit we can try to * expand it instead of letting the userspace apps crash. @@ -114,7 +114,7 @@ static int vmw_gmrid_man_get_node(struct ttm_resource_manager *man, return 0; nospace: - gman->used_gmr_pages -= (*res)->num_pages; + gman->used_gmr_pages -= PFN_UP((*res)->size); spin_unlock(&gman->lock); ida_free(&gman->gmr_ida, id); ttm_resource_fini(man, *res); @@ -129,7 +129,7 @@ static void vmw_gmrid_man_put_node(struct ttm_resource_manager *man, ida_free(&gman->gmr_ida, res->start); spin_lock(&gman->lock); - gman->used_gmr_pages -= res->num_pages; + gman->used_gmr_pages -= PFN_UP(res->size); spin_unlock(&gman->lock); ttm_resource_fini(man, res); kfree(res); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c b/drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c index 7bc99b1279f7..f41f041559f4 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c @@ -230,7 +230,7 @@ void vmw_bo_dirty_unmap(struct vmw_buffer_object *vbo, int vmw_bo_dirty_add(struct vmw_buffer_object *vbo) { struct vmw_bo_dirty *dirty = vbo->dirty; - pgoff_t num_pages = vbo->base.resource->num_pages; + pgoff_t num_pages = PFN_UP(vbo->base.resource->size); size_t size; int ret; @@ -395,7 +395,7 @@ vm_fault_t vmw_bo_vm_mkwrite(struct vm_fault *vmf) return ret; page_offset = vmf->pgoff - drm_vma_node_start(&bo->base.vma_node); - if (unlikely(page_offset >= bo->resource->num_pages)) { + if (unlikely(page_offset >= PFN_UP(bo->resource->size))) { ret = VM_FAULT_SIGBUS; goto out_unlock; } @@ -438,7 +438,7 @@ vm_fault_t vmw_bo_vm_fault(struct vm_fault *vmf) page_offset = vmf->pgoff - drm_vma_node_start(&bo->base.vma_node); - if (page_offset >= bo->resource->num_pages || + if (page_offset >= PFN_UP(bo->resource->size) || vmw_resources_clean(vbo, page_offset, page_offset + PAGE_SIZE, &allowed_prefault)) { diff --git a/include/drm/ttm/ttm_resource.h b/include/drm/ttm/ttm_resource.h index 5afc6d664fde..78a226eba953 100644 --- a/include/drm/ttm/ttm_resource.h +++ b/include/drm/ttm/ttm_resource.h @@ -197,7 +197,7 @@ struct ttm_bus_placement { * struct ttm_resource * * @start: Start of the allocation. - * @num_pages: Actual size of resource in pages. + * @size: Actual size of resource in bytes. * @mem_type: Resource type of the allocation. * @placement: Placement flags. * @bus: Placement on io bus accessible to the CPU @@ -208,7 +208,7 @@ struct ttm_bus_placement { */ struct ttm_resource { unsigned long start; - unsigned long num_pages; + size_t size; uint32_t mem_type; uint32_t placement; struct ttm_bus_placement bus; -- cgit From 67f99e34473f8b799c34bb0b0db404a5e32dbca9 Mon Sep 17 00:00:00 2001 From: Karolina Drobnik Date: Tue, 25 Oct 2022 11:19:03 +0200 Subject: i915/i915_gem_context: Remove debug message in i915_gem_context_create_ioctl We know that as long as GEM context create ioctl succeeds, a context was created. There is no need to write about it, especially when such a message heavily pollutes dmesg and makes debugging actual errors harder. Since commit baa89ba3f1fe ("drm/i915/gem: initial conversion to new logging macros using coccinelle"), the logging for creating a new user context was moved under the driver debug output (for lack of a means for per-user logs, and a lack of user-focused drm.debug parameter). This only reveals how obnoxious having that spam be part of the driver debug logs, so remove it. [ from Chris Wilson ] Suggested-by: Chris Wilson Signed-off-by: Karolina Drobnik Cc: Andi Shyti Reviewed-by: Andi Shyti Signed-off-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20221025091903.986819-1-karolina.drobnik@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_context.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c index d0a537b15ebb..01402f3c58f6 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c @@ -2298,7 +2298,6 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data, } args->ctx_id = id; - drm_dbg(&i915->drm, "HW context %d created\n", args->ctx_id); return 0; -- cgit From 3e4a21a29dd924995f1135cd50e8b7e0d023729c Mon Sep 17 00:00:00 2001 From: Pin-yen Lin Date: Thu, 27 Oct 2022 11:21:49 +0800 Subject: drm/bridge: it6505: Fix return value check for pm_runtime_get_sync `pm_runtime_get_sync` may return 1 on success. Fix the `if` statement here to make the code less confusing, even though additional calls to `it6505_poweron` doesn't break anything when it's already powered. This was reported by Dan Carpenter in https://lore.kernel.org/all/Y1fMCs6VnxbDcB41@kili/ Fixes: 10517777d302 ("drm/bridge: it6505: Adapt runtime power management framework") Signed-off-by: Pin-yen Lin Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20221027032149.2739912-1-treapking@chromium.org --- drivers/gpu/drm/bridge/ite-it6505.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c index b929fc766e24..21a9b8422bda 100644 --- a/drivers/gpu/drm/bridge/ite-it6505.c +++ b/drivers/gpu/drm/bridge/ite-it6505.c @@ -2699,7 +2699,7 @@ static void it6505_extcon_work(struct work_struct *work) * pm_runtime_force_resume re-enables runtime power management. * Handling the error here to make sure the bridge is powered on. */ - if (ret) + if (ret < 0) it6505_poweron(it6505); complete_all(&it6505->extcon_completion); -- cgit From a8a4f0467d706fc22d286dfa973946e5944b793c Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Tue, 25 Oct 2022 21:50:15 +0200 Subject: drm/i915: Fix CFI violations in gt_sysfs When booting with CONFIG_CFI_CLANG, there are numerous violations when accessing the files under /sys/devices/pci0000:00/0000:00:02.0/drm/card0/gt/gt0: $ cd /sys/devices/pci0000:00/0000:00:02.0/drm/card0/gt/gt0 $ grep . * id:0 punit_req_freq_mhz:350 rc6_enable:1 rc6_residency_ms:214934 rps_act_freq_mhz:1300 rps_boost_freq_mhz:1300 rps_cur_freq_mhz:350 rps_max_freq_mhz:1300 rps_min_freq_mhz:350 rps_RP0_freq_mhz:1300 rps_RP1_freq_mhz:350 rps_RPn_freq_mhz:350 throttle_reason_pl1:0 throttle_reason_pl2:0 throttle_reason_pl4:0 throttle_reason_prochot:0 throttle_reason_ratl:0 throttle_reason_status:0 throttle_reason_thermal:0 throttle_reason_vr_tdc:0 throttle_reason_vr_thermalert:0 $ sudo dmesg &| grep "CFI failure at" [ 214.595903] CFI failure at kobj_attr_show+0x19/0x30 (target: id_show+0x0/0x70 [i915]; expected type: 0xc527b809) [ 214.596064] CFI failure at kobj_attr_show+0x19/0x30 (target: punit_req_freq_mhz_show+0x0/0x40 [i915]; expected type: 0xc527b809) [ 214.596407] CFI failure at kobj_attr_show+0x19/0x30 (target: rc6_enable_show+0x0/0x40 [i915]; expected type: 0xc527b809) [ 214.596528] CFI failure at kobj_attr_show+0x19/0x30 (target: rc6_residency_ms_show+0x0/0x270 [i915]; expected type: 0xc527b809) [ 214.596682] CFI failure at kobj_attr_show+0x19/0x30 (target: act_freq_mhz_show+0x0/0xe0 [i915]; expected type: 0xc527b809) [ 214.596792] CFI failure at kobj_attr_show+0x19/0x30 (target: boost_freq_mhz_show+0x0/0xe0 [i915]; expected type: 0xc527b809) [ 214.596893] CFI failure at kobj_attr_show+0x19/0x30 (target: cur_freq_mhz_show+0x0/0xe0 [i915]; expected type: 0xc527b809) [ 214.596996] CFI failure at kobj_attr_show+0x19/0x30 (target: max_freq_mhz_show+0x0/0xe0 [i915]; expected type: 0xc527b809) [ 214.597099] CFI failure at kobj_attr_show+0x19/0x30 (target: min_freq_mhz_show+0x0/0xe0 [i915]; expected type: 0xc527b809) [ 214.597198] CFI failure at kobj_attr_show+0x19/0x30 (target: RP0_freq_mhz_show+0x0/0xe0 [i915]; expected type: 0xc527b809) [ 214.597301] CFI failure at kobj_attr_show+0x19/0x30 (target: RP1_freq_mhz_show+0x0/0xe0 [i915]; expected type: 0xc527b809) [ 214.597405] CFI failure at kobj_attr_show+0x19/0x30 (target: RPn_freq_mhz_show+0x0/0xe0 [i915]; expected type: 0xc527b809) [ 214.597538] CFI failure at kobj_attr_show+0x19/0x30 (target: throttle_reason_bool_show+0x0/0x50 [i915]; expected type: 0xc527b809) [ 214.597701] CFI failure at kobj_attr_show+0x19/0x30 (target: throttle_reason_bool_show+0x0/0x50 [i915]; expected type: 0xc527b809) [ 214.597836] CFI failure at kobj_attr_show+0x19/0x30 (target: throttle_reason_bool_show+0x0/0x50 [i915]; expected type: 0xc527b809) [ 214.597952] CFI failure at kobj_attr_show+0x19/0x30 (target: throttle_reason_bool_show+0x0/0x50 [i915]; expected type: 0xc527b809) [ 214.598071] CFI failure at kobj_attr_show+0x19/0x30 (target: throttle_reason_bool_show+0x0/0x50 [i915]; expected type: 0xc527b809) [ 214.598177] CFI failure at kobj_attr_show+0x19/0x30 (target: throttle_reason_bool_show+0x0/0x50 [i915]; expected type: 0xc527b809) [ 214.598307] CFI failure at kobj_attr_show+0x19/0x30 (target: throttle_reason_bool_show+0x0/0x50 [i915]; expected type: 0xc527b809) [ 214.598439] CFI failure at kobj_attr_show+0x19/0x30 (target: throttle_reason_bool_show+0x0/0x50 [i915]; expected type: 0xc527b809) [ 214.598542] CFI failure at kobj_attr_show+0x19/0x30 (target: throttle_reason_bool_show+0x0/0x50 [i915]; expected type: 0xc527b809) With kCFI, indirect calls are validated against their expected type versus actual type and failures occur when the two types do not match. The ultimate issue is that these sysfs functions are expecting to be called via dev_attr_show() but they may also be called via kobj_attr_show(), as certain files are created under two different kobjects that have two different sysfs_ops in intel_gt_sysfs_register(), hence the warnings above. When accessing the gt_ files under /sys/devices/pci0000:00/0000:00:02.0/drm/card0, which are using the same sysfs functions, there are no violations, meaning the functions are being called with the proper type. To make everything work properly, adjust certain functions to match the type of the ->show() and ->store() members in 'struct kobj_attribute'. Add a macro to generate functions for that can be called via both dev_attr_{show,store}() or kobj_attr_{show,store}() so that they can be called through both kobject locations without violating kCFI and adjust the attribute groups to account for this. Link: https://github.com/ClangBuiltLinux/linux/issues/1716 Reviewed-by: Andi Shyti Reviewed-by: Andrzej Hajda Reviewed-by: Kees Cook Signed-off-by: Nathan Chancellor Signed-off-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20221013205909.1282545-1-nathan@kernel.org --- drivers/gpu/drm/i915/gt/intel_gt_sysfs.c | 15 +- drivers/gpu/drm/i915/gt/intel_gt_sysfs.h | 2 +- drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c | 461 +++++++++++++--------------- 3 files changed, 220 insertions(+), 258 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_sysfs.c b/drivers/gpu/drm/i915/gt/intel_gt_sysfs.c index d651ccd0ab20..9486dd3bed99 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_sysfs.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_sysfs.c @@ -22,11 +22,9 @@ bool is_object_gt(struct kobject *kobj) return !strncmp(kobj->name, "gt", 2); } -struct intel_gt *intel_gt_sysfs_get_drvdata(struct device *dev, +struct intel_gt *intel_gt_sysfs_get_drvdata(struct kobject *kobj, const char *name) { - struct kobject *kobj = &dev->kobj; - /* * We are interested at knowing from where the interface * has been called, whether it's called from gt/ or from @@ -38,6 +36,7 @@ struct intel_gt *intel_gt_sysfs_get_drvdata(struct device *dev, * "struct drm_i915_private *" type. */ if (!is_object_gt(kobj)) { + struct device *dev = kobj_to_dev(kobj); struct drm_i915_private *i915 = kdev_minor_to_i915(dev); return to_gt(i915); @@ -51,18 +50,18 @@ static struct kobject *gt_get_parent_obj(struct intel_gt *gt) return >->i915->drm.primary->kdev->kobj; } -static ssize_t id_show(struct device *dev, - struct device_attribute *attr, +static ssize_t id_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) { - struct intel_gt *gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name); + struct intel_gt *gt = intel_gt_sysfs_get_drvdata(kobj, attr->attr.name); return sysfs_emit(buf, "%u\n", gt->info.id); } -static DEVICE_ATTR_RO(id); +static struct kobj_attribute attr_id = __ATTR_RO(id); static struct attribute *id_attrs[] = { - &dev_attr_id.attr, + &attr_id.attr, NULL, }; ATTRIBUTE_GROUPS(id); diff --git a/drivers/gpu/drm/i915/gt/intel_gt_sysfs.h b/drivers/gpu/drm/i915/gt/intel_gt_sysfs.h index d637c6c3a69f..18bab835be02 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_sysfs.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_sysfs.h @@ -25,7 +25,7 @@ static inline struct intel_gt *kobj_to_gt(struct kobject *kobj) void intel_gt_sysfs_register(struct intel_gt *gt); void intel_gt_sysfs_unregister(struct intel_gt *gt); -struct intel_gt *intel_gt_sysfs_get_drvdata(struct device *dev, +struct intel_gt *intel_gt_sysfs_get_drvdata(struct kobject *kobj, const char *name); #endif /* SYSFS_GT_H */ diff --git a/drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c b/drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c index 904160952369..2b5f05b31187 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c @@ -24,14 +24,15 @@ enum intel_gt_sysfs_op { }; static int -sysfs_gt_attribute_w_func(struct device *dev, struct device_attribute *attr, +sysfs_gt_attribute_w_func(struct kobject *kobj, struct attribute *attr, int (func)(struct intel_gt *gt, u32 val), u32 val) { struct intel_gt *gt; int ret; - if (!is_object_gt(&dev->kobj)) { + if (!is_object_gt(kobj)) { int i; + struct device *dev = kobj_to_dev(kobj); struct drm_i915_private *i915 = kdev_minor_to_i915(dev); for_each_gt(gt, i915, i) { @@ -40,7 +41,7 @@ sysfs_gt_attribute_w_func(struct device *dev, struct device_attribute *attr, break; } } else { - gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name); + gt = intel_gt_sysfs_get_drvdata(kobj, attr->name); ret = func(gt, val); } @@ -48,7 +49,7 @@ sysfs_gt_attribute_w_func(struct device *dev, struct device_attribute *attr, } static u32 -sysfs_gt_attribute_r_func(struct device *dev, struct device_attribute *attr, +sysfs_gt_attribute_r_func(struct kobject *kobj, struct attribute *attr, u32 (func)(struct intel_gt *gt), enum intel_gt_sysfs_op op) { @@ -57,8 +58,9 @@ sysfs_gt_attribute_r_func(struct device *dev, struct device_attribute *attr, ret = (op == INTEL_GT_SYSFS_MAX) ? 0 : (u32) -1; - if (!is_object_gt(&dev->kobj)) { + if (!is_object_gt(kobj)) { int i; + struct device *dev = kobj_to_dev(kobj); struct drm_i915_private *i915 = kdev_minor_to_i915(dev); for_each_gt(gt, i915, i) { @@ -77,7 +79,7 @@ sysfs_gt_attribute_r_func(struct device *dev, struct device_attribute *attr, } } } else { - gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name); + gt = intel_gt_sysfs_get_drvdata(kobj, attr->name); ret = func(gt); } @@ -92,6 +94,76 @@ sysfs_gt_attribute_r_func(struct device *dev, struct device_attribute *attr, #define sysfs_gt_attribute_r_max_func(d, a, f) \ sysfs_gt_attribute_r_func(d, a, f, INTEL_GT_SYSFS_MAX) +#define INTEL_GT_SYSFS_SHOW(_name, _attr_type) \ + static ssize_t _name##_show_common(struct kobject *kobj, \ + struct attribute *attr, char *buff) \ + { \ + u32 val = sysfs_gt_attribute_r_##_attr_type##_func(kobj, attr, \ + __##_name##_show); \ + \ + return sysfs_emit(buff, "%u\n", val); \ + } \ + static ssize_t _name##_show(struct kobject *kobj, \ + struct kobj_attribute *attr, char *buff) \ + { \ + return _name ##_show_common(kobj, &attr->attr, buff); \ + } \ + static ssize_t _name##_dev_show(struct device *dev, \ + struct device_attribute *attr, char *buff) \ + { \ + return _name##_show_common(&dev->kobj, &attr->attr, buff); \ + } + +#define INTEL_GT_SYSFS_STORE(_name, _func) \ + static ssize_t _name##_store_common(struct kobject *kobj, \ + struct attribute *attr, \ + const char *buff, size_t count) \ + { \ + int ret; \ + u32 val; \ + \ + ret = kstrtou32(buff, 0, &val); \ + if (ret) \ + return ret; \ + \ + ret = sysfs_gt_attribute_w_func(kobj, attr, _func, val); \ + \ + return ret ?: count; \ + } \ + static ssize_t _name##_store(struct kobject *kobj, \ + struct kobj_attribute *attr, const char *buff, \ + size_t count) \ + { \ + return _name##_store_common(kobj, &attr->attr, buff, count); \ + } \ + static ssize_t _name##_dev_store(struct device *dev, \ + struct device_attribute *attr, \ + const char *buff, size_t count) \ + { \ + return _name##_store_common(&dev->kobj, &attr->attr, buff, count); \ + } + +#define INTEL_GT_SYSFS_SHOW_MAX(_name) INTEL_GT_SYSFS_SHOW(_name, max) +#define INTEL_GT_SYSFS_SHOW_MIN(_name) INTEL_GT_SYSFS_SHOW(_name, min) + +#define INTEL_GT_ATTR_RW(_name) \ + static struct kobj_attribute attr_##_name = __ATTR_RW(_name) + +#define INTEL_GT_ATTR_RO(_name) \ + static struct kobj_attribute attr_##_name = __ATTR_RO(_name) + +#define INTEL_GT_DUAL_ATTR_RW(_name) \ + static struct device_attribute dev_attr_##_name = __ATTR(_name, 0644, \ + _name##_dev_show, \ + _name##_dev_store); \ + INTEL_GT_ATTR_RW(_name) + +#define INTEL_GT_DUAL_ATTR_RO(_name) \ + static struct device_attribute dev_attr_##_name = __ATTR(_name, 0444, \ + _name##_dev_show, \ + NULL); \ + INTEL_GT_ATTR_RO(_name) + #ifdef CONFIG_PM static u32 get_residency(struct intel_gt *gt, i915_reg_t reg) { @@ -104,11 +176,8 @@ static u32 get_residency(struct intel_gt *gt, i915_reg_t reg) return DIV_ROUND_CLOSEST_ULL(res, 1000); } -static ssize_t rc6_enable_show(struct device *dev, - struct device_attribute *attr, - char *buff) +static u8 get_rc6_mask(struct intel_gt *gt) { - struct intel_gt *gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name); u8 mask = 0; if (HAS_RC6(gt->i915)) @@ -118,37 +187,35 @@ static ssize_t rc6_enable_show(struct device *dev, if (HAS_RC6pp(gt->i915)) mask |= BIT(2); - return sysfs_emit(buff, "%x\n", mask); + return mask; } -static u32 __rc6_residency_ms_show(struct intel_gt *gt) +static ssize_t rc6_enable_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buff) { - return get_residency(gt, GEN6_GT_GFX_RC6); + struct intel_gt *gt = intel_gt_sysfs_get_drvdata(kobj, attr->attr.name); + + return sysfs_emit(buff, "%x\n", get_rc6_mask(gt)); } -static ssize_t rc6_residency_ms_show(struct device *dev, - struct device_attribute *attr, - char *buff) +static ssize_t rc6_enable_dev_show(struct device *dev, + struct device_attribute *attr, + char *buff) { - u32 rc6_residency = sysfs_gt_attribute_r_min_func(dev, attr, - __rc6_residency_ms_show); + struct intel_gt *gt = intel_gt_sysfs_get_drvdata(&dev->kobj, attr->attr.name); - return sysfs_emit(buff, "%u\n", rc6_residency); + return sysfs_emit(buff, "%x\n", get_rc6_mask(gt)); } -static u32 __rc6p_residency_ms_show(struct intel_gt *gt) +static u32 __rc6_residency_ms_show(struct intel_gt *gt) { - return get_residency(gt, GEN6_GT_GFX_RC6p); + return get_residency(gt, GEN6_GT_GFX_RC6); } -static ssize_t rc6p_residency_ms_show(struct device *dev, - struct device_attribute *attr, - char *buff) +static u32 __rc6p_residency_ms_show(struct intel_gt *gt) { - u32 rc6p_residency = sysfs_gt_attribute_r_min_func(dev, attr, - __rc6p_residency_ms_show); - - return sysfs_emit(buff, "%u\n", rc6p_residency); + return get_residency(gt, GEN6_GT_GFX_RC6p); } static u32 __rc6pp_residency_ms_show(struct intel_gt *gt) @@ -156,67 +223,69 @@ static u32 __rc6pp_residency_ms_show(struct intel_gt *gt) return get_residency(gt, GEN6_GT_GFX_RC6pp); } -static ssize_t rc6pp_residency_ms_show(struct device *dev, - struct device_attribute *attr, - char *buff) -{ - u32 rc6pp_residency = sysfs_gt_attribute_r_min_func(dev, attr, - __rc6pp_residency_ms_show); - - return sysfs_emit(buff, "%u\n", rc6pp_residency); -} - static u32 __media_rc6_residency_ms_show(struct intel_gt *gt) { return get_residency(gt, VLV_GT_MEDIA_RC6); } -static ssize_t media_rc6_residency_ms_show(struct device *dev, - struct device_attribute *attr, - char *buff) -{ - u32 rc6_residency = sysfs_gt_attribute_r_min_func(dev, attr, - __media_rc6_residency_ms_show); +INTEL_GT_SYSFS_SHOW_MIN(rc6_residency_ms); +INTEL_GT_SYSFS_SHOW_MIN(rc6p_residency_ms); +INTEL_GT_SYSFS_SHOW_MIN(rc6pp_residency_ms); +INTEL_GT_SYSFS_SHOW_MIN(media_rc6_residency_ms); - return sysfs_emit(buff, "%u\n", rc6_residency); -} - -static DEVICE_ATTR_RO(rc6_enable); -static DEVICE_ATTR_RO(rc6_residency_ms); -static DEVICE_ATTR_RO(rc6p_residency_ms); -static DEVICE_ATTR_RO(rc6pp_residency_ms); -static DEVICE_ATTR_RO(media_rc6_residency_ms); +INTEL_GT_DUAL_ATTR_RO(rc6_enable); +INTEL_GT_DUAL_ATTR_RO(rc6_residency_ms); +INTEL_GT_DUAL_ATTR_RO(rc6p_residency_ms); +INTEL_GT_DUAL_ATTR_RO(rc6pp_residency_ms); +INTEL_GT_DUAL_ATTR_RO(media_rc6_residency_ms); static struct attribute *rc6_attrs[] = { + &attr_rc6_enable.attr, + &attr_rc6_residency_ms.attr, + NULL +}; + +static struct attribute *rc6p_attrs[] = { + &attr_rc6p_residency_ms.attr, + &attr_rc6pp_residency_ms.attr, + NULL +}; + +static struct attribute *media_rc6_attrs[] = { + &attr_media_rc6_residency_ms.attr, + NULL +}; + +static struct attribute *rc6_dev_attrs[] = { &dev_attr_rc6_enable.attr, &dev_attr_rc6_residency_ms.attr, NULL }; -static struct attribute *rc6p_attrs[] = { +static struct attribute *rc6p_dev_attrs[] = { &dev_attr_rc6p_residency_ms.attr, &dev_attr_rc6pp_residency_ms.attr, NULL }; -static struct attribute *media_rc6_attrs[] = { +static struct attribute *media_rc6_dev_attrs[] = { &dev_attr_media_rc6_residency_ms.attr, NULL }; static const struct attribute_group rc6_attr_group[] = { { .attrs = rc6_attrs, }, - { .name = power_group_name, .attrs = rc6_attrs, }, + { .name = power_group_name, .attrs = rc6_dev_attrs, }, }; static const struct attribute_group rc6p_attr_group[] = { { .attrs = rc6p_attrs, }, - { .name = power_group_name, .attrs = rc6p_attrs, }, + { .name = power_group_name, .attrs = rc6p_dev_attrs, }, }; static const struct attribute_group media_rc6_attr_group[] = { { .attrs = media_rc6_attrs, }, - { .name = power_group_name, .attrs = media_rc6_attrs, }, + { .name = power_group_name, .attrs = media_rc6_dev_attrs, }, }; static int __intel_gt_sysfs_create_group(struct kobject *kobj, @@ -271,104 +340,34 @@ static u32 __act_freq_mhz_show(struct intel_gt *gt) return intel_rps_read_actual_frequency(>->rps); } -static ssize_t act_freq_mhz_show(struct device *dev, - struct device_attribute *attr, char *buff) -{ - u32 actual_freq = sysfs_gt_attribute_r_max_func(dev, attr, - __act_freq_mhz_show); - - return sysfs_emit(buff, "%u\n", actual_freq); -} - static u32 __cur_freq_mhz_show(struct intel_gt *gt) { return intel_rps_get_requested_frequency(>->rps); } -static ssize_t cur_freq_mhz_show(struct device *dev, - struct device_attribute *attr, char *buff) -{ - u32 cur_freq = sysfs_gt_attribute_r_max_func(dev, attr, - __cur_freq_mhz_show); - - return sysfs_emit(buff, "%u\n", cur_freq); -} - static u32 __boost_freq_mhz_show(struct intel_gt *gt) { return intel_rps_get_boost_frequency(>->rps); } -static ssize_t boost_freq_mhz_show(struct device *dev, - struct device_attribute *attr, - char *buff) -{ - u32 boost_freq = sysfs_gt_attribute_r_max_func(dev, attr, - __boost_freq_mhz_show); - - return sysfs_emit(buff, "%u\n", boost_freq); -} - static int __boost_freq_mhz_store(struct intel_gt *gt, u32 val) { return intel_rps_set_boost_frequency(>->rps, val); } -static ssize_t boost_freq_mhz_store(struct device *dev, - struct device_attribute *attr, - const char *buff, size_t count) -{ - ssize_t ret; - u32 val; - - ret = kstrtou32(buff, 0, &val); - if (ret) - return ret; - - return sysfs_gt_attribute_w_func(dev, attr, - __boost_freq_mhz_store, val) ?: count; -} - -static u32 __rp0_freq_mhz_show(struct intel_gt *gt) +static u32 __RP0_freq_mhz_show(struct intel_gt *gt) { return intel_rps_get_rp0_frequency(>->rps); } -static ssize_t RP0_freq_mhz_show(struct device *dev, - struct device_attribute *attr, char *buff) -{ - u32 rp0_freq = sysfs_gt_attribute_r_max_func(dev, attr, - __rp0_freq_mhz_show); - - return sysfs_emit(buff, "%u\n", rp0_freq); -} - -static u32 __rp1_freq_mhz_show(struct intel_gt *gt) -{ - return intel_rps_get_rp1_frequency(>->rps); -} - -static ssize_t RP1_freq_mhz_show(struct device *dev, - struct device_attribute *attr, char *buff) -{ - u32 rp1_freq = sysfs_gt_attribute_r_max_func(dev, attr, - __rp1_freq_mhz_show); - - return sysfs_emit(buff, "%u\n", rp1_freq); -} - -static u32 __rpn_freq_mhz_show(struct intel_gt *gt) +static u32 __RPn_freq_mhz_show(struct intel_gt *gt) { return intel_rps_get_rpn_frequency(>->rps); } -static ssize_t RPn_freq_mhz_show(struct device *dev, - struct device_attribute *attr, char *buff) +static u32 __RP1_freq_mhz_show(struct intel_gt *gt) { - u32 rpn_freq = sysfs_gt_attribute_r_max_func(dev, attr, - __rpn_freq_mhz_show); - - return sysfs_emit(buff, "%u\n", rpn_freq); + return intel_rps_get_rp1_frequency(>->rps); } static u32 __max_freq_mhz_show(struct intel_gt *gt) @@ -376,71 +375,21 @@ static u32 __max_freq_mhz_show(struct intel_gt *gt) return intel_rps_get_max_frequency(>->rps); } -static ssize_t max_freq_mhz_show(struct device *dev, - struct device_attribute *attr, char *buff) -{ - u32 max_freq = sysfs_gt_attribute_r_max_func(dev, attr, - __max_freq_mhz_show); - - return sysfs_emit(buff, "%u\n", max_freq); -} - static int __set_max_freq(struct intel_gt *gt, u32 val) { return intel_rps_set_max_frequency(>->rps, val); } -static ssize_t max_freq_mhz_store(struct device *dev, - struct device_attribute *attr, - const char *buff, size_t count) -{ - int ret; - u32 val; - - ret = kstrtou32(buff, 0, &val); - if (ret) - return ret; - - ret = sysfs_gt_attribute_w_func(dev, attr, __set_max_freq, val); - - return ret ?: count; -} - static u32 __min_freq_mhz_show(struct intel_gt *gt) { return intel_rps_get_min_frequency(>->rps); } -static ssize_t min_freq_mhz_show(struct device *dev, - struct device_attribute *attr, char *buff) -{ - u32 min_freq = sysfs_gt_attribute_r_min_func(dev, attr, - __min_freq_mhz_show); - - return sysfs_emit(buff, "%u\n", min_freq); -} - static int __set_min_freq(struct intel_gt *gt, u32 val) { return intel_rps_set_min_frequency(>->rps, val); } -static ssize_t min_freq_mhz_store(struct device *dev, - struct device_attribute *attr, - const char *buff, size_t count) -{ - int ret; - u32 val; - - ret = kstrtou32(buff, 0, &val); - if (ret) - return ret; - - ret = sysfs_gt_attribute_w_func(dev, attr, __set_min_freq, val); - - return ret ?: count; -} - static u32 __vlv_rpe_freq_mhz_show(struct intel_gt *gt) { struct intel_rps *rps = >->rps; @@ -448,23 +397,31 @@ static u32 __vlv_rpe_freq_mhz_show(struct intel_gt *gt) return intel_gpu_freq(rps, rps->efficient_freq); } -static ssize_t vlv_rpe_freq_mhz_show(struct device *dev, - struct device_attribute *attr, char *buff) -{ - u32 rpe_freq = sysfs_gt_attribute_r_max_func(dev, attr, - __vlv_rpe_freq_mhz_show); - - return sysfs_emit(buff, "%u\n", rpe_freq); -} - -#define INTEL_GT_RPS_SYSFS_ATTR(_name, _mode, _show, _store) \ - static struct device_attribute dev_attr_gt_##_name = __ATTR(gt_##_name, _mode, _show, _store); \ - static struct device_attribute dev_attr_rps_##_name = __ATTR(rps_##_name, _mode, _show, _store) - -#define INTEL_GT_RPS_SYSFS_ATTR_RO(_name) \ - INTEL_GT_RPS_SYSFS_ATTR(_name, 0444, _name##_show, NULL) -#define INTEL_GT_RPS_SYSFS_ATTR_RW(_name) \ - INTEL_GT_RPS_SYSFS_ATTR(_name, 0644, _name##_show, _name##_store) +INTEL_GT_SYSFS_SHOW_MAX(act_freq_mhz); +INTEL_GT_SYSFS_SHOW_MAX(boost_freq_mhz); +INTEL_GT_SYSFS_SHOW_MAX(cur_freq_mhz); +INTEL_GT_SYSFS_SHOW_MAX(RP0_freq_mhz); +INTEL_GT_SYSFS_SHOW_MAX(RP1_freq_mhz); +INTEL_GT_SYSFS_SHOW_MAX(RPn_freq_mhz); +INTEL_GT_SYSFS_SHOW_MAX(max_freq_mhz); +INTEL_GT_SYSFS_SHOW_MIN(min_freq_mhz); +INTEL_GT_SYSFS_SHOW_MAX(vlv_rpe_freq_mhz); +INTEL_GT_SYSFS_STORE(boost_freq_mhz, __boost_freq_mhz_store); +INTEL_GT_SYSFS_STORE(max_freq_mhz, __set_max_freq); +INTEL_GT_SYSFS_STORE(min_freq_mhz, __set_min_freq); + +#define INTEL_GT_RPS_SYSFS_ATTR(_name, _mode, _show, _store, _show_dev, _store_dev) \ + static struct device_attribute dev_attr_gt_##_name = __ATTR(gt_##_name, _mode, \ + _show_dev, _store_dev); \ + static struct kobj_attribute attr_rps_##_name = __ATTR(rps_##_name, _mode, \ + _show, _store) + +#define INTEL_GT_RPS_SYSFS_ATTR_RO(_name) \ + INTEL_GT_RPS_SYSFS_ATTR(_name, 0444, _name##_show, NULL, \ + _name##_dev_show, NULL) +#define INTEL_GT_RPS_SYSFS_ATTR_RW(_name) \ + INTEL_GT_RPS_SYSFS_ATTR(_name, 0644, _name##_show, _name##_store, \ + _name##_dev_show, _name##_dev_store) /* The below macros generate static structures */ INTEL_GT_RPS_SYSFS_ATTR_RO(act_freq_mhz); @@ -475,32 +432,31 @@ INTEL_GT_RPS_SYSFS_ATTR_RO(RP1_freq_mhz); INTEL_GT_RPS_SYSFS_ATTR_RO(RPn_freq_mhz); INTEL_GT_RPS_SYSFS_ATTR_RW(max_freq_mhz); INTEL_GT_RPS_SYSFS_ATTR_RW(min_freq_mhz); - -static DEVICE_ATTR_RO(vlv_rpe_freq_mhz); - -#define GEN6_ATTR(s) { \ - &dev_attr_##s##_act_freq_mhz.attr, \ - &dev_attr_##s##_cur_freq_mhz.attr, \ - &dev_attr_##s##_boost_freq_mhz.attr, \ - &dev_attr_##s##_max_freq_mhz.attr, \ - &dev_attr_##s##_min_freq_mhz.attr, \ - &dev_attr_##s##_RP0_freq_mhz.attr, \ - &dev_attr_##s##_RP1_freq_mhz.attr, \ - &dev_attr_##s##_RPn_freq_mhz.attr, \ +INTEL_GT_RPS_SYSFS_ATTR_RO(vlv_rpe_freq_mhz); + +#define GEN6_ATTR(p, s) { \ + &p##attr_##s##_act_freq_mhz.attr, \ + &p##attr_##s##_cur_freq_mhz.attr, \ + &p##attr_##s##_boost_freq_mhz.attr, \ + &p##attr_##s##_max_freq_mhz.attr, \ + &p##attr_##s##_min_freq_mhz.attr, \ + &p##attr_##s##_RP0_freq_mhz.attr, \ + &p##attr_##s##_RP1_freq_mhz.attr, \ + &p##attr_##s##_RPn_freq_mhz.attr, \ NULL, \ } -#define GEN6_RPS_ATTR GEN6_ATTR(rps) -#define GEN6_GT_ATTR GEN6_ATTR(gt) +#define GEN6_RPS_ATTR GEN6_ATTR(, rps) +#define GEN6_GT_ATTR GEN6_ATTR(dev_, gt) static const struct attribute * const gen6_rps_attrs[] = GEN6_RPS_ATTR; static const struct attribute * const gen6_gt_attrs[] = GEN6_GT_ATTR; -static ssize_t punit_req_freq_mhz_show(struct device *dev, - struct device_attribute *attr, +static ssize_t punit_req_freq_mhz_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buff) { - struct intel_gt *gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name); + struct intel_gt *gt = intel_gt_sysfs_get_drvdata(kobj, attr->attr.name); u32 preq = intel_rps_read_punit_req_frequency(>->rps); return sysfs_emit(buff, "%u\n", preq); @@ -508,17 +464,17 @@ static ssize_t punit_req_freq_mhz_show(struct device *dev, struct intel_gt_bool_throttle_attr { struct attribute attr; - ssize_t (*show)(struct device *dev, struct device_attribute *attr, + ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr, char *buf); i915_reg_t (*reg32)(struct intel_gt *gt); u32 mask; }; -static ssize_t throttle_reason_bool_show(struct device *dev, - struct device_attribute *attr, +static ssize_t throttle_reason_bool_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buff) { - struct intel_gt *gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name); + struct intel_gt *gt = intel_gt_sysfs_get_drvdata(kobj, attr->attr.name); struct intel_gt_bool_throttle_attr *t_attr = (struct intel_gt_bool_throttle_attr *) attr; bool val = rps_read_mask_mmio(>->rps, t_attr->reg32(gt), t_attr->mask); @@ -534,7 +490,7 @@ struct intel_gt_bool_throttle_attr attr_##sysfs_func__ = { \ .mask = mask__, \ } -static DEVICE_ATTR_RO(punit_req_freq_mhz); +INTEL_GT_ATTR_RO(punit_req_freq_mhz); static INTEL_GT_RPS_BOOL_ATTR_RO(throttle_reason_status, GT0_PERF_LIMIT_REASONS_MASK); static INTEL_GT_RPS_BOOL_ATTR_RO(throttle_reason_pl1, POWER_LIMIT_1_MASK); static INTEL_GT_RPS_BOOL_ATTR_RO(throttle_reason_pl2, POWER_LIMIT_2_MASK); @@ -597,8 +553,8 @@ static const struct attribute *throttle_reason_attrs[] = { #define U8_8_VAL_MASK 0xffff #define U8_8_SCALE_TO_VALUE "0.00390625" -static ssize_t freq_factor_scale_show(struct device *dev, - struct device_attribute *attr, +static ssize_t freq_factor_scale_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buff) { return sysfs_emit(buff, "%s\n", U8_8_SCALE_TO_VALUE); @@ -610,11 +566,11 @@ static u32 media_ratio_mode_to_factor(u32 mode) return !mode ? mode : 256 / mode; } -static ssize_t media_freq_factor_show(struct device *dev, - struct device_attribute *attr, +static ssize_t media_freq_factor_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buff) { - struct intel_gt *gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name); + struct intel_gt *gt = intel_gt_sysfs_get_drvdata(kobj, attr->attr.name); struct intel_guc_slpc *slpc = >->uc.guc.slpc; intel_wakeref_t wakeref; u32 mode; @@ -641,11 +597,11 @@ static ssize_t media_freq_factor_show(struct device *dev, return sysfs_emit(buff, "%u\n", media_ratio_mode_to_factor(mode)); } -static ssize_t media_freq_factor_store(struct device *dev, - struct device_attribute *attr, +static ssize_t media_freq_factor_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buff, size_t count) { - struct intel_gt *gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name); + struct intel_gt *gt = intel_gt_sysfs_get_drvdata(kobj, attr->attr.name); struct intel_guc_slpc *slpc = >->uc.guc.slpc; u32 factor, mode; int err; @@ -670,11 +626,11 @@ static ssize_t media_freq_factor_store(struct device *dev, return err ?: count; } -static ssize_t media_RP0_freq_mhz_show(struct device *dev, - struct device_attribute *attr, +static ssize_t media_RP0_freq_mhz_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buff) { - struct intel_gt *gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name); + struct intel_gt *gt = intel_gt_sysfs_get_drvdata(kobj, attr->attr.name); u32 val; int err; @@ -691,11 +647,11 @@ static ssize_t media_RP0_freq_mhz_show(struct device *dev, return sysfs_emit(buff, "%u\n", val); } -static ssize_t media_RPn_freq_mhz_show(struct device *dev, - struct device_attribute *attr, +static ssize_t media_RPn_freq_mhz_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buff) { - struct intel_gt *gt = intel_gt_sysfs_get_drvdata(dev, attr->attr.name); + struct intel_gt *gt = intel_gt_sysfs_get_drvdata(kobj, attr->attr.name); u32 val; int err; @@ -712,17 +668,17 @@ static ssize_t media_RPn_freq_mhz_show(struct device *dev, return sysfs_emit(buff, "%u\n", val); } -static DEVICE_ATTR_RW(media_freq_factor); -static struct device_attribute dev_attr_media_freq_factor_scale = +INTEL_GT_ATTR_RW(media_freq_factor); +static struct kobj_attribute attr_media_freq_factor_scale = __ATTR(media_freq_factor.scale, 0444, freq_factor_scale_show, NULL); -static DEVICE_ATTR_RO(media_RP0_freq_mhz); -static DEVICE_ATTR_RO(media_RPn_freq_mhz); +INTEL_GT_ATTR_RO(media_RP0_freq_mhz); +INTEL_GT_ATTR_RO(media_RPn_freq_mhz); static const struct attribute *media_perf_power_attrs[] = { - &dev_attr_media_freq_factor.attr, - &dev_attr_media_freq_factor_scale.attr, - &dev_attr_media_RP0_freq_mhz.attr, - &dev_attr_media_RPn_freq_mhz.attr, + &attr_media_freq_factor.attr, + &attr_media_freq_factor_scale.attr, + &attr_media_RP0_freq_mhz.attr, + &attr_media_RPn_freq_mhz.attr, NULL }; @@ -754,20 +710,29 @@ static const struct attribute * const rps_defaults_attrs[] = { NULL }; -static int intel_sysfs_rps_init(struct intel_gt *gt, struct kobject *kobj, - const struct attribute * const *attrs) +static int intel_sysfs_rps_init(struct intel_gt *gt, struct kobject *kobj) { + const struct attribute * const *attrs; + struct attribute *vlv_attr; int ret; if (GRAPHICS_VER(gt->i915) < 6) return 0; + if (is_object_gt(kobj)) { + attrs = gen6_rps_attrs; + vlv_attr = &attr_rps_vlv_rpe_freq_mhz.attr; + } else { + attrs = gen6_gt_attrs; + vlv_attr = &dev_attr_gt_vlv_rpe_freq_mhz.attr; + } + ret = sysfs_create_files(kobj, attrs); if (ret) return ret; if (IS_VALLEYVIEW(gt->i915) || IS_CHERRYVIEW(gt->i915)) - ret = sysfs_create_file(kobj, &dev_attr_vlv_rpe_freq_mhz.attr); + ret = sysfs_create_file(kobj, vlv_attr); return ret; } @@ -778,9 +743,7 @@ void intel_gt_sysfs_pm_init(struct intel_gt *gt, struct kobject *kobj) intel_sysfs_rc6_init(gt, kobj); - ret = is_object_gt(kobj) ? - intel_sysfs_rps_init(gt, kobj, gen6_rps_attrs) : - intel_sysfs_rps_init(gt, kobj, gen6_gt_attrs); + ret = intel_sysfs_rps_init(gt, kobj); if (ret) drm_warn(>->i915->drm, "failed to create gt%u RPS sysfs files (%pe)", @@ -790,7 +753,7 @@ void intel_gt_sysfs_pm_init(struct intel_gt *gt, struct kobject *kobj) if (!is_object_gt(kobj)) return; - ret = sysfs_create_file(kobj, &dev_attr_punit_req_freq_mhz.attr); + ret = sysfs_create_file(kobj, &attr_punit_req_freq_mhz.attr); if (ret) drm_warn(>->i915->drm, "failed to create gt%u punit_req_freq_mhz sysfs (%pe)", -- cgit From 46e61ee4e01e4a8a7e4e13a249d46c4cbc99ed88 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 26 Oct 2022 20:01:36 +0300 Subject: drm/i915/audio: s/dev_priv/i915/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename the 'dev_priv' variables to 'i915' in the audio code to match modern style conventions. v2: Drop some needless braces in intel_audio_hooks_init() Cc: Chaitanya Kumar Borah Cc: Kai Vehmanen Cc: Takashi Iwai Reviewed-by: Jani Nikula Reviewed-by: Kai Vehmanen Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221026170150.2654-2-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_audio.c | 391 ++++++++++++------------ drivers/gpu/drm/i915/display/intel_audio_regs.h | 2 +- 2 files changed, 196 insertions(+), 197 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c index aacbc6da84ef..aa70b3f075c3 100644 --- a/drivers/gpu/drm/i915/display/intel_audio.c +++ b/drivers/gpu/drm/i915/display/intel_audio.c @@ -250,7 +250,7 @@ static const struct hdmi_aud_ncts hdmi_aud_ncts_36bpp[] = { /* get AUD_CONFIG_PIXEL_CLOCK_HDMI_* value for mode */ static u32 audio_config_hdmi_pixel_clock(const struct intel_crtc_state *crtc_state) { - struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; int i; @@ -260,17 +260,17 @@ static u32 audio_config_hdmi_pixel_clock(const struct intel_crtc_state *crtc_sta break; } - if (DISPLAY_VER(dev_priv) < 12 && adjusted_mode->crtc_clock > 148500) + if (DISPLAY_VER(i915) < 12 && adjusted_mode->crtc_clock > 148500) i = ARRAY_SIZE(hdmi_audio_clock); if (i == ARRAY_SIZE(hdmi_audio_clock)) { - drm_dbg_kms(&dev_priv->drm, + drm_dbg_kms(&i915->drm, "HDMI audio pixel clock setting for %d not found, falling back to defaults\n", adjusted_mode->crtc_clock); i = 1; } - drm_dbg_kms(&dev_priv->drm, + drm_dbg_kms(&i915->drm, "Configuring HDMI audio for pixel clock %d (0x%08x)\n", hdmi_audio_clock[i].clock, hdmi_audio_clock[i].config); @@ -309,23 +309,23 @@ static bool intel_eld_uptodate(struct drm_connector *connector, i915_reg_t reg_elda, u32 bits_elda, i915_reg_t reg_edid) { - struct drm_i915_private *dev_priv = to_i915(connector->dev); + struct drm_i915_private *i915 = to_i915(connector->dev); const u8 *eld = connector->eld; u32 tmp; int i; - tmp = intel_de_read(dev_priv, reg_eldv); + tmp = intel_de_read(i915, reg_eldv); tmp &= bits_eldv; if (!tmp) return false; - tmp = intel_de_read(dev_priv, reg_elda); + tmp = intel_de_read(i915, reg_elda); tmp &= ~bits_elda; - intel_de_write(dev_priv, reg_elda, tmp); + intel_de_write(i915, reg_elda, tmp); for (i = 0; i < drm_eld_size(eld) / 4; i++) - if (intel_de_read(dev_priv, reg_edid) != *((const u32 *)eld + i)) + if (intel_de_read(i915, reg_edid) != *((const u32 *)eld + i)) return false; return true; @@ -335,33 +335,33 @@ static void g4x_audio_codec_disable(struct intel_encoder *encoder, const struct intel_crtc_state *old_crtc_state, const struct drm_connector_state *old_conn_state) { - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct drm_i915_private *i915 = to_i915(encoder->base.dev); u32 eldv, tmp; - tmp = intel_de_read(dev_priv, G4X_AUD_VID_DID); + tmp = intel_de_read(i915, G4X_AUD_VID_DID); if (tmp == INTEL_AUDIO_DEVBLC || tmp == INTEL_AUDIO_DEVCL) eldv = G4X_ELDV_DEVCL_DEVBLC; else eldv = G4X_ELDV_DEVCTG; /* Invalidate ELD */ - tmp = intel_de_read(dev_priv, G4X_AUD_CNTL_ST); + tmp = intel_de_read(i915, G4X_AUD_CNTL_ST); tmp &= ~eldv; - intel_de_write(dev_priv, G4X_AUD_CNTL_ST, tmp); + intel_de_write(i915, G4X_AUD_CNTL_ST, tmp); } static void g4x_audio_codec_enable(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state) { - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct drm_i915_private *i915 = to_i915(encoder->base.dev); struct drm_connector *connector = conn_state->connector; const u8 *eld = connector->eld; u32 eldv; u32 tmp; int len, i; - tmp = intel_de_read(dev_priv, G4X_AUD_VID_DID); + tmp = intel_de_read(i915, G4X_AUD_VID_DID); if (tmp == INTEL_AUDIO_DEVBLC || tmp == INTEL_AUDIO_DEVCL) eldv = G4X_ELDV_DEVCL_DEVBLC; else @@ -373,27 +373,27 @@ static void g4x_audio_codec_enable(struct intel_encoder *encoder, G4X_HDMIW_HDMIEDID)) return; - tmp = intel_de_read(dev_priv, G4X_AUD_CNTL_ST); + tmp = intel_de_read(i915, G4X_AUD_CNTL_ST); tmp &= ~(eldv | G4X_ELD_ADDR_MASK); len = (tmp >> 9) & 0x1f; /* ELD buffer size */ - intel_de_write(dev_priv, G4X_AUD_CNTL_ST, tmp); + intel_de_write(i915, G4X_AUD_CNTL_ST, tmp); len = min(drm_eld_size(eld) / 4, len); for (i = 0; i < len; i++) - intel_de_write(dev_priv, G4X_HDMIW_HDMIEDID, + intel_de_write(i915, G4X_HDMIW_HDMIEDID, *((const u32 *)eld + i)); - tmp = intel_de_read(dev_priv, G4X_AUD_CNTL_ST); + tmp = intel_de_read(i915, G4X_AUD_CNTL_ST); tmp |= eldv; - intel_de_write(dev_priv, G4X_AUD_CNTL_ST, tmp); + intel_de_write(i915, G4X_AUD_CNTL_ST, tmp); } static void hsw_dp_audio_config_update(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - struct i915_audio_component *acomp = dev_priv->display.audio.component; + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + struct i915_audio_component *acomp = i915->display.audio.component; enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; enum port port = encoder->port; const struct dp_aud_n_m *nm; @@ -403,12 +403,12 @@ hsw_dp_audio_config_update(struct intel_encoder *encoder, rate = acomp ? acomp->aud_sample_rate[port] : 0; nm = audio_config_dp_get_n_m(crtc_state, rate); if (nm) - drm_dbg_kms(&dev_priv->drm, "using Maud %u, Naud %u\n", nm->m, + drm_dbg_kms(&i915->drm, "using Maud %u, Naud %u\n", nm->m, nm->n); else - drm_dbg_kms(&dev_priv->drm, "using automatic Maud, Naud\n"); + drm_dbg_kms(&i915->drm, "using automatic Maud, Naud\n"); - tmp = intel_de_read(dev_priv, HSW_AUD_CFG(cpu_transcoder)); + tmp = intel_de_read(i915, HSW_AUD_CFG(cpu_transcoder)); tmp &= ~AUD_CONFIG_N_VALUE_INDEX; tmp &= ~AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK; tmp &= ~AUD_CONFIG_N_PROG_ENABLE; @@ -420,9 +420,9 @@ hsw_dp_audio_config_update(struct intel_encoder *encoder, tmp |= AUD_CONFIG_N_PROG_ENABLE; } - intel_de_write(dev_priv, HSW_AUD_CFG(cpu_transcoder), tmp); + intel_de_write(i915, HSW_AUD_CFG(cpu_transcoder), tmp); - tmp = intel_de_read(dev_priv, HSW_AUD_M_CTS_ENABLE(cpu_transcoder)); + tmp = intel_de_read(i915, HSW_AUD_M_CTS_ENABLE(cpu_transcoder)); tmp &= ~AUD_CONFIG_M_MASK; tmp &= ~AUD_M_CTS_M_VALUE_INDEX; tmp &= ~AUD_M_CTS_M_PROG_ENABLE; @@ -433,15 +433,15 @@ hsw_dp_audio_config_update(struct intel_encoder *encoder, tmp |= AUD_M_CTS_M_PROG_ENABLE; } - intel_de_write(dev_priv, HSW_AUD_M_CTS_ENABLE(cpu_transcoder), tmp); + intel_de_write(i915, HSW_AUD_M_CTS_ENABLE(cpu_transcoder), tmp); } static void hsw_hdmi_audio_config_update(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - struct i915_audio_component *acomp = dev_priv->display.audio.component; + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + struct i915_audio_component *acomp = i915->display.audio.component; enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; enum port port = encoder->port; int n, rate; @@ -449,7 +449,7 @@ hsw_hdmi_audio_config_update(struct intel_encoder *encoder, rate = acomp ? acomp->aud_sample_rate[port] : 0; - tmp = intel_de_read(dev_priv, HSW_AUD_CFG(cpu_transcoder)); + tmp = intel_de_read(i915, HSW_AUD_CFG(cpu_transcoder)); tmp &= ~AUD_CONFIG_N_VALUE_INDEX; tmp &= ~AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK; tmp &= ~AUD_CONFIG_N_PROG_ENABLE; @@ -457,25 +457,25 @@ hsw_hdmi_audio_config_update(struct intel_encoder *encoder, n = audio_config_hdmi_get_n(crtc_state, rate); if (n != 0) { - drm_dbg_kms(&dev_priv->drm, "using N %d\n", n); + drm_dbg_kms(&i915->drm, "using N %d\n", n); tmp &= ~AUD_CONFIG_N_MASK; tmp |= AUD_CONFIG_N(n); tmp |= AUD_CONFIG_N_PROG_ENABLE; } else { - drm_dbg_kms(&dev_priv->drm, "using automatic N\n"); + drm_dbg_kms(&i915->drm, "using automatic N\n"); } - intel_de_write(dev_priv, HSW_AUD_CFG(cpu_transcoder), tmp); + intel_de_write(i915, HSW_AUD_CFG(cpu_transcoder), tmp); /* * Let's disable "Enable CTS or M Prog bit" * and let HW calculate the value */ - tmp = intel_de_read(dev_priv, HSW_AUD_M_CTS_ENABLE(cpu_transcoder)); + tmp = intel_de_read(i915, HSW_AUD_M_CTS_ENABLE(cpu_transcoder)); tmp &= ~AUD_M_CTS_M_PROG_ENABLE; tmp &= ~AUD_M_CTS_M_VALUE_INDEX; - intel_de_write(dev_priv, HSW_AUD_M_CTS_ENABLE(cpu_transcoder), tmp); + intel_de_write(i915, HSW_AUD_M_CTS_ENABLE(cpu_transcoder), tmp); } static void @@ -492,29 +492,29 @@ static void hsw_audio_codec_disable(struct intel_encoder *encoder, const struct intel_crtc_state *old_crtc_state, const struct drm_connector_state *old_conn_state) { - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct drm_i915_private *i915 = to_i915(encoder->base.dev); enum transcoder cpu_transcoder = old_crtc_state->cpu_transcoder; u32 tmp; - mutex_lock(&dev_priv->display.audio.mutex); + mutex_lock(&i915->display.audio.mutex); /* Disable timestamps */ - tmp = intel_de_read(dev_priv, HSW_AUD_CFG(cpu_transcoder)); + tmp = intel_de_read(i915, HSW_AUD_CFG(cpu_transcoder)); tmp &= ~AUD_CONFIG_N_VALUE_INDEX; tmp |= AUD_CONFIG_N_PROG_ENABLE; tmp &= ~AUD_CONFIG_UPPER_N_MASK; tmp &= ~AUD_CONFIG_LOWER_N_MASK; if (intel_crtc_has_dp_encoder(old_crtc_state)) tmp |= AUD_CONFIG_N_VALUE_INDEX; - intel_de_write(dev_priv, HSW_AUD_CFG(cpu_transcoder), tmp); + intel_de_write(i915, HSW_AUD_CFG(cpu_transcoder), tmp); /* Invalidate ELD */ - tmp = intel_de_read(dev_priv, HSW_AUD_PIN_ELD_CP_VLD); + tmp = intel_de_read(i915, HSW_AUD_PIN_ELD_CP_VLD); tmp &= ~AUDIO_ELD_VALID(cpu_transcoder); tmp &= ~AUDIO_OUTPUT_ENABLE(cpu_transcoder); - intel_de_write(dev_priv, HSW_AUD_PIN_ELD_CP_VLD, tmp); + intel_de_write(i915, HSW_AUD_PIN_ELD_CP_VLD, tmp); - mutex_unlock(&dev_priv->display.audio.mutex); + mutex_unlock(&i915->display.audio.mutex); } static unsigned int calc_hblank_early_prog(struct intel_encoder *encoder, @@ -632,24 +632,24 @@ static void hsw_audio_codec_enable(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state) { - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct drm_i915_private *i915 = to_i915(encoder->base.dev); struct drm_connector *connector = conn_state->connector; enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; const u8 *eld = connector->eld; u32 tmp; int len, i; - mutex_lock(&dev_priv->display.audio.mutex); + mutex_lock(&i915->display.audio.mutex); /* Enable Audio WA for 4k DSC usecases */ if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP)) enable_audio_dsc_wa(encoder, crtc_state); /* Enable audio presence detect, invalidate ELD */ - tmp = intel_de_read(dev_priv, HSW_AUD_PIN_ELD_CP_VLD); + tmp = intel_de_read(i915, HSW_AUD_PIN_ELD_CP_VLD); tmp |= AUDIO_OUTPUT_ENABLE(cpu_transcoder); tmp &= ~AUDIO_ELD_VALID(cpu_transcoder); - intel_de_write(dev_priv, HSW_AUD_PIN_ELD_CP_VLD, tmp); + intel_de_write(i915, HSW_AUD_PIN_ELD_CP_VLD, tmp); /* * FIXME: We're supposed to wait for vblank here, but we have vblanks @@ -659,45 +659,45 @@ static void hsw_audio_codec_enable(struct intel_encoder *encoder, */ /* Reset ELD write address */ - tmp = intel_de_read(dev_priv, HSW_AUD_DIP_ELD_CTRL(cpu_transcoder)); + tmp = intel_de_read(i915, HSW_AUD_DIP_ELD_CTRL(cpu_transcoder)); tmp &= ~IBX_ELD_ADDRESS_MASK; - intel_de_write(dev_priv, HSW_AUD_DIP_ELD_CTRL(cpu_transcoder), tmp); + intel_de_write(i915, HSW_AUD_DIP_ELD_CTRL(cpu_transcoder), tmp); /* Up to 84 bytes of hw ELD buffer */ len = min(drm_eld_size(eld), 84); for (i = 0; i < len / 4; i++) - intel_de_write(dev_priv, HSW_AUD_EDID_DATA(cpu_transcoder), + intel_de_write(i915, HSW_AUD_EDID_DATA(cpu_transcoder), *((const u32 *)eld + i)); /* ELD valid */ - tmp = intel_de_read(dev_priv, HSW_AUD_PIN_ELD_CP_VLD); + tmp = intel_de_read(i915, HSW_AUD_PIN_ELD_CP_VLD); tmp |= AUDIO_ELD_VALID(cpu_transcoder); - intel_de_write(dev_priv, HSW_AUD_PIN_ELD_CP_VLD, tmp); + intel_de_write(i915, HSW_AUD_PIN_ELD_CP_VLD, tmp); /* Enable timestamps */ hsw_audio_config_update(encoder, crtc_state); - mutex_unlock(&dev_priv->display.audio.mutex); + mutex_unlock(&i915->display.audio.mutex); } static void ilk_audio_codec_disable(struct intel_encoder *encoder, const struct intel_crtc_state *old_crtc_state, const struct drm_connector_state *old_conn_state) { - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct drm_i915_private *i915 = to_i915(encoder->base.dev); struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc); enum pipe pipe = crtc->pipe; enum port port = encoder->port; u32 tmp, eldv; i915_reg_t aud_config, aud_cntrl_st2; - if (drm_WARN_ON(&dev_priv->drm, port == PORT_A)) + if (drm_WARN_ON(&i915->drm, port == PORT_A)) return; - if (HAS_PCH_IBX(dev_priv)) { + if (HAS_PCH_IBX(i915)) { aud_config = IBX_AUD_CFG(pipe); aud_cntrl_st2 = IBX_AUD_CNTL_ST2; - } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { + } else if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) { aud_config = VLV_AUD_CFG(pipe); aud_cntrl_st2 = VLV_AUD_CNTL_ST2; } else { @@ -706,28 +706,28 @@ static void ilk_audio_codec_disable(struct intel_encoder *encoder, } /* Disable timestamps */ - tmp = intel_de_read(dev_priv, aud_config); + tmp = intel_de_read(i915, aud_config); tmp &= ~AUD_CONFIG_N_VALUE_INDEX; tmp |= AUD_CONFIG_N_PROG_ENABLE; tmp &= ~AUD_CONFIG_UPPER_N_MASK; tmp &= ~AUD_CONFIG_LOWER_N_MASK; if (intel_crtc_has_dp_encoder(old_crtc_state)) tmp |= AUD_CONFIG_N_VALUE_INDEX; - intel_de_write(dev_priv, aud_config, tmp); + intel_de_write(i915, aud_config, tmp); eldv = IBX_ELD_VALID(port); /* Invalidate ELD */ - tmp = intel_de_read(dev_priv, aud_cntrl_st2); + tmp = intel_de_read(i915, aud_cntrl_st2); tmp &= ~eldv; - intel_de_write(dev_priv, aud_cntrl_st2, tmp); + intel_de_write(i915, aud_cntrl_st2, tmp); } static void ilk_audio_codec_enable(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state) { - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct drm_i915_private *i915 = to_i915(encoder->base.dev); struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_connector *connector = conn_state->connector; enum pipe pipe = crtc->pipe; @@ -737,7 +737,7 @@ static void ilk_audio_codec_enable(struct intel_encoder *encoder, int len, i; i915_reg_t hdmiw_hdmiedid, aud_config, aud_cntl_st, aud_cntrl_st2; - if (drm_WARN_ON(&dev_priv->drm, port == PORT_A)) + if (drm_WARN_ON(&i915->drm, port == PORT_A)) return; /* @@ -747,13 +747,13 @@ static void ilk_audio_codec_enable(struct intel_encoder *encoder, * infrastructure is not there yet. */ - if (HAS_PCH_IBX(dev_priv)) { + if (HAS_PCH_IBX(i915)) { hdmiw_hdmiedid = IBX_HDMIW_HDMIEDID(pipe); aud_config = IBX_AUD_CFG(pipe); aud_cntl_st = IBX_AUD_CNTL_ST(pipe); aud_cntrl_st2 = IBX_AUD_CNTL_ST2; - } else if (IS_VALLEYVIEW(dev_priv) || - IS_CHERRYVIEW(dev_priv)) { + } else if (IS_VALLEYVIEW(i915) || + IS_CHERRYVIEW(i915)) { hdmiw_hdmiedid = VLV_HDMIW_HDMIEDID(pipe); aud_config = VLV_AUD_CFG(pipe); aud_cntl_st = VLV_AUD_CNTL_ST(pipe); @@ -768,28 +768,28 @@ static void ilk_audio_codec_enable(struct intel_encoder *encoder, eldv = IBX_ELD_VALID(port); /* Invalidate ELD */ - tmp = intel_de_read(dev_priv, aud_cntrl_st2); + tmp = intel_de_read(i915, aud_cntrl_st2); tmp &= ~eldv; - intel_de_write(dev_priv, aud_cntrl_st2, tmp); + intel_de_write(i915, aud_cntrl_st2, tmp); /* Reset ELD write address */ - tmp = intel_de_read(dev_priv, aud_cntl_st); + tmp = intel_de_read(i915, aud_cntl_st); tmp &= ~IBX_ELD_ADDRESS_MASK; - intel_de_write(dev_priv, aud_cntl_st, tmp); + intel_de_write(i915, aud_cntl_st, tmp); /* Up to 84 bytes of hw ELD buffer */ len = min(drm_eld_size(eld), 84); for (i = 0; i < len / 4; i++) - intel_de_write(dev_priv, hdmiw_hdmiedid, + intel_de_write(i915, hdmiw_hdmiedid, *((const u32 *)eld + i)); /* ELD valid */ - tmp = intel_de_read(dev_priv, aud_cntrl_st2); + tmp = intel_de_read(i915, aud_cntrl_st2); tmp |= eldv; - intel_de_write(dev_priv, aud_cntrl_st2, tmp); + intel_de_write(i915, aud_cntrl_st2, tmp); /* Enable timestamps */ - tmp = intel_de_read(dev_priv, aud_config); + tmp = intel_de_read(i915, aud_config); tmp &= ~AUD_CONFIG_N_VALUE_INDEX; tmp &= ~AUD_CONFIG_N_PROG_ENABLE; tmp &= ~AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK; @@ -797,7 +797,7 @@ static void ilk_audio_codec_enable(struct intel_encoder *encoder, tmp |= AUD_CONFIG_N_VALUE_INDEX; else tmp |= audio_config_hdmi_pixel_clock(crtc_state); - intel_de_write(dev_priv, aud_config, tmp); + intel_de_write(i915, aud_config, tmp); } /** @@ -813,8 +813,8 @@ void intel_audio_codec_enable(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state) { - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - struct i915_audio_component *acomp = dev_priv->display.audio.component; + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + struct i915_audio_component *acomp = i915->display.audio.component; struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_connector *connector = conn_state->connector; const struct drm_display_mode *adjusted_mode = @@ -825,30 +825,30 @@ void intel_audio_codec_enable(struct intel_encoder *encoder, if (!crtc_state->has_audio) return; - drm_dbg_kms(&dev_priv->drm, "[CONNECTOR:%d:%s][ENCODER:%d:%s] Enable audio codec on pipe %c, %u bytes ELD\n", + drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s][ENCODER:%d:%s] Enable audio codec on pipe %c, %u bytes ELD\n", connector->base.id, connector->name, encoder->base.base.id, encoder->base.name, pipe_name(pipe), drm_eld_size(connector->eld)); /* FIXME precompute the ELD in .compute_config() */ if (!connector->eld[0]) - drm_dbg_kms(&dev_priv->drm, + drm_dbg_kms(&i915->drm, "Bogus ELD on [CONNECTOR:%d:%s]\n", connector->base.id, connector->name); connector->eld[6] = drm_av_sync_delay(connector, adjusted_mode) / 2; - if (dev_priv->display.funcs.audio) - dev_priv->display.funcs.audio->audio_codec_enable(encoder, + if (i915->display.funcs.audio) + i915->display.funcs.audio->audio_codec_enable(encoder, crtc_state, conn_state); - mutex_lock(&dev_priv->display.audio.mutex); + mutex_lock(&i915->display.audio.mutex); encoder->audio_connector = connector; /* referred in audio callbacks */ - dev_priv->display.audio.encoder_map[pipe] = encoder; - mutex_unlock(&dev_priv->display.audio.mutex); + i915->display.audio.encoder_map[pipe] = encoder; + mutex_unlock(&i915->display.audio.mutex); if (acomp && acomp->base.audio_ops && acomp->base.audio_ops->pin_eld_notify) { @@ -859,7 +859,7 @@ void intel_audio_codec_enable(struct intel_encoder *encoder, (int) port, (int) pipe); } - intel_lpe_audio_notify(dev_priv, pipe, port, connector->eld, + intel_lpe_audio_notify(i915, pipe, port, connector->eld, crtc_state->port_clock, intel_crtc_has_dp_encoder(crtc_state)); } @@ -877,8 +877,8 @@ void intel_audio_codec_disable(struct intel_encoder *encoder, const struct intel_crtc_state *old_crtc_state, const struct drm_connector_state *old_conn_state) { - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - struct i915_audio_component *acomp = dev_priv->display.audio.component; + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + struct i915_audio_component *acomp = i915->display.audio.component; struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc); struct drm_connector *connector = old_conn_state->connector; enum port port = encoder->port; @@ -887,19 +887,19 @@ void intel_audio_codec_disable(struct intel_encoder *encoder, if (!old_crtc_state->has_audio) return; - drm_dbg_kms(&dev_priv->drm, "[CONNECTOR:%d:%s][ENCODER:%d:%s] Disable audio codec on pipe %c\n", + drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s][ENCODER:%d:%s] Disable audio codec on pipe %c\n", connector->base.id, connector->name, encoder->base.base.id, encoder->base.name, pipe_name(pipe)); - if (dev_priv->display.funcs.audio) - dev_priv->display.funcs.audio->audio_codec_disable(encoder, + if (i915->display.funcs.audio) + i915->display.funcs.audio->audio_codec_disable(encoder, old_crtc_state, old_conn_state); - mutex_lock(&dev_priv->display.audio.mutex); + mutex_lock(&i915->display.audio.mutex); encoder->audio_connector = NULL; - dev_priv->display.audio.encoder_map[pipe] = NULL; - mutex_unlock(&dev_priv->display.audio.mutex); + i915->display.audio.encoder_map[pipe] = NULL; + mutex_unlock(&i915->display.audio.mutex); if (acomp && acomp->base.audio_ops && acomp->base.audio_ops->pin_eld_notify) { @@ -910,7 +910,7 @@ void intel_audio_codec_disable(struct intel_encoder *encoder, (int) port, (int) pipe); } - intel_lpe_audio_notify(dev_priv, pipe, port, NULL, 0, false); + intel_lpe_audio_notify(i915, pipe, port, NULL, 0, false); } static const struct intel_audio_funcs g4x_audio_funcs = { @@ -930,19 +930,18 @@ static const struct intel_audio_funcs hsw_audio_funcs = { /** * intel_audio_hooks_init - Set up chip specific audio hooks - * @dev_priv: device private + * @i915: device private */ -void intel_audio_hooks_init(struct drm_i915_private *dev_priv) +void intel_audio_hooks_init(struct drm_i915_private *i915) { - if (IS_G4X(dev_priv)) { - dev_priv->display.funcs.audio = &g4x_audio_funcs; - } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { - dev_priv->display.funcs.audio = &ilk_audio_funcs; - } else if (IS_HASWELL(dev_priv) || DISPLAY_VER(dev_priv) >= 8) { - dev_priv->display.funcs.audio = &hsw_audio_funcs; - } else if (HAS_PCH_SPLIT(dev_priv)) { - dev_priv->display.funcs.audio = &ilk_audio_funcs; - } + if (IS_G4X(i915)) + i915->display.funcs.audio = &g4x_audio_funcs; + else if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) + i915->display.funcs.audio = &ilk_audio_funcs; + else if (IS_HASWELL(i915) || DISPLAY_VER(i915) >= 8) + i915->display.funcs.audio = &hsw_audio_funcs; + else if (HAS_PCH_SPLIT(i915)) + i915->display.funcs.audio = &ilk_audio_funcs; } struct aud_ts_cdclk_m_n { @@ -1000,7 +999,7 @@ static int glk_force_audio_cdclk_commit(struct intel_atomic_state *state, return drm_atomic_commit(&state->base); } -static void glk_force_audio_cdclk(struct drm_i915_private *dev_priv, +static void glk_force_audio_cdclk(struct drm_i915_private *i915, bool enable) { struct drm_modeset_acquire_ctx ctx; @@ -1008,13 +1007,13 @@ static void glk_force_audio_cdclk(struct drm_i915_private *dev_priv, struct intel_crtc *crtc; int ret; - crtc = intel_first_crtc(dev_priv); + crtc = intel_first_crtc(i915); if (!crtc) return; drm_modeset_acquire_init(&ctx, 0); - state = drm_atomic_state_alloc(&dev_priv->drm); - if (drm_WARN_ON(&dev_priv->drm, !state)) + state = drm_atomic_state_alloc(&i915->drm); + if (drm_WARN_ON(&i915->drm, !state)) return; state->acquire_ctx = &ctx; @@ -1028,7 +1027,7 @@ retry: goto retry; } - drm_WARN_ON(&dev_priv->drm, ret); + drm_WARN_ON(&i915->drm, ret); drm_atomic_state_put(state); @@ -1038,30 +1037,30 @@ retry: static unsigned long i915_audio_component_get_power(struct device *kdev) { - struct drm_i915_private *dev_priv = kdev_to_i915(kdev); + struct drm_i915_private *i915 = kdev_to_i915(kdev); intel_wakeref_t ret; /* Catch potential impedance mismatches before they occur! */ BUILD_BUG_ON(sizeof(intel_wakeref_t) > sizeof(unsigned long)); - ret = intel_display_power_get(dev_priv, POWER_DOMAIN_AUDIO_PLAYBACK); + ret = intel_display_power_get(i915, POWER_DOMAIN_AUDIO_PLAYBACK); - if (dev_priv->display.audio.power_refcount++ == 0) { - if (DISPLAY_VER(dev_priv) >= 9) { - intel_de_write(dev_priv, AUD_FREQ_CNTRL, - dev_priv->display.audio.freq_cntrl); - drm_dbg_kms(&dev_priv->drm, + if (i915->display.audio.power_refcount++ == 0) { + if (DISPLAY_VER(i915) >= 9) { + intel_de_write(i915, AUD_FREQ_CNTRL, + i915->display.audio.freq_cntrl); + drm_dbg_kms(&i915->drm, "restored AUD_FREQ_CNTRL to 0x%x\n", - dev_priv->display.audio.freq_cntrl); + i915->display.audio.freq_cntrl); } /* Force CDCLK to 2*BCLK as long as we need audio powered. */ - if (IS_GEMINILAKE(dev_priv)) - glk_force_audio_cdclk(dev_priv, true); + if (IS_GEMINILAKE(i915)) + glk_force_audio_cdclk(i915, true); - if (DISPLAY_VER(dev_priv) >= 10) - intel_de_write(dev_priv, AUD_PIN_BUF_CTL, - (intel_de_read(dev_priv, AUD_PIN_BUF_CTL) | AUD_PIN_BUF_ENABLE)); + if (DISPLAY_VER(i915) >= 10) + intel_de_write(i915, AUD_PIN_BUF_CTL, + (intel_de_read(i915, AUD_PIN_BUF_CTL) | AUD_PIN_BUF_ENABLE)); } return ret; @@ -1070,24 +1069,24 @@ static unsigned long i915_audio_component_get_power(struct device *kdev) static void i915_audio_component_put_power(struct device *kdev, unsigned long cookie) { - struct drm_i915_private *dev_priv = kdev_to_i915(kdev); + struct drm_i915_private *i915 = kdev_to_i915(kdev); /* Stop forcing CDCLK to 2*BCLK if no need for audio to be powered. */ - if (--dev_priv->display.audio.power_refcount == 0) - if (IS_GEMINILAKE(dev_priv)) - glk_force_audio_cdclk(dev_priv, false); + if (--i915->display.audio.power_refcount == 0) + if (IS_GEMINILAKE(i915)) + glk_force_audio_cdclk(i915, false); - intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO_PLAYBACK, cookie); + intel_display_power_put(i915, POWER_DOMAIN_AUDIO_PLAYBACK, cookie); } static void i915_audio_component_codec_wake_override(struct device *kdev, bool enable) { - struct drm_i915_private *dev_priv = kdev_to_i915(kdev); + struct drm_i915_private *i915 = kdev_to_i915(kdev); unsigned long cookie; u32 tmp; - if (DISPLAY_VER(dev_priv) < 9) + if (DISPLAY_VER(i915) < 9) return; cookie = i915_audio_component_get_power(kdev); @@ -1096,15 +1095,15 @@ static void i915_audio_component_codec_wake_override(struct device *kdev, * Enable/disable generating the codec wake signal, overriding the * internal logic to generate the codec wake to controller. */ - tmp = intel_de_read(dev_priv, HSW_AUD_CHICKENBIT); + tmp = intel_de_read(i915, HSW_AUD_CHICKENBIT); tmp &= ~SKL_AUD_CODEC_WAKE_SIGNAL; - intel_de_write(dev_priv, HSW_AUD_CHICKENBIT, tmp); + intel_de_write(i915, HSW_AUD_CHICKENBIT, tmp); usleep_range(1000, 1500); if (enable) { - tmp = intel_de_read(dev_priv, HSW_AUD_CHICKENBIT); + tmp = intel_de_read(i915, HSW_AUD_CHICKENBIT); tmp |= SKL_AUD_CODEC_WAKE_SIGNAL; - intel_de_write(dev_priv, HSW_AUD_CHICKENBIT, tmp); + intel_de_write(i915, HSW_AUD_CHICKENBIT, tmp); usleep_range(1000, 1500); } @@ -1114,12 +1113,12 @@ static void i915_audio_component_codec_wake_override(struct device *kdev, /* Get CDCLK in kHz */ static int i915_audio_component_get_cdclk_freq(struct device *kdev) { - struct drm_i915_private *dev_priv = kdev_to_i915(kdev); + struct drm_i915_private *i915 = kdev_to_i915(kdev); - if (drm_WARN_ON_ONCE(&dev_priv->drm, !HAS_DDI(dev_priv))) + if (drm_WARN_ON_ONCE(&i915->drm, !HAS_DDI(i915))) return -ENODEV; - return dev_priv->display.cdclk.hw.cdclk; + return i915->display.cdclk.hw.cdclk; } /* @@ -1132,18 +1131,18 @@ static int i915_audio_component_get_cdclk_freq(struct device *kdev) * will get the right intel_encoder with port matched * Non-MST & (pipe < 0): get the right intel_encoder with port matched */ -static struct intel_encoder *get_saved_enc(struct drm_i915_private *dev_priv, - int port, int pipe) +static struct intel_encoder *get_saved_enc(struct drm_i915_private *i915, + int port, int pipe) { struct intel_encoder *encoder; /* MST */ if (pipe >= 0) { - if (drm_WARN_ON(&dev_priv->drm, - pipe >= ARRAY_SIZE(dev_priv->display.audio.encoder_map))) + if (drm_WARN_ON(&i915->drm, + pipe >= ARRAY_SIZE(i915->display.audio.encoder_map))) return NULL; - encoder = dev_priv->display.audio.encoder_map[pipe]; + encoder = i915->display.audio.encoder_map[pipe]; /* * when bootup, audio driver may not know it is * MST or not. So it will poll all the port & pipe @@ -1158,8 +1157,8 @@ static struct intel_encoder *get_saved_enc(struct drm_i915_private *dev_priv, if (pipe > 0) return NULL; - for_each_pipe(dev_priv, pipe) { - encoder = dev_priv->display.audio.encoder_map[pipe]; + for_each_pipe(i915, pipe) { + encoder = i915->display.audio.encoder_map[pipe]; if (encoder == NULL) continue; @@ -1176,23 +1175,23 @@ static struct intel_encoder *get_saved_enc(struct drm_i915_private *dev_priv, static int i915_audio_component_sync_audio_rate(struct device *kdev, int port, int pipe, int rate) { - struct drm_i915_private *dev_priv = kdev_to_i915(kdev); - struct i915_audio_component *acomp = dev_priv->display.audio.component; + struct drm_i915_private *i915 = kdev_to_i915(kdev); + struct i915_audio_component *acomp = i915->display.audio.component; struct intel_encoder *encoder; struct intel_crtc *crtc; unsigned long cookie; int err = 0; - if (!HAS_DDI(dev_priv)) + if (!HAS_DDI(i915)) return 0; cookie = i915_audio_component_get_power(kdev); - mutex_lock(&dev_priv->display.audio.mutex); + mutex_lock(&i915->display.audio.mutex); /* 1. get the pipe */ - encoder = get_saved_enc(dev_priv, port, pipe); + encoder = get_saved_enc(i915, port, pipe); if (!encoder || !encoder->base.crtc) { - drm_dbg_kms(&dev_priv->drm, "Not valid for port %c\n", + drm_dbg_kms(&i915->drm, "Not valid for port %c\n", port_name(port)); err = -ENODEV; goto unlock; @@ -1206,7 +1205,7 @@ static int i915_audio_component_sync_audio_rate(struct device *kdev, int port, hsw_audio_config_update(encoder, crtc->config); unlock: - mutex_unlock(&dev_priv->display.audio.mutex); + mutex_unlock(&i915->display.audio.mutex); i915_audio_component_put_power(kdev, cookie); return err; } @@ -1215,18 +1214,18 @@ static int i915_audio_component_get_eld(struct device *kdev, int port, int pipe, bool *enabled, unsigned char *buf, int max_bytes) { - struct drm_i915_private *dev_priv = kdev_to_i915(kdev); + struct drm_i915_private *i915 = kdev_to_i915(kdev); struct intel_encoder *intel_encoder; const u8 *eld; int ret = -EINVAL; - mutex_lock(&dev_priv->display.audio.mutex); + mutex_lock(&i915->display.audio.mutex); - intel_encoder = get_saved_enc(dev_priv, port, pipe); + intel_encoder = get_saved_enc(i915, port, pipe); if (!intel_encoder) { - drm_dbg_kms(&dev_priv->drm, "Not valid for port %c\n", + drm_dbg_kms(&i915->drm, "Not valid for port %c\n", port_name(port)); - mutex_unlock(&dev_priv->display.audio.mutex); + mutex_unlock(&i915->display.audio.mutex); return ret; } @@ -1238,7 +1237,7 @@ static int i915_audio_component_get_eld(struct device *kdev, int port, memcpy(buf, eld, min(max_bytes, ret)); } - mutex_unlock(&dev_priv->display.audio.mutex); + mutex_unlock(&i915->display.audio.mutex); return ret; } @@ -1256,25 +1255,25 @@ static int i915_audio_component_bind(struct device *i915_kdev, struct device *hda_kdev, void *data) { struct i915_audio_component *acomp = data; - struct drm_i915_private *dev_priv = kdev_to_i915(i915_kdev); + struct drm_i915_private *i915 = kdev_to_i915(i915_kdev); int i; - if (drm_WARN_ON(&dev_priv->drm, acomp->base.ops || acomp->base.dev)) + if (drm_WARN_ON(&i915->drm, acomp->base.ops || acomp->base.dev)) return -EEXIST; - if (drm_WARN_ON(&dev_priv->drm, + if (drm_WARN_ON(&i915->drm, !device_link_add(hda_kdev, i915_kdev, DL_FLAG_STATELESS))) return -ENOMEM; - drm_modeset_lock_all(&dev_priv->drm); + drm_modeset_lock_all(&i915->drm); acomp->base.ops = &i915_audio_component_ops; acomp->base.dev = i915_kdev; BUILD_BUG_ON(MAX_PORTS != I915_MAX_PORTS); for (i = 0; i < ARRAY_SIZE(acomp->aud_sample_rate); i++) acomp->aud_sample_rate[i] = 0; - dev_priv->display.audio.component = acomp; - drm_modeset_unlock_all(&dev_priv->drm); + i915->display.audio.component = acomp; + drm_modeset_unlock_all(&i915->drm); return 0; } @@ -1283,19 +1282,19 @@ static void i915_audio_component_unbind(struct device *i915_kdev, struct device *hda_kdev, void *data) { struct i915_audio_component *acomp = data; - struct drm_i915_private *dev_priv = kdev_to_i915(i915_kdev); + struct drm_i915_private *i915 = kdev_to_i915(i915_kdev); - drm_modeset_lock_all(&dev_priv->drm); + drm_modeset_lock_all(&i915->drm); acomp->base.ops = NULL; acomp->base.dev = NULL; - dev_priv->display.audio.component = NULL; - drm_modeset_unlock_all(&dev_priv->drm); + i915->display.audio.component = NULL; + drm_modeset_unlock_all(&i915->drm); device_link_remove(hda_kdev, i915_kdev); - if (dev_priv->display.audio.power_refcount) - drm_err(&dev_priv->drm, "audio power refcount %d after unbind\n", - dev_priv->display.audio.power_refcount); + if (i915->display.audio.power_refcount) + drm_err(&i915->drm, "audio power refcount %d after unbind\n", + i915->display.audio.power_refcount); } static const struct component_ops i915_audio_component_bind_ops = { @@ -1314,7 +1313,7 @@ static const struct component_ops i915_audio_component_bind_ops = { /** * i915_audio_component_init - initialize and register the audio component - * @dev_priv: i915 device instance + * @i915: i915 device instance * * This will register with the component framework a child component which * will bind dynamically to the snd_hda_intel driver's corresponding master @@ -1328,83 +1327,83 @@ static const struct component_ops i915_audio_component_bind_ops = { * We ignore any error during registration and continue with reduced * functionality (i.e. without HDMI audio). */ -static void i915_audio_component_init(struct drm_i915_private *dev_priv) +static void i915_audio_component_init(struct drm_i915_private *i915) { u32 aud_freq, aud_freq_init; int ret; - ret = component_add_typed(dev_priv->drm.dev, + ret = component_add_typed(i915->drm.dev, &i915_audio_component_bind_ops, I915_COMPONENT_AUDIO); if (ret < 0) { - drm_err(&dev_priv->drm, + drm_err(&i915->drm, "failed to add audio component (%d)\n", ret); /* continue with reduced functionality */ return; } - if (DISPLAY_VER(dev_priv) >= 9) { - aud_freq_init = intel_de_read(dev_priv, AUD_FREQ_CNTRL); + if (DISPLAY_VER(i915) >= 9) { + aud_freq_init = intel_de_read(i915, AUD_FREQ_CNTRL); - if (DISPLAY_VER(dev_priv) >= 12) + if (DISPLAY_VER(i915) >= 12) aud_freq = AUD_FREQ_GEN12; else aud_freq = aud_freq_init; /* use BIOS provided value for TGL and RKL unless it is a known bad value */ - if ((IS_TIGERLAKE(dev_priv) || IS_ROCKETLAKE(dev_priv)) && + if ((IS_TIGERLAKE(i915) || IS_ROCKETLAKE(i915)) && aud_freq_init != AUD_FREQ_TGL_BROKEN) aud_freq = aud_freq_init; - drm_dbg_kms(&dev_priv->drm, "use AUD_FREQ_CNTRL of 0x%x (init value 0x%x)\n", + drm_dbg_kms(&i915->drm, "use AUD_FREQ_CNTRL of 0x%x (init value 0x%x)\n", aud_freq, aud_freq_init); - dev_priv->display.audio.freq_cntrl = aud_freq; + i915->display.audio.freq_cntrl = aud_freq; } /* init with current cdclk */ - intel_audio_cdclk_change_post(dev_priv); + intel_audio_cdclk_change_post(i915); - dev_priv->display.audio.component_registered = true; + i915->display.audio.component_registered = true; } /** * i915_audio_component_cleanup - deregister the audio component - * @dev_priv: i915 device instance + * @i915: i915 device instance * * Deregisters the audio component, breaking any existing binding to the * corresponding snd_hda_intel driver's master component. */ -static void i915_audio_component_cleanup(struct drm_i915_private *dev_priv) +static void i915_audio_component_cleanup(struct drm_i915_private *i915) { - if (!dev_priv->display.audio.component_registered) + if (!i915->display.audio.component_registered) return; - component_del(dev_priv->drm.dev, &i915_audio_component_bind_ops); - dev_priv->display.audio.component_registered = false; + component_del(i915->drm.dev, &i915_audio_component_bind_ops); + i915->display.audio.component_registered = false; } /** * intel_audio_init() - Initialize the audio driver either using * component framework or using lpe audio bridge - * @dev_priv: the i915 drm device private data + * @i915: the i915 drm device private data * */ -void intel_audio_init(struct drm_i915_private *dev_priv) +void intel_audio_init(struct drm_i915_private *i915) { - if (intel_lpe_audio_init(dev_priv) < 0) - i915_audio_component_init(dev_priv); + if (intel_lpe_audio_init(i915) < 0) + i915_audio_component_init(i915); } /** * intel_audio_deinit() - deinitialize the audio driver - * @dev_priv: the i915 drm device private data + * @i915: the i915 drm device private data * */ -void intel_audio_deinit(struct drm_i915_private *dev_priv) +void intel_audio_deinit(struct drm_i915_private *i915) { - if (dev_priv->display.audio.lpe.platdev != NULL) - intel_lpe_audio_teardown(dev_priv); + if (i915->display.audio.lpe.platdev != NULL) + intel_lpe_audio_teardown(i915); else - i915_audio_component_cleanup(dev_priv); + i915_audio_component_cleanup(i915); } diff --git a/drivers/gpu/drm/i915/display/intel_audio_regs.h b/drivers/gpu/drm/i915/display/intel_audio_regs.h index d1e5844e3484..e25248cdac51 100644 --- a/drivers/gpu/drm/i915/display/intel_audio_regs.h +++ b/drivers/gpu/drm/i915/display/intel_audio_regs.h @@ -8,7 +8,7 @@ #include "i915_reg_defs.h" -#define G4X_AUD_VID_DID _MMIO(DISPLAY_MMIO_BASE(dev_priv) + 0x62020) +#define G4X_AUD_VID_DID _MMIO(DISPLAY_MMIO_BASE(i915) + 0x62020) #define INTEL_AUDIO_DEVCL 0x808629FB #define INTEL_AUDIO_DEVBLC 0x80862801 #define INTEL_AUDIO_DEVCTG 0x80862802 -- cgit From 0ff6b8eafd1800b245b2601688d8e202649167cf Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 26 Oct 2022 20:01:37 +0300 Subject: drm/i915/audio: Nuke leftover ROUNDING_FACTOR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove some leftovers I missed in commit 2dd43144e824 ("drm/i915: Streamline the artihmetic") Cc: Chaitanya Kumar Borah Cc: Kai Vehmanen Cc: Takashi Iwai Reviewed-by: Jani Nikula Reviewed-by: Kai Vehmanen Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221026170150.2654-3-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_audio.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c index aa70b3f075c3..c6e7cecc6690 100644 --- a/drivers/gpu/drm/i915/display/intel_audio.c +++ b/drivers/gpu/drm/i915/display/intel_audio.c @@ -626,8 +626,6 @@ static void enable_audio_dsc_wa(struct intel_encoder *encoder, intel_de_write(i915, AUD_CONFIG_BE, val); } -#undef ROUNDING_FACTOR - static void hsw_audio_codec_enable(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state) -- cgit From b87a9a128bf00e496376c038f51c638b12782833 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 26 Oct 2022 20:01:38 +0300 Subject: drm/i915/audio: Remove CL/BLC audio stuff MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don't use the audio code on crestline (CL) since it doesn't support native HDMI output, and SDVO has it's own way of doing audio. And Bearlake-C (BLC) doesn't even exist in the real world, so no point it trying to deal with it. Cc: Chaitanya Kumar Borah Cc: Kai Vehmanen Cc: Takashi Iwai Reviewed-by: Jani Nikula Reviewed-by: Kai Vehmanen Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221026170150.2654-4-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_audio.c | 23 +++++------------------ drivers/gpu/drm/i915/display/intel_audio_regs.h | 8 +------- 2 files changed, 6 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c index c6e7cecc6690..b91167eaf71f 100644 --- a/drivers/gpu/drm/i915/display/intel_audio.c +++ b/drivers/gpu/drm/i915/display/intel_audio.c @@ -336,17 +336,11 @@ static void g4x_audio_codec_disable(struct intel_encoder *encoder, const struct drm_connector_state *old_conn_state) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); - u32 eldv, tmp; - - tmp = intel_de_read(i915, G4X_AUD_VID_DID); - if (tmp == INTEL_AUDIO_DEVBLC || tmp == INTEL_AUDIO_DEVCL) - eldv = G4X_ELDV_DEVCL_DEVBLC; - else - eldv = G4X_ELDV_DEVCTG; + u32 tmp; /* Invalidate ELD */ tmp = intel_de_read(i915, G4X_AUD_CNTL_ST); - tmp &= ~eldv; + tmp &= ~G4X_ELDV; intel_de_write(i915, G4X_AUD_CNTL_ST, tmp); } @@ -357,24 +351,17 @@ static void g4x_audio_codec_enable(struct intel_encoder *encoder, struct drm_i915_private *i915 = to_i915(encoder->base.dev); struct drm_connector *connector = conn_state->connector; const u8 *eld = connector->eld; - u32 eldv; u32 tmp; int len, i; - tmp = intel_de_read(i915, G4X_AUD_VID_DID); - if (tmp == INTEL_AUDIO_DEVBLC || tmp == INTEL_AUDIO_DEVCL) - eldv = G4X_ELDV_DEVCL_DEVBLC; - else - eldv = G4X_ELDV_DEVCTG; - if (intel_eld_uptodate(connector, - G4X_AUD_CNTL_ST, eldv, + G4X_AUD_CNTL_ST, G4X_ELDV, G4X_AUD_CNTL_ST, G4X_ELD_ADDR_MASK, G4X_HDMIW_HDMIEDID)) return; tmp = intel_de_read(i915, G4X_AUD_CNTL_ST); - tmp &= ~(eldv | G4X_ELD_ADDR_MASK); + tmp &= ~(G4X_ELDV | G4X_ELD_ADDR_MASK); len = (tmp >> 9) & 0x1f; /* ELD buffer size */ intel_de_write(i915, G4X_AUD_CNTL_ST, tmp); @@ -384,7 +371,7 @@ static void g4x_audio_codec_enable(struct intel_encoder *encoder, *((const u32 *)eld + i)); tmp = intel_de_read(i915, G4X_AUD_CNTL_ST); - tmp |= eldv; + tmp |= G4X_ELDV; intel_de_write(i915, G4X_AUD_CNTL_ST, tmp); } diff --git a/drivers/gpu/drm/i915/display/intel_audio_regs.h b/drivers/gpu/drm/i915/display/intel_audio_regs.h index e25248cdac51..ebbdd0654919 100644 --- a/drivers/gpu/drm/i915/display/intel_audio_regs.h +++ b/drivers/gpu/drm/i915/display/intel_audio_regs.h @@ -8,14 +8,8 @@ #include "i915_reg_defs.h" -#define G4X_AUD_VID_DID _MMIO(DISPLAY_MMIO_BASE(i915) + 0x62020) -#define INTEL_AUDIO_DEVCL 0x808629FB -#define INTEL_AUDIO_DEVBLC 0x80862801 -#define INTEL_AUDIO_DEVCTG 0x80862802 - #define G4X_AUD_CNTL_ST _MMIO(0x620B4) -#define G4X_ELDV_DEVCL_DEVBLC (1 << 13) -#define G4X_ELDV_DEVCTG (1 << 14) +#define G4X_ELDV (1 << 14) #define G4X_ELD_ADDR_MASK (0xf << 5) #define G4X_ELD_ACK (1 << 4) #define G4X_HDMIW_HDMIEDID _MMIO(0x6210C) -- cgit From 669d7fd64099b400759a9b0ca54d92da8330d1a1 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 26 Oct 2022 20:01:39 +0300 Subject: drm/i915/audio: Extract struct ilk_audio_regs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "ilk" audio codec codepaths have some duplicated code to figure out the correct registers to use on each platform. Extrat that into a single place. Cc: Chaitanya Kumar Borah Cc: Kai Vehmanen Cc: Takashi Iwai Reviewed-by: Jani Nikula Reviewed-by: Kai Vehmanen Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221026170150.2654-5-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_audio.c | 85 +++++++++++++++--------------- 1 file changed, 43 insertions(+), 42 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c index b91167eaf71f..e35fabf8d86e 100644 --- a/drivers/gpu/drm/i915/display/intel_audio.c +++ b/drivers/gpu/drm/i915/display/intel_audio.c @@ -665,6 +665,32 @@ static void hsw_audio_codec_enable(struct intel_encoder *encoder, mutex_unlock(&i915->display.audio.mutex); } +struct ilk_audio_regs { + i915_reg_t hdmiw_hdmiedid, aud_config, aud_cntl_st, aud_cntrl_st2; +}; + +static void ilk_audio_regs_init(struct drm_i915_private *i915, + enum pipe pipe, + struct ilk_audio_regs *regs) +{ + if (HAS_PCH_IBX(i915)) { + regs->hdmiw_hdmiedid = IBX_HDMIW_HDMIEDID(pipe); + regs->aud_config = IBX_AUD_CFG(pipe); + regs->aud_cntl_st = IBX_AUD_CNTL_ST(pipe); + regs->aud_cntrl_st2 = IBX_AUD_CNTL_ST2; + } else if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) { + regs->hdmiw_hdmiedid = VLV_HDMIW_HDMIEDID(pipe); + regs->aud_config = VLV_AUD_CFG(pipe); + regs->aud_cntl_st = VLV_AUD_CNTL_ST(pipe); + regs->aud_cntrl_st2 = VLV_AUD_CNTL_ST2; + } else { + regs->hdmiw_hdmiedid = CPT_HDMIW_HDMIEDID(pipe); + regs->aud_config = CPT_AUD_CFG(pipe); + regs->aud_cntl_st = CPT_AUD_CNTL_ST(pipe); + regs->aud_cntrl_st2 = CPT_AUD_CNTRL_ST2; + } +} + static void ilk_audio_codec_disable(struct intel_encoder *encoder, const struct intel_crtc_state *old_crtc_state, const struct drm_connector_state *old_conn_state) @@ -673,39 +699,30 @@ static void ilk_audio_codec_disable(struct intel_encoder *encoder, struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc); enum pipe pipe = crtc->pipe; enum port port = encoder->port; + struct ilk_audio_regs regs; u32 tmp, eldv; - i915_reg_t aud_config, aud_cntrl_st2; if (drm_WARN_ON(&i915->drm, port == PORT_A)) return; - if (HAS_PCH_IBX(i915)) { - aud_config = IBX_AUD_CFG(pipe); - aud_cntrl_st2 = IBX_AUD_CNTL_ST2; - } else if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) { - aud_config = VLV_AUD_CFG(pipe); - aud_cntrl_st2 = VLV_AUD_CNTL_ST2; - } else { - aud_config = CPT_AUD_CFG(pipe); - aud_cntrl_st2 = CPT_AUD_CNTRL_ST2; - } + ilk_audio_regs_init(i915, pipe, ®s); /* Disable timestamps */ - tmp = intel_de_read(i915, aud_config); + tmp = intel_de_read(i915, regs.aud_config); tmp &= ~AUD_CONFIG_N_VALUE_INDEX; tmp |= AUD_CONFIG_N_PROG_ENABLE; tmp &= ~AUD_CONFIG_UPPER_N_MASK; tmp &= ~AUD_CONFIG_LOWER_N_MASK; if (intel_crtc_has_dp_encoder(old_crtc_state)) tmp |= AUD_CONFIG_N_VALUE_INDEX; - intel_de_write(i915, aud_config, tmp); + intel_de_write(i915, regs.aud_config, tmp); eldv = IBX_ELD_VALID(port); /* Invalidate ELD */ - tmp = intel_de_read(i915, aud_cntrl_st2); + tmp = intel_de_read(i915, regs.aud_cntrl_st2); tmp &= ~eldv; - intel_de_write(i915, aud_cntrl_st2, tmp); + intel_de_write(i915, regs.aud_cntrl_st2, tmp); } static void ilk_audio_codec_enable(struct intel_encoder *encoder, @@ -718,9 +735,9 @@ static void ilk_audio_codec_enable(struct intel_encoder *encoder, enum pipe pipe = crtc->pipe; enum port port = encoder->port; const u8 *eld = connector->eld; + struct ilk_audio_regs regs; u32 tmp, eldv; int len, i; - i915_reg_t hdmiw_hdmiedid, aud_config, aud_cntl_st, aud_cntrl_st2; if (drm_WARN_ON(&i915->drm, port == PORT_A)) return; @@ -732,49 +749,33 @@ static void ilk_audio_codec_enable(struct intel_encoder *encoder, * infrastructure is not there yet. */ - if (HAS_PCH_IBX(i915)) { - hdmiw_hdmiedid = IBX_HDMIW_HDMIEDID(pipe); - aud_config = IBX_AUD_CFG(pipe); - aud_cntl_st = IBX_AUD_CNTL_ST(pipe); - aud_cntrl_st2 = IBX_AUD_CNTL_ST2; - } else if (IS_VALLEYVIEW(i915) || - IS_CHERRYVIEW(i915)) { - hdmiw_hdmiedid = VLV_HDMIW_HDMIEDID(pipe); - aud_config = VLV_AUD_CFG(pipe); - aud_cntl_st = VLV_AUD_CNTL_ST(pipe); - aud_cntrl_st2 = VLV_AUD_CNTL_ST2; - } else { - hdmiw_hdmiedid = CPT_HDMIW_HDMIEDID(pipe); - aud_config = CPT_AUD_CFG(pipe); - aud_cntl_st = CPT_AUD_CNTL_ST(pipe); - aud_cntrl_st2 = CPT_AUD_CNTRL_ST2; - } + ilk_audio_regs_init(i915, pipe, ®s); eldv = IBX_ELD_VALID(port); /* Invalidate ELD */ - tmp = intel_de_read(i915, aud_cntrl_st2); + tmp = intel_de_read(i915, regs.aud_cntrl_st2); tmp &= ~eldv; - intel_de_write(i915, aud_cntrl_st2, tmp); + intel_de_write(i915, regs.aud_cntrl_st2, tmp); /* Reset ELD write address */ - tmp = intel_de_read(i915, aud_cntl_st); + tmp = intel_de_read(i915, regs.aud_cntl_st); tmp &= ~IBX_ELD_ADDRESS_MASK; - intel_de_write(i915, aud_cntl_st, tmp); + intel_de_write(i915, regs.aud_cntl_st, tmp); /* Up to 84 bytes of hw ELD buffer */ len = min(drm_eld_size(eld), 84); for (i = 0; i < len / 4; i++) - intel_de_write(i915, hdmiw_hdmiedid, + intel_de_write(i915, regs.hdmiw_hdmiedid, *((const u32 *)eld + i)); /* ELD valid */ - tmp = intel_de_read(i915, aud_cntrl_st2); + tmp = intel_de_read(i915, regs.aud_cntrl_st2); tmp |= eldv; - intel_de_write(i915, aud_cntrl_st2, tmp); + intel_de_write(i915, regs.aud_cntrl_st2, tmp); /* Enable timestamps */ - tmp = intel_de_read(i915, aud_config); + tmp = intel_de_read(i915, regs.aud_config); tmp &= ~AUD_CONFIG_N_VALUE_INDEX; tmp &= ~AUD_CONFIG_N_PROG_ENABLE; tmp &= ~AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK; @@ -782,7 +783,7 @@ static void ilk_audio_codec_enable(struct intel_encoder *encoder, tmp |= AUD_CONFIG_N_VALUE_INDEX; else tmp |= audio_config_hdmi_pixel_clock(crtc_state); - intel_de_write(i915, aud_config, tmp); + intel_de_write(i915, regs.aud_config, tmp); } /** -- cgit From 011aa42ef6ae7809249eaacca78081d357ffc95a Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 26 Oct 2022 20:01:40 +0300 Subject: drm/i915/audio: Use REG_BIT() & co. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switch the audio registers to REG_BIT() & co. Cc: Chaitanya Kumar Borah Cc: Kai Vehmanen Cc: Takashi Iwai Reviewed-by: Jani Nikula Reviewed-by: Kai Vehmanen Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221026170150.2654-6-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_audio.c | 15 ++--- drivers/gpu/drm/i915/display/intel_audio_regs.h | 81 ++++++++++++------------- 2 files changed, 45 insertions(+), 51 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c index e35fabf8d86e..29f2820c94c3 100644 --- a/drivers/gpu/drm/i915/display/intel_audio.c +++ b/drivers/gpu/drm/i915/display/intel_audio.c @@ -362,7 +362,7 @@ static void g4x_audio_codec_enable(struct intel_encoder *encoder, tmp = intel_de_read(i915, G4X_AUD_CNTL_ST); tmp &= ~(G4X_ELDV | G4X_ELD_ADDR_MASK); - len = (tmp >> 9) & 0x1f; /* ELD buffer size */ + len = REG_FIELD_GET(G4X_ELD_BUFFER_SIZE_MASK, tmp); intel_de_write(i915, G4X_AUD_CNTL_ST, tmp); len = min(drm_eld_size(eld) / 4, len); @@ -700,7 +700,7 @@ static void ilk_audio_codec_disable(struct intel_encoder *encoder, enum pipe pipe = crtc->pipe; enum port port = encoder->port; struct ilk_audio_regs regs; - u32 tmp, eldv; + u32 tmp; if (drm_WARN_ON(&i915->drm, port == PORT_A)) return; @@ -717,11 +717,9 @@ static void ilk_audio_codec_disable(struct intel_encoder *encoder, tmp |= AUD_CONFIG_N_VALUE_INDEX; intel_de_write(i915, regs.aud_config, tmp); - eldv = IBX_ELD_VALID(port); - /* Invalidate ELD */ tmp = intel_de_read(i915, regs.aud_cntrl_st2); - tmp &= ~eldv; + tmp &= ~IBX_ELD_VALID(port); intel_de_write(i915, regs.aud_cntrl_st2, tmp); } @@ -736,8 +734,8 @@ static void ilk_audio_codec_enable(struct intel_encoder *encoder, enum port port = encoder->port; const u8 *eld = connector->eld; struct ilk_audio_regs regs; - u32 tmp, eldv; int len, i; + u32 tmp; if (drm_WARN_ON(&i915->drm, port == PORT_A)) return; @@ -751,11 +749,10 @@ static void ilk_audio_codec_enable(struct intel_encoder *encoder, ilk_audio_regs_init(i915, pipe, ®s); - eldv = IBX_ELD_VALID(port); /* Invalidate ELD */ tmp = intel_de_read(i915, regs.aud_cntrl_st2); - tmp &= ~eldv; + tmp &= ~IBX_ELD_VALID(port); intel_de_write(i915, regs.aud_cntrl_st2, tmp); /* Reset ELD write address */ @@ -771,7 +768,7 @@ static void ilk_audio_codec_enable(struct intel_encoder *encoder, /* ELD valid */ tmp = intel_de_read(i915, regs.aud_cntrl_st2); - tmp |= eldv; + tmp |= IBX_ELD_VALID(port); intel_de_write(i915, regs.aud_cntrl_st2, tmp); /* Enable timestamps */ diff --git a/drivers/gpu/drm/i915/display/intel_audio_regs.h b/drivers/gpu/drm/i915/display/intel_audio_regs.h index ebbdd0654919..b5684ed839be 100644 --- a/drivers/gpu/drm/i915/display/intel_audio_regs.h +++ b/drivers/gpu/drm/i915/display/intel_audio_regs.h @@ -9,9 +9,10 @@ #include "i915_reg_defs.h" #define G4X_AUD_CNTL_ST _MMIO(0x620B4) -#define G4X_ELDV (1 << 14) -#define G4X_ELD_ADDR_MASK (0xf << 5) -#define G4X_ELD_ACK (1 << 4) +#define G4X_ELDV REG_BIT(14) +#define G4X_ELD_BUFFER_SIZE_MASK REG_GENMASK(13, 9) +#define G4X_ELD_ADDR_MASK REG_GENMASK(8, 5) +#define G4X_ELD_ACK REG_BIT(4) #define G4X_HDMIW_HDMIEDID _MMIO(0x6210C) #define _IBX_HDMIW_HDMIEDID_A 0xE2050 @@ -22,12 +23,12 @@ #define _IBX_AUD_CNTL_ST_B 0xE21B4 #define IBX_AUD_CNTL_ST(pipe) _MMIO_PIPE(pipe, _IBX_AUD_CNTL_ST_A, \ _IBX_AUD_CNTL_ST_B) -#define IBX_ELD_BUFFER_SIZE_MASK (0x1f << 10) -#define IBX_ELD_ADDRESS_MASK (0x1f << 5) -#define IBX_ELD_ACK (1 << 4) +#define IBX_ELD_BUFFER_SIZE_MASK REG_GENMASK(14, 10) +#define IBX_ELD_ADDRESS_MASK REG_GENMASK(9, 5) +#define IBX_ELD_ACK REG_BIT(4) #define IBX_AUD_CNTL_ST2 _MMIO(0xE20C0) -#define IBX_CP_READY(port) ((1 << 1) << (((port) - 1) * 4)) -#define IBX_ELD_VALID(port) ((1 << 0) << (((port) - 1) * 4)) +#define IBX_CP_READY(port) REG_BIT(((port) - 1) * 4 + 1) +#define IBX_ELD_VALID(port) REG_BIT(((port) - 1) * 4 + 0) #define _CPT_HDMIW_HDMIEDID_A 0xE5050 #define _CPT_HDMIW_HDMIEDID_B 0xE5150 @@ -54,34 +55,30 @@ #define _VLV_AUD_CONFIG_A (VLV_DISPLAY_BASE + 0x62000) #define _VLV_AUD_CONFIG_B (VLV_DISPLAY_BASE + 0x62100) #define VLV_AUD_CFG(pipe) _MMIO_PIPE(pipe, _VLV_AUD_CONFIG_A, _VLV_AUD_CONFIG_B) - -#define AUD_CONFIG_N_VALUE_INDEX (1 << 29) -#define AUD_CONFIG_N_PROG_ENABLE (1 << 28) -#define AUD_CONFIG_UPPER_N_SHIFT 20 -#define AUD_CONFIG_UPPER_N_MASK (0xff << 20) -#define AUD_CONFIG_LOWER_N_SHIFT 4 -#define AUD_CONFIG_LOWER_N_MASK (0xfff << 4) -#define AUD_CONFIG_N_MASK (AUD_CONFIG_UPPER_N_MASK | AUD_CONFIG_LOWER_N_MASK) -#define AUD_CONFIG_N(n) \ - (((((n) >> 12) & 0xff) << AUD_CONFIG_UPPER_N_SHIFT) | \ - (((n) & 0xfff) << AUD_CONFIG_LOWER_N_SHIFT)) -#define AUD_CONFIG_PIXEL_CLOCK_HDMI_SHIFT 16 -#define AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK (0xf << 16) -#define AUD_CONFIG_PIXEL_CLOCK_HDMI_25175 (0 << 16) -#define AUD_CONFIG_PIXEL_CLOCK_HDMI_25200 (1 << 16) -#define AUD_CONFIG_PIXEL_CLOCK_HDMI_27000 (2 << 16) -#define AUD_CONFIG_PIXEL_CLOCK_HDMI_27027 (3 << 16) -#define AUD_CONFIG_PIXEL_CLOCK_HDMI_54000 (4 << 16) -#define AUD_CONFIG_PIXEL_CLOCK_HDMI_54054 (5 << 16) -#define AUD_CONFIG_PIXEL_CLOCK_HDMI_74176 (6 << 16) -#define AUD_CONFIG_PIXEL_CLOCK_HDMI_74250 (7 << 16) -#define AUD_CONFIG_PIXEL_CLOCK_HDMI_148352 (8 << 16) -#define AUD_CONFIG_PIXEL_CLOCK_HDMI_148500 (9 << 16) -#define AUD_CONFIG_PIXEL_CLOCK_HDMI_296703 (10 << 16) -#define AUD_CONFIG_PIXEL_CLOCK_HDMI_297000 (11 << 16) -#define AUD_CONFIG_PIXEL_CLOCK_HDMI_593407 (12 << 16) -#define AUD_CONFIG_PIXEL_CLOCK_HDMI_594000 (13 << 16) -#define AUD_CONFIG_DISABLE_NCTS (1 << 3) +#define AUD_CONFIG_N_VALUE_INDEX REG_BIT(29) +#define AUD_CONFIG_N_PROG_ENABLE REG_BIT(28) +#define AUD_CONFIG_UPPER_N_MASK REG_GENMASK(27, 20) +#define AUD_CONFIG_LOWER_N_MASK REG_GENMASK(15, 4) +#define AUD_CONFIG_N_MASK (AUD_CONFIG_UPPER_N_MASK | \ + AUD_CONFIG_LOWER_N_MASK) +#define AUD_CONFIG_N(n) (REG_FIELD_PREP(AUD_CONFIG_UPPER_N_MASK, (n) >> 12) | \ + REG_FIELD_PREP(AUD_CONFIG_LOWER_N_MASK, (n) & 0xfff)) +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK REG_GENMASK(19, 16) +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_25175 REG_FIELD_PREP(AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK, 0) +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_25200 REG_FIELD_PREP(AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK, 1) +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_27000 REG_FIELD_PREP(AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK, 2) +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_27027 REG_FIELD_PREP(AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK, 3) +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_54000 REG_FIELD_PREP(AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK, 4) +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_54054 REG_FIELD_PREP(AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK, 5) +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_74176 REG_FIELD_PREP(AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK, 6) +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_74250 REG_FIELD_PREP(AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK, 7) +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_148352 REG_FIELD_PREP(AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK, 8) +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_148500 REG_FIELD_PREP(AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK, 9) +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_296703 REG_FIELD_PREP(AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK, 10) +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_297000 REG_FIELD_PREP(AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK, 11) +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_593407 REG_FIELD_PREP(AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK, 12) +#define AUD_CONFIG_PIXEL_CLOCK_HDMI_594000 REG_FIELD_PREP(AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK, 13) +#define AUD_CONFIG_DISABLE_NCTS REG_BIT(3) #define _HSW_AUD_CONFIG_A 0x65000 #define _HSW_AUD_CONFIG_B 0x65100 @@ -94,9 +91,9 @@ #define _HSW_AUD_M_CTS_ENABLE_A 0x65028 #define _HSW_AUD_M_CTS_ENABLE_B 0x65128 #define HSW_AUD_M_CTS_ENABLE(trans) _MMIO_TRANS(trans, _HSW_AUD_M_CTS_ENABLE_A, _HSW_AUD_M_CTS_ENABLE_B) -#define AUD_M_CTS_M_VALUE_INDEX (1 << 21) -#define AUD_M_CTS_M_PROG_ENABLE (1 << 20) -#define AUD_CONFIG_M_MASK 0xfffff +#define AUD_M_CTS_M_VALUE_INDEX REG_BIT(21) +#define AUD_M_CTS_M_PROG_ENABLE REG_BIT(20) +#define AUD_CONFIG_M_MASK REG_GENMASK(19, 0) #define _HSW_AUD_DIP_ELD_CTRL_ST_A 0x650b4 #define _HSW_AUD_DIP_ELD_CTRL_ST_B 0x651b4 @@ -124,11 +121,11 @@ #define AUD_DP_2DOT0_CTRL(trans) _MMIO_TRANS(trans, _AUD_TCA_DP_2DOT0_CTRL, _AUD_TCB_DP_2DOT0_CTRL) #define AUD_ENABLE_SDP_SPLIT REG_BIT(31) -#define HSW_AUD_CHICKENBIT _MMIO(0x65f10) -#define SKL_AUD_CODEC_WAKE_SIGNAL (1 << 15) +#define HSW_AUD_CHICKENBIT _MMIO(0x65f10) +#define SKL_AUD_CODEC_WAKE_SIGNAL REG_BIT(15) #define AUD_FREQ_CNTRL _MMIO(0x65900) -#define AUD_PIN_BUF_CTL _MMIO(0x48414) +#define AUD_PIN_BUF_CTL _MMIO(0x48414) #define AUD_PIN_BUF_ENABLE REG_BIT(31) #define AUD_TS_CDCLK_M _MMIO(0x65ea0) -- cgit From 985a74d8ecc675e7e0535de1ad5812076d040569 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 26 Oct 2022 20:01:41 +0300 Subject: drm/i915/audio: Unify register bit naming MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename a few g4x bits to match the ibx+ bits. Cc: Chaitanya Kumar Borah Cc: Kai Vehmanen Cc: Takashi Iwai Reviewed-by: Jani Nikula Reviewed-by: Kai Vehmanen Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221026170150.2654-7-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_audio.c | 10 +++++----- drivers/gpu/drm/i915/display/intel_audio_regs.h | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c index 29f2820c94c3..5d545d2ffb33 100644 --- a/drivers/gpu/drm/i915/display/intel_audio.c +++ b/drivers/gpu/drm/i915/display/intel_audio.c @@ -340,7 +340,7 @@ static void g4x_audio_codec_disable(struct intel_encoder *encoder, /* Invalidate ELD */ tmp = intel_de_read(i915, G4X_AUD_CNTL_ST); - tmp &= ~G4X_ELDV; + tmp &= ~G4X_ELD_VALID; intel_de_write(i915, G4X_AUD_CNTL_ST, tmp); } @@ -355,13 +355,13 @@ static void g4x_audio_codec_enable(struct intel_encoder *encoder, int len, i; if (intel_eld_uptodate(connector, - G4X_AUD_CNTL_ST, G4X_ELDV, - G4X_AUD_CNTL_ST, G4X_ELD_ADDR_MASK, + G4X_AUD_CNTL_ST, G4X_ELD_VALID, + G4X_AUD_CNTL_ST, G4X_ELD_ADDRESS_MASK, G4X_HDMIW_HDMIEDID)) return; tmp = intel_de_read(i915, G4X_AUD_CNTL_ST); - tmp &= ~(G4X_ELDV | G4X_ELD_ADDR_MASK); + tmp &= ~(G4X_ELD_VALID | G4X_ELD_ADDRESS_MASK); len = REG_FIELD_GET(G4X_ELD_BUFFER_SIZE_MASK, tmp); intel_de_write(i915, G4X_AUD_CNTL_ST, tmp); @@ -371,7 +371,7 @@ static void g4x_audio_codec_enable(struct intel_encoder *encoder, *((const u32 *)eld + i)); tmp = intel_de_read(i915, G4X_AUD_CNTL_ST); - tmp |= G4X_ELDV; + tmp |= G4X_ELD_VALID; intel_de_write(i915, G4X_AUD_CNTL_ST, tmp); } diff --git a/drivers/gpu/drm/i915/display/intel_audio_regs.h b/drivers/gpu/drm/i915/display/intel_audio_regs.h index b5684ed839be..4f432c2eb543 100644 --- a/drivers/gpu/drm/i915/display/intel_audio_regs.h +++ b/drivers/gpu/drm/i915/display/intel_audio_regs.h @@ -9,9 +9,9 @@ #include "i915_reg_defs.h" #define G4X_AUD_CNTL_ST _MMIO(0x620B4) -#define G4X_ELDV REG_BIT(14) +#define G4X_ELD_VALID REG_BIT(14) #define G4X_ELD_BUFFER_SIZE_MASK REG_GENMASK(13, 9) -#define G4X_ELD_ADDR_MASK REG_GENMASK(8, 5) +#define G4X_ELD_ADDRESS_MASK REG_GENMASK(8, 5) #define G4X_ELD_ACK REG_BIT(4) #define G4X_HDMIW_HDMIEDID _MMIO(0x6210C) -- cgit From 9f4a51256f439265f28d729a8866692337d58505 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 26 Oct 2022 20:01:42 +0300 Subject: drm/i915/audio: Protect singleton register with a lock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On the "ilk" platforms AUD_CNTL_ST2 is a singleton. Protect it with the audio mutex in case we ever want to do parallel RMW access to it. Currently that should not happen since we only do audio enable/disable from full modesets, and those are fully serialized. But we probably want to think about toggling audio on/off from fastsets too. The hsw codepaths already have the same locking. g4x should not need it since it can only do audio to a single port at a time, which means it's actually broken in more ways than this atm. Cc: Chaitanya Kumar Borah Cc: Kai Vehmanen Cc: Takashi Iwai Reviewed-by: Jani Nikula Reviewed-by: Kai Vehmanen Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221026170150.2654-8-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_audio.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c index 5d545d2ffb33..093283fd1c28 100644 --- a/drivers/gpu/drm/i915/display/intel_audio.c +++ b/drivers/gpu/drm/i915/display/intel_audio.c @@ -707,6 +707,8 @@ static void ilk_audio_codec_disable(struct intel_encoder *encoder, ilk_audio_regs_init(i915, pipe, ®s); + mutex_lock(&i915->display.audio.mutex); + /* Disable timestamps */ tmp = intel_de_read(i915, regs.aud_config); tmp &= ~AUD_CONFIG_N_VALUE_INDEX; @@ -721,6 +723,8 @@ static void ilk_audio_codec_disable(struct intel_encoder *encoder, tmp = intel_de_read(i915, regs.aud_cntrl_st2); tmp &= ~IBX_ELD_VALID(port); intel_de_write(i915, regs.aud_cntrl_st2, tmp); + + mutex_unlock(&i915->display.audio.mutex); } static void ilk_audio_codec_enable(struct intel_encoder *encoder, @@ -749,6 +753,7 @@ static void ilk_audio_codec_enable(struct intel_encoder *encoder, ilk_audio_regs_init(i915, pipe, ®s); + mutex_lock(&i915->display.audio.mutex); /* Invalidate ELD */ tmp = intel_de_read(i915, regs.aud_cntrl_st2); @@ -781,6 +786,8 @@ static void ilk_audio_codec_enable(struct intel_encoder *encoder, else tmp |= audio_config_hdmi_pixel_clock(crtc_state); intel_de_write(i915, regs.aud_config, tmp); + + mutex_unlock(&i915->display.audio.mutex); } /** -- cgit From 6e22c35ddaa19dcaa57bf9bfb4ca747ee7ce98a6 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 26 Oct 2022 20:01:43 +0300 Subject: drm/i915/audio: Nuke intel_eld_uptodate() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No idea why we do this ELD comparions on g4x before loading the new ELD. Seems entirely pointless so just get rid of it. Cc: Chaitanya Kumar Borah Cc: Kai Vehmanen Cc: Takashi Iwai Reviewed-by: Jani Nikula Reviewed-by: Kai Vehmanen Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221026170150.2654-9-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_audio.c | 33 ------------------------------ 1 file changed, 33 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c index 093283fd1c28..7867eb670560 100644 --- a/drivers/gpu/drm/i915/display/intel_audio.c +++ b/drivers/gpu/drm/i915/display/intel_audio.c @@ -304,33 +304,6 @@ static int audio_config_hdmi_get_n(const struct intel_crtc_state *crtc_state, return 0; } -static bool intel_eld_uptodate(struct drm_connector *connector, - i915_reg_t reg_eldv, u32 bits_eldv, - i915_reg_t reg_elda, u32 bits_elda, - i915_reg_t reg_edid) -{ - struct drm_i915_private *i915 = to_i915(connector->dev); - const u8 *eld = connector->eld; - u32 tmp; - int i; - - tmp = intel_de_read(i915, reg_eldv); - tmp &= bits_eldv; - - if (!tmp) - return false; - - tmp = intel_de_read(i915, reg_elda); - tmp &= ~bits_elda; - intel_de_write(i915, reg_elda, tmp); - - for (i = 0; i < drm_eld_size(eld) / 4; i++) - if (intel_de_read(i915, reg_edid) != *((const u32 *)eld + i)) - return false; - - return true; -} - static void g4x_audio_codec_disable(struct intel_encoder *encoder, const struct intel_crtc_state *old_crtc_state, const struct drm_connector_state *old_conn_state) @@ -354,12 +327,6 @@ static void g4x_audio_codec_enable(struct intel_encoder *encoder, u32 tmp; int len, i; - if (intel_eld_uptodate(connector, - G4X_AUD_CNTL_ST, G4X_ELD_VALID, - G4X_AUD_CNTL_ST, G4X_ELD_ADDRESS_MASK, - G4X_HDMIW_HDMIEDID)) - return; - tmp = intel_de_read(i915, G4X_AUD_CNTL_ST); tmp &= ~(G4X_ELD_VALID | G4X_ELD_ADDRESS_MASK); len = REG_FIELD_GET(G4X_ELD_BUFFER_SIZE_MASK, tmp); -- cgit From 1c0ab71acc83091f55f9c9091f9959d5be565dff Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 26 Oct 2022 20:01:44 +0300 Subject: drm/i915/audio: Read ELD buffer size from hardware MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We currently read the ELD buffer size from hardware on g4x, but on ilk+ we just hardcode it to 84 bytes. Let's unify this and just do the hardware readout on all platforms, in case the size changes in the future or something. TODO: should perhaps do the readout during driver init and stash the results somewhere so that we could check that the connector's ELD actually fits and not even try to enable audio in that case... v2: Document the size is in dwords (Jani) Cc: Chaitanya Kumar Borah Cc: Kai Vehmanen Cc: Takashi Iwai Reviewed-by: Jani Nikula Reviewed-by: Kai Vehmanen Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221026170150.2654-10-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_audio.c | 52 ++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c index 7867eb670560..60b44bcaa0e4 100644 --- a/drivers/gpu/drm/i915/display/intel_audio.c +++ b/drivers/gpu/drm/i915/display/intel_audio.c @@ -304,6 +304,16 @@ static int audio_config_hdmi_get_n(const struct intel_crtc_state *crtc_state, return 0; } +/* ELD buffer size in dwords */ +static int g4x_eld_buffer_size(struct drm_i915_private *i915) +{ + u32 tmp; + + tmp = intel_de_read(i915, G4X_AUD_CNTL_ST); + + return REG_FIELD_GET(G4X_ELD_BUFFER_SIZE_MASK, tmp); +} + static void g4x_audio_codec_disable(struct intel_encoder *encoder, const struct intel_crtc_state *old_crtc_state, const struct drm_connector_state *old_conn_state) @@ -329,10 +339,11 @@ static void g4x_audio_codec_enable(struct intel_encoder *encoder, tmp = intel_de_read(i915, G4X_AUD_CNTL_ST); tmp &= ~(G4X_ELD_VALID | G4X_ELD_ADDRESS_MASK); - len = REG_FIELD_GET(G4X_ELD_BUFFER_SIZE_MASK, tmp); intel_de_write(i915, G4X_AUD_CNTL_ST, tmp); + len = g4x_eld_buffer_size(i915); len = min(drm_eld_size(eld) / 4, len); + for (i = 0; i < len; i++) intel_de_write(i915, G4X_HDMIW_HDMIEDID, *((const u32 *)eld + i)); @@ -442,6 +453,17 @@ hsw_audio_config_update(struct intel_encoder *encoder, hsw_hdmi_audio_config_update(encoder, crtc_state); } +/* ELD buffer size in dwords */ +static int hsw_eld_buffer_size(struct drm_i915_private *i915, + enum transcoder cpu_transcoder) +{ + u32 tmp; + + tmp = intel_de_read(i915, HSW_AUD_DIP_ELD_CTRL(cpu_transcoder)); + + return REG_FIELD_GET(IBX_ELD_BUFFER_SIZE_MASK, tmp); +} + static void hsw_audio_codec_disable(struct intel_encoder *encoder, const struct intel_crtc_state *old_crtc_state, const struct drm_connector_state *old_conn_state) @@ -615,9 +637,10 @@ static void hsw_audio_codec_enable(struct intel_encoder *encoder, tmp &= ~IBX_ELD_ADDRESS_MASK; intel_de_write(i915, HSW_AUD_DIP_ELD_CTRL(cpu_transcoder), tmp); - /* Up to 84 bytes of hw ELD buffer */ - len = min(drm_eld_size(eld), 84); - for (i = 0; i < len / 4; i++) + len = hsw_eld_buffer_size(i915, cpu_transcoder); + len = min(drm_eld_size(eld) / 4, len); + + for (i = 0; i < len; i++) intel_de_write(i915, HSW_AUD_EDID_DATA(cpu_transcoder), *((const u32 *)eld + i)); @@ -658,6 +681,20 @@ static void ilk_audio_regs_init(struct drm_i915_private *i915, } } +/* ELD buffer size in dwords */ +static int ilk_eld_buffer_size(struct drm_i915_private *i915, + enum pipe pipe) +{ + struct ilk_audio_regs regs; + u32 tmp; + + ilk_audio_regs_init(i915, pipe, ®s); + + tmp = intel_de_read(i915, regs.aud_cntl_st); + + return REG_FIELD_GET(IBX_ELD_BUFFER_SIZE_MASK, tmp); +} + static void ilk_audio_codec_disable(struct intel_encoder *encoder, const struct intel_crtc_state *old_crtc_state, const struct drm_connector_state *old_conn_state) @@ -732,9 +769,10 @@ static void ilk_audio_codec_enable(struct intel_encoder *encoder, tmp &= ~IBX_ELD_ADDRESS_MASK; intel_de_write(i915, regs.aud_cntl_st, tmp); - /* Up to 84 bytes of hw ELD buffer */ - len = min(drm_eld_size(eld), 84); - for (i = 0; i < len / 4; i++) + len = ilk_eld_buffer_size(i915, pipe); + len = min(drm_eld_size(eld) / 4, len); + + for (i = 0; i < len; i++) intel_de_write(i915, regs.hdmiw_hdmiedid, *((const u32 *)eld + i)); -- cgit From 0234cda2ceb9b90da55e3bc43dfda451b152acb1 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 26 Oct 2022 20:01:45 +0300 Subject: drm/i915/audio: Make sure we write the whole ELD buffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we only write as many dwords into the hardware ELD buffers as drm_eld_size() tells us. That could mean the remainder of the hardware buffer is left with whatever stale garbage it had before, which doesn't seem entirely great. Let's zero out the remainder of the buffer in case the provided ELD doesn't fill it fully. We can also sanity check out idea of the hardware ELD buffer's size by making sure the address wrapped back to zero once we wrote the entire buffer. Cc: Chaitanya Kumar Borah Cc: Kai Vehmanen Cc: Takashi Iwai Reviewed-by: Jani Nikula Reviewed-by: Kai Vehmanen Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221026170150.2654-11-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_audio.c | 34 ++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c index 60b44bcaa0e4..56f0d8af313e 100644 --- a/drivers/gpu/drm/i915/display/intel_audio.c +++ b/drivers/gpu/drm/i915/display/intel_audio.c @@ -334,19 +334,24 @@ static void g4x_audio_codec_enable(struct intel_encoder *encoder, struct drm_i915_private *i915 = to_i915(encoder->base.dev); struct drm_connector *connector = conn_state->connector; const u8 *eld = connector->eld; + int eld_buffer_size, len, i; u32 tmp; - int len, i; tmp = intel_de_read(i915, G4X_AUD_CNTL_ST); tmp &= ~(G4X_ELD_VALID | G4X_ELD_ADDRESS_MASK); intel_de_write(i915, G4X_AUD_CNTL_ST, tmp); - len = g4x_eld_buffer_size(i915); - len = min(drm_eld_size(eld) / 4, len); + eld_buffer_size = g4x_eld_buffer_size(i915); + len = min(drm_eld_size(eld) / 4, eld_buffer_size); for (i = 0; i < len; i++) intel_de_write(i915, G4X_HDMIW_HDMIEDID, *((const u32 *)eld + i)); + for (; i < eld_buffer_size; i++) + intel_de_write(i915, G4X_HDMIW_HDMIEDID, 0); + + drm_WARN_ON(&i915->drm, + (intel_de_read(i915, G4X_AUD_CNTL_ST) & G4X_ELD_ADDRESS_MASK) != 0); tmp = intel_de_read(i915, G4X_AUD_CNTL_ST); tmp |= G4X_ELD_VALID; @@ -610,8 +615,8 @@ static void hsw_audio_codec_enable(struct intel_encoder *encoder, struct drm_connector *connector = conn_state->connector; enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; const u8 *eld = connector->eld; + int eld_buffer_size, len, i; u32 tmp; - int len, i; mutex_lock(&i915->display.audio.mutex); @@ -637,12 +642,18 @@ static void hsw_audio_codec_enable(struct intel_encoder *encoder, tmp &= ~IBX_ELD_ADDRESS_MASK; intel_de_write(i915, HSW_AUD_DIP_ELD_CTRL(cpu_transcoder), tmp); - len = hsw_eld_buffer_size(i915, cpu_transcoder); - len = min(drm_eld_size(eld) / 4, len); + eld_buffer_size = hsw_eld_buffer_size(i915, cpu_transcoder); + len = min(drm_eld_size(eld) / 4, eld_buffer_size); for (i = 0; i < len; i++) intel_de_write(i915, HSW_AUD_EDID_DATA(cpu_transcoder), *((const u32 *)eld + i)); + for (; i < eld_buffer_size; i++) + intel_de_write(i915, HSW_AUD_EDID_DATA(cpu_transcoder), 0); + + drm_WARN_ON(&i915->drm, + (intel_de_read(i915, HSW_AUD_DIP_ELD_CTRL(cpu_transcoder)) & + IBX_ELD_ADDRESS_MASK) != 0); /* ELD valid */ tmp = intel_de_read(i915, HSW_AUD_PIN_ELD_CP_VLD); @@ -741,8 +752,8 @@ static void ilk_audio_codec_enable(struct intel_encoder *encoder, enum pipe pipe = crtc->pipe; enum port port = encoder->port; const u8 *eld = connector->eld; + int eld_buffer_size, len, i; struct ilk_audio_regs regs; - int len, i; u32 tmp; if (drm_WARN_ON(&i915->drm, port == PORT_A)) @@ -769,12 +780,17 @@ static void ilk_audio_codec_enable(struct intel_encoder *encoder, tmp &= ~IBX_ELD_ADDRESS_MASK; intel_de_write(i915, regs.aud_cntl_st, tmp); - len = ilk_eld_buffer_size(i915, pipe); - len = min(drm_eld_size(eld) / 4, len); + eld_buffer_size = ilk_eld_buffer_size(i915, pipe); + len = min(drm_eld_size(eld) / 4, eld_buffer_size); for (i = 0; i < len; i++) intel_de_write(i915, regs.hdmiw_hdmiedid, *((const u32 *)eld + i)); + for (; i < eld_buffer_size; i++) + intel_de_write(i915, regs.hdmiw_hdmiedid, 0); + + drm_WARN_ON(&i915->drm, + (intel_de_read(i915, regs.aud_cntl_st) & IBX_ELD_ADDRESS_MASK) != 0); /* ELD valid */ tmp = intel_de_read(i915, regs.aud_cntrl_st2); -- cgit From 50a4a926e65021b9f1b15e48d9439b3726ba3546 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 26 Oct 2022 20:01:46 +0300 Subject: drm/i915/audio: Use u32* for ELD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the eld pointer u32* so we don't have to do super ugly casting in the code itself. Cc: Chaitanya Kumar Borah Cc: Kai Vehmanen Cc: Takashi Iwai Reviewed-by: Jani Nikula Reviewed-by: Kai Vehmanen Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221026170150.2654-12-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_audio.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c index 56f0d8af313e..f4c319a3003b 100644 --- a/drivers/gpu/drm/i915/display/intel_audio.c +++ b/drivers/gpu/drm/i915/display/intel_audio.c @@ -333,7 +333,7 @@ static void g4x_audio_codec_enable(struct intel_encoder *encoder, { struct drm_i915_private *i915 = to_i915(encoder->base.dev); struct drm_connector *connector = conn_state->connector; - const u8 *eld = connector->eld; + const u32 *eld = (const u32 *)connector->eld; int eld_buffer_size, len, i; u32 tmp; @@ -342,11 +342,10 @@ static void g4x_audio_codec_enable(struct intel_encoder *encoder, intel_de_write(i915, G4X_AUD_CNTL_ST, tmp); eld_buffer_size = g4x_eld_buffer_size(i915); - len = min(drm_eld_size(eld) / 4, eld_buffer_size); + len = min(drm_eld_size(connector->eld) / 4, eld_buffer_size); for (i = 0; i < len; i++) - intel_de_write(i915, G4X_HDMIW_HDMIEDID, - *((const u32 *)eld + i)); + intel_de_write(i915, G4X_HDMIW_HDMIEDID, eld[i]); for (; i < eld_buffer_size; i++) intel_de_write(i915, G4X_HDMIW_HDMIEDID, 0); @@ -614,7 +613,7 @@ static void hsw_audio_codec_enable(struct intel_encoder *encoder, struct drm_i915_private *i915 = to_i915(encoder->base.dev); struct drm_connector *connector = conn_state->connector; enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; - const u8 *eld = connector->eld; + const u32 *eld = (const u32 *)connector->eld; int eld_buffer_size, len, i; u32 tmp; @@ -643,11 +642,10 @@ static void hsw_audio_codec_enable(struct intel_encoder *encoder, intel_de_write(i915, HSW_AUD_DIP_ELD_CTRL(cpu_transcoder), tmp); eld_buffer_size = hsw_eld_buffer_size(i915, cpu_transcoder); - len = min(drm_eld_size(eld) / 4, eld_buffer_size); + len = min(drm_eld_size(connector->eld) / 4, eld_buffer_size); for (i = 0; i < len; i++) - intel_de_write(i915, HSW_AUD_EDID_DATA(cpu_transcoder), - *((const u32 *)eld + i)); + intel_de_write(i915, HSW_AUD_EDID_DATA(cpu_transcoder), eld[i]); for (; i < eld_buffer_size; i++) intel_de_write(i915, HSW_AUD_EDID_DATA(cpu_transcoder), 0); @@ -749,9 +747,9 @@ static void ilk_audio_codec_enable(struct intel_encoder *encoder, struct drm_i915_private *i915 = to_i915(encoder->base.dev); struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_connector *connector = conn_state->connector; + const u32 *eld = (const u32 *)connector->eld; enum pipe pipe = crtc->pipe; enum port port = encoder->port; - const u8 *eld = connector->eld; int eld_buffer_size, len, i; struct ilk_audio_regs regs; u32 tmp; @@ -781,11 +779,10 @@ static void ilk_audio_codec_enable(struct intel_encoder *encoder, intel_de_write(i915, regs.aud_cntl_st, tmp); eld_buffer_size = ilk_eld_buffer_size(i915, pipe); - len = min(drm_eld_size(eld) / 4, eld_buffer_size); + len = min(drm_eld_size(connector->eld) / 4, eld_buffer_size); for (i = 0; i < len; i++) - intel_de_write(i915, regs.hdmiw_hdmiedid, - *((const u32 *)eld + i)); + intel_de_write(i915, regs.hdmiw_hdmiedid, eld[i]); for (; i < eld_buffer_size; i++) intel_de_write(i915, regs.hdmiw_hdmiedid, 0); -- cgit From 7c8d74e8131217e928fb92904cac5362e348744f Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 26 Oct 2022 20:01:47 +0300 Subject: drm/i915/audio: Use intel_de_rmw() for most audio registers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The audio code does a lot of RMW accesses. Utilize intel_de_rmw() to make that a bit less tedious. There are still some hand rolled RMW left, but those have a lot of code in between the read and write to calculate the new value, so would need some refactoring first. v2: Add parens around the ?: to satisfy the robot Cc: Chaitanya Kumar Borah Cc: Kai Vehmanen Cc: Takashi Iwai Reviewed-by: Jani Nikula Reviewed-by: Kai Vehmanen Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221026170150.2654-13-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_audio.c | 138 ++++++++++++----------------- 1 file changed, 57 insertions(+), 81 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c index f4c319a3003b..9ba1351f2c6d 100644 --- a/drivers/gpu/drm/i915/display/intel_audio.c +++ b/drivers/gpu/drm/i915/display/intel_audio.c @@ -319,12 +319,10 @@ static void g4x_audio_codec_disable(struct intel_encoder *encoder, const struct drm_connector_state *old_conn_state) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); - u32 tmp; /* Invalidate ELD */ - tmp = intel_de_read(i915, G4X_AUD_CNTL_ST); - tmp &= ~G4X_ELD_VALID; - intel_de_write(i915, G4X_AUD_CNTL_ST, tmp); + intel_de_rmw(i915, G4X_AUD_CNTL_ST, + G4X_ELD_VALID, 0); } static void g4x_audio_codec_enable(struct intel_encoder *encoder, @@ -335,11 +333,9 @@ static void g4x_audio_codec_enable(struct intel_encoder *encoder, struct drm_connector *connector = conn_state->connector; const u32 *eld = (const u32 *)connector->eld; int eld_buffer_size, len, i; - u32 tmp; - tmp = intel_de_read(i915, G4X_AUD_CNTL_ST); - tmp &= ~(G4X_ELD_VALID | G4X_ELD_ADDRESS_MASK); - intel_de_write(i915, G4X_AUD_CNTL_ST, tmp); + intel_de_rmw(i915, G4X_AUD_CNTL_ST, + G4X_ELD_VALID | G4X_ELD_ADDRESS_MASK, 0); eld_buffer_size = g4x_eld_buffer_size(i915); len = min(drm_eld_size(connector->eld) / 4, eld_buffer_size); @@ -352,9 +348,8 @@ static void g4x_audio_codec_enable(struct intel_encoder *encoder, drm_WARN_ON(&i915->drm, (intel_de_read(i915, G4X_AUD_CNTL_ST) & G4X_ELD_ADDRESS_MASK) != 0); - tmp = intel_de_read(i915, G4X_AUD_CNTL_ST); - tmp |= G4X_ELD_VALID; - intel_de_write(i915, G4X_AUD_CNTL_ST, tmp); + intel_de_rmw(i915, G4X_AUD_CNTL_ST, + 0, G4X_ELD_VALID); } static void @@ -474,25 +469,22 @@ static void hsw_audio_codec_disable(struct intel_encoder *encoder, { struct drm_i915_private *i915 = to_i915(encoder->base.dev); enum transcoder cpu_transcoder = old_crtc_state->cpu_transcoder; - u32 tmp; mutex_lock(&i915->display.audio.mutex); /* Disable timestamps */ - tmp = intel_de_read(i915, HSW_AUD_CFG(cpu_transcoder)); - tmp &= ~AUD_CONFIG_N_VALUE_INDEX; - tmp |= AUD_CONFIG_N_PROG_ENABLE; - tmp &= ~AUD_CONFIG_UPPER_N_MASK; - tmp &= ~AUD_CONFIG_LOWER_N_MASK; - if (intel_crtc_has_dp_encoder(old_crtc_state)) - tmp |= AUD_CONFIG_N_VALUE_INDEX; - intel_de_write(i915, HSW_AUD_CFG(cpu_transcoder), tmp); - - /* Invalidate ELD */ - tmp = intel_de_read(i915, HSW_AUD_PIN_ELD_CP_VLD); - tmp &= ~AUDIO_ELD_VALID(cpu_transcoder); - tmp &= ~AUDIO_OUTPUT_ENABLE(cpu_transcoder); - intel_de_write(i915, HSW_AUD_PIN_ELD_CP_VLD, tmp); + intel_de_rmw(i915, HSW_AUD_CFG(cpu_transcoder), + AUD_CONFIG_N_VALUE_INDEX | + AUD_CONFIG_UPPER_N_MASK | + AUD_CONFIG_LOWER_N_MASK, + AUD_CONFIG_N_PROG_ENABLE | + (intel_crtc_has_dp_encoder(old_crtc_state) ? + AUD_CONFIG_N_VALUE_INDEX : 0)); + + /* Disable audio presence detect, invalidate ELD */ + intel_de_rmw(i915, HSW_AUD_PIN_ELD_CP_VLD, + AUDIO_ELD_VALID(cpu_transcoder) | + AUDIO_OUTPUT_ENABLE(cpu_transcoder), 0); mutex_unlock(&i915->display.audio.mutex); } @@ -615,7 +607,6 @@ static void hsw_audio_codec_enable(struct intel_encoder *encoder, enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; const u32 *eld = (const u32 *)connector->eld; int eld_buffer_size, len, i; - u32 tmp; mutex_lock(&i915->display.audio.mutex); @@ -624,10 +615,9 @@ static void hsw_audio_codec_enable(struct intel_encoder *encoder, enable_audio_dsc_wa(encoder, crtc_state); /* Enable audio presence detect, invalidate ELD */ - tmp = intel_de_read(i915, HSW_AUD_PIN_ELD_CP_VLD); - tmp |= AUDIO_OUTPUT_ENABLE(cpu_transcoder); - tmp &= ~AUDIO_ELD_VALID(cpu_transcoder); - intel_de_write(i915, HSW_AUD_PIN_ELD_CP_VLD, tmp); + intel_de_rmw(i915, HSW_AUD_PIN_ELD_CP_VLD, + AUDIO_ELD_VALID(cpu_transcoder), + AUDIO_OUTPUT_ENABLE(cpu_transcoder)); /* * FIXME: We're supposed to wait for vblank here, but we have vblanks @@ -636,10 +626,9 @@ static void hsw_audio_codec_enable(struct intel_encoder *encoder, * infrastructure is not there yet. */ - /* Reset ELD write address */ - tmp = intel_de_read(i915, HSW_AUD_DIP_ELD_CTRL(cpu_transcoder)); - tmp &= ~IBX_ELD_ADDRESS_MASK; - intel_de_write(i915, HSW_AUD_DIP_ELD_CTRL(cpu_transcoder), tmp); + /* Reset ELD address */ + intel_de_rmw(i915, HSW_AUD_DIP_ELD_CTRL(cpu_transcoder), + IBX_ELD_ADDRESS_MASK, 0); eld_buffer_size = hsw_eld_buffer_size(i915, cpu_transcoder); len = min(drm_eld_size(connector->eld) / 4, eld_buffer_size); @@ -654,9 +643,8 @@ static void hsw_audio_codec_enable(struct intel_encoder *encoder, IBX_ELD_ADDRESS_MASK) != 0); /* ELD valid */ - tmp = intel_de_read(i915, HSW_AUD_PIN_ELD_CP_VLD); - tmp |= AUDIO_ELD_VALID(cpu_transcoder); - intel_de_write(i915, HSW_AUD_PIN_ELD_CP_VLD, tmp); + intel_de_rmw(i915, HSW_AUD_PIN_ELD_CP_VLD, + 0, AUDIO_ELD_VALID(cpu_transcoder)); /* Enable timestamps */ hsw_audio_config_update(encoder, crtc_state); @@ -710,10 +698,9 @@ static void ilk_audio_codec_disable(struct intel_encoder *encoder, { struct drm_i915_private *i915 = to_i915(encoder->base.dev); struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc); - enum pipe pipe = crtc->pipe; enum port port = encoder->port; + enum pipe pipe = crtc->pipe; struct ilk_audio_regs regs; - u32 tmp; if (drm_WARN_ON(&i915->drm, port == PORT_A)) return; @@ -723,19 +710,17 @@ static void ilk_audio_codec_disable(struct intel_encoder *encoder, mutex_lock(&i915->display.audio.mutex); /* Disable timestamps */ - tmp = intel_de_read(i915, regs.aud_config); - tmp &= ~AUD_CONFIG_N_VALUE_INDEX; - tmp |= AUD_CONFIG_N_PROG_ENABLE; - tmp &= ~AUD_CONFIG_UPPER_N_MASK; - tmp &= ~AUD_CONFIG_LOWER_N_MASK; - if (intel_crtc_has_dp_encoder(old_crtc_state)) - tmp |= AUD_CONFIG_N_VALUE_INDEX; - intel_de_write(i915, regs.aud_config, tmp); + intel_de_rmw(i915, regs.aud_config, + AUD_CONFIG_N_VALUE_INDEX | + AUD_CONFIG_UPPER_N_MASK | + AUD_CONFIG_LOWER_N_MASK, + AUD_CONFIG_N_PROG_ENABLE | + (intel_crtc_has_dp_encoder(old_crtc_state) ? + AUD_CONFIG_N_VALUE_INDEX : 0)); /* Invalidate ELD */ - tmp = intel_de_read(i915, regs.aud_cntrl_st2); - tmp &= ~IBX_ELD_VALID(port); - intel_de_write(i915, regs.aud_cntrl_st2, tmp); + intel_de_rmw(i915, regs.aud_cntrl_st2, + IBX_ELD_VALID(port), 0); mutex_unlock(&i915->display.audio.mutex); } @@ -748,11 +733,10 @@ static void ilk_audio_codec_enable(struct intel_encoder *encoder, struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_connector *connector = conn_state->connector; const u32 *eld = (const u32 *)connector->eld; - enum pipe pipe = crtc->pipe; enum port port = encoder->port; + enum pipe pipe = crtc->pipe; int eld_buffer_size, len, i; struct ilk_audio_regs regs; - u32 tmp; if (drm_WARN_ON(&i915->drm, port == PORT_A)) return; @@ -769,14 +753,12 @@ static void ilk_audio_codec_enable(struct intel_encoder *encoder, mutex_lock(&i915->display.audio.mutex); /* Invalidate ELD */ - tmp = intel_de_read(i915, regs.aud_cntrl_st2); - tmp &= ~IBX_ELD_VALID(port); - intel_de_write(i915, regs.aud_cntrl_st2, tmp); + intel_de_rmw(i915, regs.aud_cntrl_st2, + IBX_ELD_VALID(port), 0); - /* Reset ELD write address */ - tmp = intel_de_read(i915, regs.aud_cntl_st); - tmp &= ~IBX_ELD_ADDRESS_MASK; - intel_de_write(i915, regs.aud_cntl_st, tmp); + /* Reset ELD address */ + intel_de_rmw(i915, regs.aud_cntl_st, + IBX_ELD_ADDRESS_MASK, 0); eld_buffer_size = ilk_eld_buffer_size(i915, pipe); len = min(drm_eld_size(connector->eld) / 4, eld_buffer_size); @@ -790,20 +772,17 @@ static void ilk_audio_codec_enable(struct intel_encoder *encoder, (intel_de_read(i915, regs.aud_cntl_st) & IBX_ELD_ADDRESS_MASK) != 0); /* ELD valid */ - tmp = intel_de_read(i915, regs.aud_cntrl_st2); - tmp |= IBX_ELD_VALID(port); - intel_de_write(i915, regs.aud_cntrl_st2, tmp); + intel_de_rmw(i915, regs.aud_cntrl_st2, + 0, IBX_ELD_VALID(port)); /* Enable timestamps */ - tmp = intel_de_read(i915, regs.aud_config); - tmp &= ~AUD_CONFIG_N_VALUE_INDEX; - tmp &= ~AUD_CONFIG_N_PROG_ENABLE; - tmp &= ~AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK; - if (intel_crtc_has_dp_encoder(crtc_state)) - tmp |= AUD_CONFIG_N_VALUE_INDEX; - else - tmp |= audio_config_hdmi_pixel_clock(crtc_state); - intel_de_write(i915, regs.aud_config, tmp); + intel_de_rmw(i915, regs.aud_config, + AUD_CONFIG_N_VALUE_INDEX | + AUD_CONFIG_N_PROG_ENABLE | + AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK, + (intel_crtc_has_dp_encoder(crtc_state) ? + AUD_CONFIG_N_VALUE_INDEX : + audio_config_hdmi_pixel_clock(crtc_state))); mutex_unlock(&i915->display.audio.mutex); } @@ -1067,8 +1046,8 @@ static unsigned long i915_audio_component_get_power(struct device *kdev) glk_force_audio_cdclk(i915, true); if (DISPLAY_VER(i915) >= 10) - intel_de_write(i915, AUD_PIN_BUF_CTL, - (intel_de_read(i915, AUD_PIN_BUF_CTL) | AUD_PIN_BUF_ENABLE)); + intel_de_rmw(i915, AUD_PIN_BUF_CTL, + 0, AUD_PIN_BUF_ENABLE); } return ret; @@ -1092,7 +1071,6 @@ static void i915_audio_component_codec_wake_override(struct device *kdev, { struct drm_i915_private *i915 = kdev_to_i915(kdev); unsigned long cookie; - u32 tmp; if (DISPLAY_VER(i915) < 9) return; @@ -1103,15 +1081,13 @@ static void i915_audio_component_codec_wake_override(struct device *kdev, * Enable/disable generating the codec wake signal, overriding the * internal logic to generate the codec wake to controller. */ - tmp = intel_de_read(i915, HSW_AUD_CHICKENBIT); - tmp &= ~SKL_AUD_CODEC_WAKE_SIGNAL; - intel_de_write(i915, HSW_AUD_CHICKENBIT, tmp); + intel_de_rmw(i915, HSW_AUD_CHICKENBIT, + SKL_AUD_CODEC_WAKE_SIGNAL, 0); usleep_range(1000, 1500); if (enable) { - tmp = intel_de_read(i915, HSW_AUD_CHICKENBIT); - tmp |= SKL_AUD_CODEC_WAKE_SIGNAL; - intel_de_write(i915, HSW_AUD_CHICKENBIT, tmp); + intel_de_rmw(i915, HSW_AUD_CHICKENBIT, + 0, SKL_AUD_CODEC_WAKE_SIGNAL); usleep_range(1000, 1500); } -- cgit From cbbda2ffbb6533fba01b9c40b12c8532a115da46 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 26 Oct 2022 20:01:48 +0300 Subject: drm/i915/audio: Split "ELD valid" vs. audio PD on hsw+ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On the older platforms the audio presence detect bit is in the port register, so it gets written outside audio codec hooks and is this separate from the ELD valid toggling. Split the operations into two steps on hsw+ to be more consistent with both the other platforms and the spec. Also according to the spec we might need some vblank waits between the two which definitely needs them done separately. Cc: Chaitanya Kumar Borah Cc: Kai Vehmanen Cc: Takashi Iwai Reviewed-by: Jani Nikula Reviewed-by: Kai Vehmanen Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221026170150.2654-14-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_audio.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c index 9ba1351f2c6d..cbc5615f43bf 100644 --- a/drivers/gpu/drm/i915/display/intel_audio.c +++ b/drivers/gpu/drm/i915/display/intel_audio.c @@ -481,9 +481,12 @@ static void hsw_audio_codec_disable(struct intel_encoder *encoder, (intel_crtc_has_dp_encoder(old_crtc_state) ? AUD_CONFIG_N_VALUE_INDEX : 0)); - /* Disable audio presence detect, invalidate ELD */ + /* Invalidate ELD */ + intel_de_rmw(i915, HSW_AUD_PIN_ELD_CP_VLD, + AUDIO_ELD_VALID(cpu_transcoder), 0); + + /* Disable audio presence detect */ intel_de_rmw(i915, HSW_AUD_PIN_ELD_CP_VLD, - AUDIO_ELD_VALID(cpu_transcoder) | AUDIO_OUTPUT_ENABLE(cpu_transcoder), 0); mutex_unlock(&i915->display.audio.mutex); @@ -614,10 +617,13 @@ static void hsw_audio_codec_enable(struct intel_encoder *encoder, if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP)) enable_audio_dsc_wa(encoder, crtc_state); - /* Enable audio presence detect, invalidate ELD */ + /* Enable audio presence detect */ + intel_de_rmw(i915, HSW_AUD_PIN_ELD_CP_VLD, + 0, AUDIO_OUTPUT_ENABLE(cpu_transcoder)); + + /* Invalidate ELD */ intel_de_rmw(i915, HSW_AUD_PIN_ELD_CP_VLD, - AUDIO_ELD_VALID(cpu_transcoder), - AUDIO_OUTPUT_ENABLE(cpu_transcoder)); + AUDIO_ELD_VALID(cpu_transcoder), 0); /* * FIXME: We're supposed to wait for vblank here, but we have vblanks -- cgit From c3c5dc1d9224fb3e0c6a104527567090fbbae13c Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 26 Oct 2022 20:01:49 +0300 Subject: drm/i915/audio: Do the vblank waits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The spec tells us to do a bunch of vblank waits in the audio enable/disable sequences. Make it so. The FIXMEs are nonsense since we do the audio disable very early and enable very late, so vblank interrupts are in fact enabled when we do this. TODO not sure we actually want these since we don't even rely on the hw ELD buffer, and these might be there just to give the audio side a bit of time to respond to the unsol events. OTOH they might be really needed for some other reason. Cc: Chaitanya Kumar Borah Cc: Kai Vehmanen Cc: Takashi Iwai Acked-by: Jani Nikula Reviewed-by: Kai Vehmanen Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221026170150.2654-15-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_audio.c | 31 +++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c index cbc5615f43bf..c3176c9c89a6 100644 --- a/drivers/gpu/drm/i915/display/intel_audio.c +++ b/drivers/gpu/drm/i915/display/intel_audio.c @@ -319,10 +319,14 @@ static void g4x_audio_codec_disable(struct intel_encoder *encoder, const struct drm_connector_state *old_conn_state) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); + struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc); /* Invalidate ELD */ intel_de_rmw(i915, G4X_AUD_CNTL_ST, G4X_ELD_VALID, 0); + + intel_crtc_wait_for_next_vblank(crtc); + intel_crtc_wait_for_next_vblank(crtc); } static void g4x_audio_codec_enable(struct intel_encoder *encoder, @@ -330,10 +334,13 @@ static void g4x_audio_codec_enable(struct intel_encoder *encoder, const struct drm_connector_state *conn_state) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_connector *connector = conn_state->connector; const u32 *eld = (const u32 *)connector->eld; int eld_buffer_size, len, i; + intel_crtc_wait_for_next_vblank(crtc); + intel_de_rmw(i915, G4X_AUD_CNTL_ST, G4X_ELD_VALID | G4X_ELD_ADDRESS_MASK, 0); @@ -468,6 +475,7 @@ static void hsw_audio_codec_disable(struct intel_encoder *encoder, const struct drm_connector_state *old_conn_state) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); + struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc); enum transcoder cpu_transcoder = old_crtc_state->cpu_transcoder; mutex_lock(&i915->display.audio.mutex); @@ -485,6 +493,9 @@ static void hsw_audio_codec_disable(struct intel_encoder *encoder, intel_de_rmw(i915, HSW_AUD_PIN_ELD_CP_VLD, AUDIO_ELD_VALID(cpu_transcoder), 0); + intel_crtc_wait_for_next_vblank(crtc); + intel_crtc_wait_for_next_vblank(crtc); + /* Disable audio presence detect */ intel_de_rmw(i915, HSW_AUD_PIN_ELD_CP_VLD, AUDIO_OUTPUT_ENABLE(cpu_transcoder), 0); @@ -606,6 +617,7 @@ static void hsw_audio_codec_enable(struct intel_encoder *encoder, const struct drm_connector_state *conn_state) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_connector *connector = conn_state->connector; enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; const u32 *eld = (const u32 *)connector->eld; @@ -621,17 +633,12 @@ static void hsw_audio_codec_enable(struct intel_encoder *encoder, intel_de_rmw(i915, HSW_AUD_PIN_ELD_CP_VLD, 0, AUDIO_OUTPUT_ENABLE(cpu_transcoder)); + intel_crtc_wait_for_next_vblank(crtc); + /* Invalidate ELD */ intel_de_rmw(i915, HSW_AUD_PIN_ELD_CP_VLD, AUDIO_ELD_VALID(cpu_transcoder), 0); - /* - * FIXME: We're supposed to wait for vblank here, but we have vblanks - * disabled during the mode set. The proper fix would be to push the - * rest of the setup into a vblank work item, queued here, but the - * infrastructure is not there yet. - */ - /* Reset ELD address */ intel_de_rmw(i915, HSW_AUD_DIP_ELD_CTRL(cpu_transcoder), IBX_ELD_ADDRESS_MASK, 0); @@ -729,6 +736,9 @@ static void ilk_audio_codec_disable(struct intel_encoder *encoder, IBX_ELD_VALID(port), 0); mutex_unlock(&i915->display.audio.mutex); + + intel_crtc_wait_for_next_vblank(crtc); + intel_crtc_wait_for_next_vblank(crtc); } static void ilk_audio_codec_enable(struct intel_encoder *encoder, @@ -747,12 +757,7 @@ static void ilk_audio_codec_enable(struct intel_encoder *encoder, if (drm_WARN_ON(&i915->drm, port == PORT_A)) return; - /* - * FIXME: We're supposed to wait for vblank here, but we have vblanks - * disabled during the mode set. The proper fix would be to push the - * rest of the setup into a vblank work item, queued here, but the - * infrastructure is not there yet. - */ + intel_crtc_wait_for_next_vblank(crtc); ilk_audio_regs_init(i915, pipe, ®s); -- cgit From 8388eb067cd6db7ea514235d84798dd73872208a Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 26 Oct 2022 20:01:50 +0300 Subject: drm/i915/sdvo: Extract intel_sdvo_has_audio() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pull the SDVO audio state computation into a helper. This is almost identical to intel_hdmi_has_audio(), except the sink capabilities are stored under intel_sdvo rather than intel_hdmi. Might be nice to get rid of this duplication eventually... Cc: Chaitanya Kumar Borah Cc: Kai Vehmanen Cc: Takashi Iwai Reviewed-by: Jani Nikula Reviewed-by: Kai Vehmanen Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221026170150.2654-16-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_sdvo.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c index cf8e80936d8e..8852564b5fbf 100644 --- a/drivers/gpu/drm/i915/display/intel_sdvo.c +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c @@ -1297,13 +1297,28 @@ static bool intel_sdvo_limited_color_range(struct intel_encoder *encoder, return intel_hdmi_limited_color_range(crtc_state, conn_state); } +static bool intel_sdvo_has_audio(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + const struct drm_connector_state *conn_state) +{ + struct intel_sdvo *intel_sdvo = to_sdvo(encoder); + const struct intel_digital_connector_state *intel_conn_state = + to_intel_digital_connector_state(conn_state); + + if (!crtc_state->has_hdmi_sink) + return false; + + if (intel_conn_state->force_audio == HDMI_AUDIO_AUTO) + return intel_sdvo->has_hdmi_audio; + else + return intel_conn_state->force_audio == HDMI_AUDIO_ON; +} + static int intel_sdvo_compute_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state) { struct intel_sdvo *intel_sdvo = to_sdvo(encoder); - struct intel_sdvo_connector_state *intel_sdvo_state = - to_intel_sdvo_connector_state(conn_state); struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(conn_state->connector); struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; @@ -1362,13 +1377,7 @@ static int intel_sdvo_compute_config(struct intel_encoder *encoder, pipe_config->has_hdmi_sink = intel_has_hdmi_sink(intel_sdvo, conn_state); - if (pipe_config->has_hdmi_sink) { - if (intel_sdvo_state->base.force_audio == HDMI_AUDIO_AUTO) - pipe_config->has_audio = intel_sdvo->has_hdmi_audio; - else - pipe_config->has_audio = - intel_sdvo_state->base.force_audio == HDMI_AUDIO_ON; - } + pipe_config->has_audio = intel_sdvo_has_audio(encoder, pipe_config, conn_state); pipe_config->limited_color_range = intel_sdvo_limited_color_range(encoder, pipe_config, -- cgit From e37203511c1f2622398eafb7c94a00915bf8e1a1 Mon Sep 17 00:00:00 2001 From: Leo Chen Date: Thu, 20 Oct 2022 11:46:40 -0400 Subject: drm/amd/display: Update DSC capabilitie for DCN314 dcn314 has 4 DSC - conflicted hardware document updated and confirmed. Tested-by: Mark Broadworth Reviewed-by: Charlene Liu Acked-by: Rodrigo Siqueira Signed-off-by: Leo Chen Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c index 92eb56873eee..85e2d87a8e44 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c @@ -847,7 +847,7 @@ static const struct resource_caps res_cap_dcn314 = { .num_ddc = 5, .num_vmid = 16, .num_mpc_3dlut = 2, - .num_dsc = 3, + .num_dsc = 4, }; static const struct dc_plane_cap plane_cap = { -- cgit From d1bc26cb5cd51fd1e7984423b665bf8abfd69256 Mon Sep 17 00:00:00 2001 From: Fangzhi Zuo Date: Thu, 20 Oct 2022 11:46:41 -0400 Subject: drm/amd/display: Ignore Cable ID Feature Ignore cable ID for DP2 receivers that does not support the feature. Tested-by: Mark Broadworth Reviewed-by: Roman Li Acked-by: Rodrigo Siqueira Signed-off-by: Fangzhi Zuo Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index c053cb79cd06..589bee9acf16 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1549,6 +1549,9 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) adev->dm.dc->debug.visual_confirm = amdgpu_dc_visual_confirm; + /* TODO: Remove after DP2 receiver gets proper support of Cable ID feature */ + adev->dm.dc->debug.ignore_cable_id = true; + r = dm_dmub_hw_init(adev); if (r) { DRM_ERROR("DMUB interface failed to initialize: status=%d\n", r); -- cgit From c0459bddd1955df35c9331757671e64e3ea0a77a Mon Sep 17 00:00:00 2001 From: Alan Liu Date: Thu, 20 Oct 2022 11:46:42 -0400 Subject: drm/amd/display: Implement secure display on DCN21 [Why] Porting secure display feature from DCN10 to DCN21. Support single display for now and will extend to multiple displays. [How] - use workqueue to offload works for dmub or dmcu firmware - after receiving ROI update from userspace, set skip_frame_cnt to 1 - refactor amdgpu_dm_crtc_handle_crc_window_irq() - disable PSR before activating secure_display on a crtc - check if secure_display is activated before enabling psr - only work for single display for now. Tested-by: Mark Broadworth Reviewed-by: Wayne Lin Acked-by: Rodrigo Siqueira Signed-off-by: Alan Liu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 7 +- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c | 151 ++++++++++----------- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h | 17 ++- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c | 3 + .../drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 55 +++++--- .../amd/display/amdgpu_dm/amdgpu_dm_irq_params.h | 2 +- drivers/gpu/drm/amd/display/dc/core/dc.c | 115 ++++++++-------- drivers/gpu/drm/amd/display/dc/dc_stream.h | 8 +- drivers/gpu/drm/amd/display/dc/dc_types.h | 14 ++ drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h | 14 -- drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 26 ++++ 11 files changed, 223 insertions(+), 189 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 589bee9acf16..72aede3fcf9b 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -7840,6 +7840,9 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, */ if (acrtc_state->stream->link->psr_settings.psr_version >= DC_PSR_VERSION_SU_1 && acrtc_attach->dm_irq_params.allow_psr_entry && +#ifdef CONFIG_DRM_AMD_SECURE_DISPLAY + !amdgpu_dm_crc_window_is_activated(acrtc_state->base.crtc) && +#endif !acrtc_state->stream->link->psr_settings.psr_allow_active) amdgpu_dm_psr_enable(acrtc_state->stream); } else { @@ -8301,8 +8304,8 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) if (amdgpu_dm_crc_window_is_activated(crtc)) { spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags); - acrtc->dm_irq_params.crc_window.update_win = true; - acrtc->dm_irq_params.crc_window.skip_frame_cnt = 2; + acrtc->dm_irq_params.window_param.update_win = true; + acrtc->dm_irq_params.window_param.skip_frame_cnt = 2; spin_lock_irq(&crc_rd_wrk->crc_rd_work_lock); crc_rd_wrk->crtc = crtc; spin_unlock_irq(&crc_rd_wrk->crc_rd_work_lock); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c index 8a441a22c46e..a857f6454753 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c @@ -89,13 +89,13 @@ static void amdgpu_dm_set_crc_window_default(struct drm_crtc *crtc) struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); spin_lock_irq(&drm_dev->event_lock); - acrtc->dm_irq_params.crc_window.x_start = 0; - acrtc->dm_irq_params.crc_window.y_start = 0; - acrtc->dm_irq_params.crc_window.x_end = 0; - acrtc->dm_irq_params.crc_window.y_end = 0; - acrtc->dm_irq_params.crc_window.activated = false; - acrtc->dm_irq_params.crc_window.update_win = false; - acrtc->dm_irq_params.crc_window.skip_frame_cnt = 0; + acrtc->dm_irq_params.window_param.roi.x_start = 0; + acrtc->dm_irq_params.window_param.roi.y_start = 0; + acrtc->dm_irq_params.window_param.roi.x_end = 0; + acrtc->dm_irq_params.window_param.roi.y_end = 0; + acrtc->dm_irq_params.window_param.activated = false; + acrtc->dm_irq_params.window_param.update_win = false; + acrtc->dm_irq_params.window_param.skip_frame_cnt = 0; spin_unlock_irq(&drm_dev->event_lock); } @@ -135,6 +135,22 @@ static void amdgpu_dm_crtc_notify_ta_to_read(struct work_struct *work) } } +static void +amdgpu_dm_forward_crc_window(struct work_struct *work) +{ + struct crc_fw_work *crc_fw_wrk; + struct amdgpu_display_manager *dm; + + crc_fw_wrk = container_of(work, struct crc_fw_work, forward_roi_work); + dm = crc_fw_wrk->dm; + + mutex_lock(&dm->dc_lock); + dc_stream_forward_crc_window(dm->dc, &crc_fw_wrk->roi, crc_fw_wrk->stream, crc_fw_wrk->is_stop_cmd); + mutex_unlock(&dm->dc_lock); + + kfree(crc_fw_wrk); +} + bool amdgpu_dm_crc_window_is_activated(struct drm_crtc *crtc) { struct drm_device *drm_dev = crtc->dev; @@ -142,7 +158,7 @@ bool amdgpu_dm_crc_window_is_activated(struct drm_crtc *crtc) bool ret = false; spin_lock_irq(&drm_dev->event_lock); - ret = acrtc->dm_irq_params.crc_window.activated; + ret = acrtc->dm_irq_params.window_param.activated; spin_unlock_irq(&drm_dev->event_lock); return ret; @@ -187,9 +203,11 @@ int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc, if (adev->dm.crc_rd_wrk) { flush_work(&adev->dm.crc_rd_wrk->notify_ta_work); spin_lock_irq(&adev->dm.crc_rd_wrk->crc_rd_work_lock); + if (adev->dm.crc_rd_wrk->crtc == crtc) { - dc_stream_stop_dmcu_crc_win_update(stream_state->ctx->dc, - dm_crtc_state->stream); + /* stop ROI update on this crtc */ + dc_stream_forward_crc_window(stream_state->ctx->dc, + NULL, stream_state, true); adev->dm.crc_rd_wrk->crtc = NULL; } spin_unlock_irq(&adev->dm.crc_rd_wrk->crc_rd_work_lock); @@ -439,14 +457,9 @@ void amdgpu_dm_crtc_handle_crc_window_irq(struct drm_crtc *crtc) enum amdgpu_dm_pipe_crc_source cur_crc_src; struct amdgpu_crtc *acrtc = NULL; struct amdgpu_device *adev = NULL; - struct crc_rd_work *crc_rd_wrk = NULL; - struct crc_params *crc_window = NULL, tmp_window; + struct crc_rd_work *crc_rd_wrk; + struct crc_fw_work *crc_fw_wrk; unsigned long flags1, flags2; - struct crtc_position position; - uint32_t v_blank; - uint32_t v_back_porch; - uint32_t crc_window_latch_up_line; - struct dc_crtc_timing *timing_out; if (crtc == NULL) return; @@ -458,74 +471,52 @@ void amdgpu_dm_crtc_handle_crc_window_irq(struct drm_crtc *crtc) spin_lock_irqsave(&drm_dev->event_lock, flags1); stream_state = acrtc->dm_irq_params.stream; cur_crc_src = acrtc->dm_irq_params.crc_src; - timing_out = &stream_state->timing; /* Early return if CRC capture is not enabled. */ if (!amdgpu_dm_is_valid_crc_source(cur_crc_src)) goto cleanup; - if (dm_is_crc_source_crtc(cur_crc_src)) { - if (acrtc->dm_irq_params.crc_window.activated) { - if (acrtc->dm_irq_params.crc_window.update_win) { - if (acrtc->dm_irq_params.crc_window.skip_frame_cnt) { - acrtc->dm_irq_params.crc_window.skip_frame_cnt -= 1; - goto cleanup; - } - crc_window = &tmp_window; - - tmp_window.windowa_x_start = - acrtc->dm_irq_params.crc_window.x_start; - tmp_window.windowa_y_start = - acrtc->dm_irq_params.crc_window.y_start; - tmp_window.windowa_x_end = - acrtc->dm_irq_params.crc_window.x_end; - tmp_window.windowa_y_end = - acrtc->dm_irq_params.crc_window.y_end; - tmp_window.windowb_x_start = - acrtc->dm_irq_params.crc_window.x_start; - tmp_window.windowb_y_start = - acrtc->dm_irq_params.crc_window.y_start; - tmp_window.windowb_x_end = - acrtc->dm_irq_params.crc_window.x_end; - tmp_window.windowb_y_end = - acrtc->dm_irq_params.crc_window.y_end; - - dc_stream_forward_dmcu_crc_window(stream_state->ctx->dc, - stream_state, crc_window); - - acrtc->dm_irq_params.crc_window.update_win = false; - - dc_stream_get_crtc_position(stream_state->ctx->dc, &stream_state, 1, - &position.vertical_count, - &position.nominal_vcount); - - v_blank = timing_out->v_total - timing_out->v_border_top - - timing_out->v_addressable - timing_out->v_border_bottom; - - v_back_porch = v_blank - timing_out->v_front_porch - - timing_out->v_sync_width; - - crc_window_latch_up_line = v_back_porch + timing_out->v_sync_width; - - /* take 3 lines margin*/ - if ((position.vertical_count + 3) >= crc_window_latch_up_line) - acrtc->dm_irq_params.crc_window.skip_frame_cnt = 1; - else - acrtc->dm_irq_params.crc_window.skip_frame_cnt = 0; - } else { - if (acrtc->dm_irq_params.crc_window.skip_frame_cnt == 0) { - if (adev->dm.crc_rd_wrk) { - crc_rd_wrk = adev->dm.crc_rd_wrk; - spin_lock_irqsave(&crc_rd_wrk->crc_rd_work_lock, flags2); - crc_rd_wrk->phy_inst = - stream_state->link->link_enc_hw_inst; - spin_unlock_irqrestore(&crc_rd_wrk->crc_rd_work_lock, flags2); - schedule_work(&crc_rd_wrk->notify_ta_work); - } - } else { - acrtc->dm_irq_params.crc_window.skip_frame_cnt -= 1; - } - } + if (!dm_is_crc_source_crtc(cur_crc_src)) + goto cleanup; + + if (!acrtc->dm_irq_params.window_param.activated) + goto cleanup; + + if (acrtc->dm_irq_params.window_param.update_win) { + if (acrtc->dm_irq_params.window_param.skip_frame_cnt) { + acrtc->dm_irq_params.window_param.skip_frame_cnt -= 1; + goto cleanup; + } + + /* prepare work for dmub to update ROI */ + crc_fw_wrk = kzalloc(sizeof(*crc_fw_wrk), GFP_ATOMIC); + if (!crc_fw_wrk) + goto cleanup; + + INIT_WORK(&crc_fw_wrk->forward_roi_work, amdgpu_dm_forward_crc_window); + crc_fw_wrk->dm = &adev->dm; + crc_fw_wrk->stream = stream_state; + crc_fw_wrk->roi.x_start = acrtc->dm_irq_params.window_param.roi.x_start; + crc_fw_wrk->roi.y_start = acrtc->dm_irq_params.window_param.roi.y_start; + crc_fw_wrk->roi.x_end = acrtc->dm_irq_params.window_param.roi.x_end; + crc_fw_wrk->roi.y_end = acrtc->dm_irq_params.window_param.roi.y_end; + schedule_work(&crc_fw_wrk->forward_roi_work); + + acrtc->dm_irq_params.window_param.update_win = false; + acrtc->dm_irq_params.window_param.skip_frame_cnt = 1; + + } else { + if (acrtc->dm_irq_params.window_param.skip_frame_cnt) { + acrtc->dm_irq_params.window_param.skip_frame_cnt -= 1; + goto cleanup; + } + + if (adev->dm.crc_rd_wrk) { + crc_rd_wrk = adev->dm.crc_rd_wrk; + spin_lock_irqsave(&crc_rd_wrk->crc_rd_work_lock, flags2); + crc_rd_wrk->phy_inst = stream_state->link->link_enc_hw_inst; + spin_unlock_irqrestore(&crc_rd_wrk->crc_rd_work_lock, flags2); + schedule_work(&crc_rd_wrk->notify_ta_work); } } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h index f07850db60a6..16bfc2dc35ab 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h @@ -40,11 +40,8 @@ enum amdgpu_dm_pipe_crc_source { }; #ifdef CONFIG_DRM_AMD_SECURE_DISPLAY -struct crc_window_parm { - uint16_t x_start; - uint16_t y_start; - uint16_t x_end; - uint16_t y_end; +struct crc_window_param { + struct crc_region roi; /* CRC windwo is activated or not*/ bool activated; /* Update crc window during vertical blank or not */ @@ -53,6 +50,7 @@ struct crc_window_parm { int skip_frame_cnt; }; +/* read_work for driver to call PSP to read */ struct crc_rd_work { struct work_struct notify_ta_work; /* To protect crc_rd_work carried fields*/ @@ -60,6 +58,15 @@ struct crc_rd_work { struct drm_crtc *crtc; uint8_t phy_inst; }; + +/* forward_work for driver to forward ROI to dmu */ +struct crc_fw_work { + struct work_struct forward_roi_work; + struct amdgpu_display_manager *dm; + struct dc_stream_state *stream; + struct crc_region roi; + bool is_stop_cmd; +}; #endif static inline bool amdgpu_dm_is_valid_crc_source(enum amdgpu_dm_pipe_crc_source source) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c index 594fe8a4d02b..3675b39e297a 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c @@ -127,6 +127,9 @@ static void vblank_control_worker(struct work_struct *work) amdgpu_dm_psr_disable(vblank_work->stream); } else if (vblank_work->stream->link->psr_settings.psr_feature_enabled && !vblank_work->stream->link->psr_settings.psr_allow_active && +#ifdef CONFIG_DRM_AMD_SECURE_DISPLAY + !amdgpu_dm_crc_window_is_activated(&vblank_work->acrtc->base) && +#endif vblank_work->acrtc->dm_irq_params.allow_psr_entry) { amdgpu_dm_psr_enable(vblank_work->stream); } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index 0c717d7b12e5..8f5b98df26db 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -38,6 +38,10 @@ #include "link_hwss.h" #include "dc/dc_dmub_srv.h" +#ifdef CONFIG_DRM_AMD_SECURE_DISPLAY +#include "amdgpu_dm_psr.h" +#endif + struct dmub_debugfs_trace_header { uint32_t entry_count; uint32_t reserved[3]; @@ -3081,8 +3085,8 @@ static int crc_win_x_start_set(void *data, u64 val) struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); spin_lock_irq(&drm_dev->event_lock); - acrtc->dm_irq_params.crc_window.x_start = (uint16_t) val; - acrtc->dm_irq_params.crc_window.update_win = false; + acrtc->dm_irq_params.window_param.roi.x_start = (uint16_t) val; + acrtc->dm_irq_params.window_param.update_win = false; spin_unlock_irq(&drm_dev->event_lock); return 0; @@ -3098,7 +3102,7 @@ static int crc_win_x_start_get(void *data, u64 *val) struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); spin_lock_irq(&drm_dev->event_lock); - *val = acrtc->dm_irq_params.crc_window.x_start; + *val = acrtc->dm_irq_params.window_param.roi.x_start; spin_unlock_irq(&drm_dev->event_lock); return 0; @@ -3118,8 +3122,8 @@ static int crc_win_y_start_set(void *data, u64 val) struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); spin_lock_irq(&drm_dev->event_lock); - acrtc->dm_irq_params.crc_window.y_start = (uint16_t) val; - acrtc->dm_irq_params.crc_window.update_win = false; + acrtc->dm_irq_params.window_param.roi.y_start = (uint16_t) val; + acrtc->dm_irq_params.window_param.update_win = false; spin_unlock_irq(&drm_dev->event_lock); return 0; @@ -3135,7 +3139,7 @@ static int crc_win_y_start_get(void *data, u64 *val) struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); spin_lock_irq(&drm_dev->event_lock); - *val = acrtc->dm_irq_params.crc_window.y_start; + *val = acrtc->dm_irq_params.window_param.roi.y_start; spin_unlock_irq(&drm_dev->event_lock); return 0; @@ -3154,8 +3158,8 @@ static int crc_win_x_end_set(void *data, u64 val) struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); spin_lock_irq(&drm_dev->event_lock); - acrtc->dm_irq_params.crc_window.x_end = (uint16_t) val; - acrtc->dm_irq_params.crc_window.update_win = false; + acrtc->dm_irq_params.window_param.roi.x_end = (uint16_t) val; + acrtc->dm_irq_params.window_param.update_win = false; spin_unlock_irq(&drm_dev->event_lock); return 0; @@ -3171,7 +3175,7 @@ static int crc_win_x_end_get(void *data, u64 *val) struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); spin_lock_irq(&drm_dev->event_lock); - *val = acrtc->dm_irq_params.crc_window.x_end; + *val = acrtc->dm_irq_params.window_param.roi.x_end; spin_unlock_irq(&drm_dev->event_lock); return 0; @@ -3190,8 +3194,8 @@ static int crc_win_y_end_set(void *data, u64 val) struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); spin_lock_irq(&drm_dev->event_lock); - acrtc->dm_irq_params.crc_window.y_end = (uint16_t) val; - acrtc->dm_irq_params.crc_window.update_win = false; + acrtc->dm_irq_params.window_param.roi.y_end = (uint16_t) val; + acrtc->dm_irq_params.window_param.update_win = false; spin_unlock_irq(&drm_dev->event_lock); return 0; @@ -3207,7 +3211,7 @@ static int crc_win_y_end_get(void *data, u64 *val) struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); spin_lock_irq(&drm_dev->event_lock); - *val = acrtc->dm_irq_params.crc_window.y_end; + *val = acrtc->dm_irq_params.window_param.roi.y_end; spin_unlock_irq(&drm_dev->event_lock); return 0; @@ -3230,31 +3234,38 @@ static int crc_win_update_set(void *data, u64 val) return 0; if (val) { + new_acrtc = to_amdgpu_crtc(new_crtc); + mutex_lock(&adev->dm.dc_lock); + /* PSR may write to OTG CRC window control register, + * so close it before starting secure_display. + */ + amdgpu_dm_psr_disable(new_acrtc->dm_irq_params.stream); + spin_lock_irq(&adev_to_drm(adev)->event_lock); spin_lock_irq(&crc_rd_wrk->crc_rd_work_lock); if (crc_rd_wrk->crtc) { old_crtc = crc_rd_wrk->crtc; old_acrtc = to_amdgpu_crtc(old_crtc); } - new_acrtc = to_amdgpu_crtc(new_crtc); if (old_crtc && old_crtc != new_crtc) { - old_acrtc->dm_irq_params.crc_window.activated = false; - old_acrtc->dm_irq_params.crc_window.update_win = false; - old_acrtc->dm_irq_params.crc_window.skip_frame_cnt = 0; + old_acrtc->dm_irq_params.window_param.activated = false; + old_acrtc->dm_irq_params.window_param.update_win = false; + old_acrtc->dm_irq_params.window_param.skip_frame_cnt = 0; - new_acrtc->dm_irq_params.crc_window.activated = true; - new_acrtc->dm_irq_params.crc_window.update_win = true; - new_acrtc->dm_irq_params.crc_window.skip_frame_cnt = 0; + new_acrtc->dm_irq_params.window_param.activated = true; + new_acrtc->dm_irq_params.window_param.update_win = true; + new_acrtc->dm_irq_params.window_param.skip_frame_cnt = 0; crc_rd_wrk->crtc = new_crtc; } else { - new_acrtc->dm_irq_params.crc_window.activated = true; - new_acrtc->dm_irq_params.crc_window.update_win = true; - new_acrtc->dm_irq_params.crc_window.skip_frame_cnt = 0; + new_acrtc->dm_irq_params.window_param.activated = true; + new_acrtc->dm_irq_params.window_param.update_win = true; + new_acrtc->dm_irq_params.window_param.skip_frame_cnt = 0; crc_rd_wrk->crtc = new_crtc; } spin_unlock_irq(&crc_rd_wrk->crc_rd_work_lock); spin_unlock_irq(&adev_to_drm(adev)->event_lock); + mutex_unlock(&adev->dm.dc_lock); } return 0; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq_params.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq_params.h index 79b5f9999fec..5c9303241aeb 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq_params.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq_params.h @@ -39,7 +39,7 @@ struct dm_irq_params { #ifdef CONFIG_DEBUG_FS enum amdgpu_dm_pipe_crc_source crc_src; #ifdef CONFIG_DRM_AMD_SECURE_DISPLAY - struct crc_window_parm crc_window; + struct crc_window_param window_param; #endif #endif }; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 56629197a6a1..58352de24061 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -491,86 +491,79 @@ bool dc_stream_get_crtc_position(struct dc *dc, } #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) -bool dc_stream_forward_dmcu_crc_window(struct dc *dc, struct dc_stream_state *stream, - struct crc_params *crc_window) +static inline void +dc_stream_forward_dmub_crc_window(struct dc_dmub_srv *dmub_srv, + struct crc_region *roi, struct otg_phy_mux *mux_mapping, bool is_stop) { - int i; - struct dmcu *dmcu = dc->res_pool->dmcu; - struct pipe_ctx *pipe; - struct crc_region tmp_win, *crc_win; - struct otg_phy_mux mapping_tmp, *mux_mapping; - - /*crc window can't be null*/ - if (!crc_window) - return false; - - if ((dmcu != NULL && dmcu->funcs->is_dmcu_initialized(dmcu))) { - crc_win = &tmp_win; - mux_mapping = &mapping_tmp; - /*set crc window*/ - tmp_win.x_start = crc_window->windowa_x_start; - tmp_win.y_start = crc_window->windowa_y_start; - tmp_win.x_end = crc_window->windowa_x_end; - tmp_win.y_end = crc_window->windowa_y_end; - - for (i = 0; i < MAX_PIPES; i++) { - pipe = &dc->current_state->res_ctx.pipe_ctx[i]; - if (pipe->stream == stream && !pipe->top_pipe && !pipe->prev_odm_pipe) - break; - } - - /* Stream not found */ - if (i == MAX_PIPES) - return false; - + union dmub_rb_cmd cmd = {0}; - /*set mux routing info*/ - mapping_tmp.phy_output_num = stream->link->link_enc_hw_inst; - mapping_tmp.otg_output_num = pipe->stream_res.tg->inst; + cmd.secure_display.roi_info.phy_id = mux_mapping->phy_output_num; + cmd.secure_display.roi_info.otg_id = mux_mapping->otg_output_num; - dmcu->funcs->forward_crc_window(dmcu, crc_win, mux_mapping); + if (is_stop) { + cmd.secure_display.header.type = DMUB_CMD__SECURE_DISPLAY; + cmd.secure_display.header.sub_type = DMUB_CMD__SECURE_DISPLAY_CRC_STOP_UPDATE; } else { - DC_LOG_DC("dmcu is not initialized"); - return false; + cmd.secure_display.header.type = DMUB_CMD__SECURE_DISPLAY; + cmd.secure_display.header.sub_type = DMUB_CMD__SECURE_DISPLAY_CRC_WIN_NOTIFY; + cmd.secure_display.roi_info.x_start = roi->x_start; + cmd.secure_display.roi_info.y_start = roi->y_start; + cmd.secure_display.roi_info.x_end = roi->x_end; + cmd.secure_display.roi_info.y_end = roi->y_end; } - return true; + dc_dmub_srv_cmd_queue(dmub_srv, &cmd); + dc_dmub_srv_cmd_execute(dmub_srv); } -bool dc_stream_stop_dmcu_crc_win_update(struct dc *dc, struct dc_stream_state *stream) +static inline void +dc_stream_forward_dmcu_crc_window(struct dmcu *dmcu, + struct crc_region *roi, struct otg_phy_mux *mux_mapping, bool is_stop) { - int i; - struct dmcu *dmcu = dc->res_pool->dmcu; - struct pipe_ctx *pipe; - struct otg_phy_mux mapping_tmp, *mux_mapping; + if (is_stop) + dmcu->funcs->stop_crc_win_update(dmcu, mux_mapping); + else + dmcu->funcs->forward_crc_window(dmcu, roi, mux_mapping); +} - if ((dmcu != NULL && dmcu->funcs->is_dmcu_initialized(dmcu))) { - mux_mapping = &mapping_tmp; +bool +dc_stream_forward_crc_window(struct dc *dc, + struct crc_region *roi, struct dc_stream_state *stream, bool is_stop) +{ + struct dmcu *dmcu; + struct dc_dmub_srv *dmub_srv; + struct otg_phy_mux mux_mapping; + struct pipe_ctx *pipe; + int i; - for (i = 0; i < MAX_PIPES; i++) { - pipe = &dc->current_state->res_ctx.pipe_ctx[i]; - if (pipe->stream == stream && !pipe->top_pipe && !pipe->prev_odm_pipe) - break; - } + for (i = 0; i < MAX_PIPES; i++) { + pipe = &dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe->stream == stream && !pipe->top_pipe && !pipe->prev_odm_pipe) + break; + } - /* Stream not found */ - if (i == MAX_PIPES) - return false; + /* Stream not found */ + if (i == MAX_PIPES) + return false; + mux_mapping.phy_output_num = stream->link->link_enc_hw_inst; + mux_mapping.otg_output_num = pipe->stream_res.tg->inst; - /*set mux routing info*/ - mapping_tmp.phy_output_num = stream->link->link_enc_hw_inst; - mapping_tmp.otg_output_num = pipe->stream_res.tg->inst; + dmcu = dc->res_pool->dmcu; + dmub_srv = dc->ctx->dmub_srv; - dmcu->funcs->stop_crc_win_update(dmcu, mux_mapping); - } else { - DC_LOG_DC("dmcu is not initialized"); + /* forward to dmub */ + if (dmub_srv) + dc_stream_forward_dmub_crc_window(dmub_srv, roi, &mux_mapping, is_stop); + /* forward to dmcu */ + else if (dmcu && dmcu->funcs->is_dmcu_initialized(dmcu)) + dc_stream_forward_dmcu_crc_window(dmcu, roi, &mux_mapping, is_stop); + else return false; - } return true; } -#endif +#endif /* CONFIG_DRM_AMD_SECURE_DISPLAY */ /** * dc_stream_configure_crc() - Configure CRC capture for the given stream. diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index 73dccd485895..26f8f18e675c 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -521,10 +521,10 @@ bool dc_stream_get_crtc_position(struct dc *dc, unsigned int *nom_v_pos); #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) -bool dc_stream_forward_dmcu_crc_window(struct dc *dc, struct dc_stream_state *stream, - struct crc_params *crc_window); -bool dc_stream_stop_dmcu_crc_win_update(struct dc *dc, - struct dc_stream_state *stream); +bool dc_stream_forward_crc_window(struct dc *dc, + struct crc_region *roi, + struct dc_stream_state *stream, + bool is_stop); #endif bool dc_stream_configure_crc(struct dc *dc, diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index ad9041472cca..27dd4304ce69 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -993,4 +993,18 @@ struct display_endpoint_id { enum display_endpoint_type ep_type; }; +#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) +struct crc_region { + uint16_t x_start; + uint16_t y_start; + uint16_t x_end; + uint16_t y_end; +}; + +struct otg_phy_mux { + uint8_t phy_output_num; + uint8_t otg_output_num; +}; +#endif + #endif /* DC_TYPES_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h index 8df2765cce78..9a2432608ddf 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h @@ -56,20 +56,6 @@ struct dmcu { bool auto_load_dmcu; }; -#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) -struct crc_region { - uint16_t x_start; - uint16_t y_start; - uint16_t x_end; - uint16_t y_end; -}; - -struct otg_phy_mux { - uint8_t phy_output_num; - uint8_t otg_output_num; -}; -#endif - struct dmcu_funcs { bool (*dmcu_init)(struct dmcu *dmcu); bool (*load_iram)(struct dmcu *dmcu, diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index 7a8f61517424..dc7c4d74cb5d 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -729,6 +729,10 @@ enum dmub_cmd_type { /** * Command type used for all VBIOS interface commands. */ + /** + * Command type used for all SECURE_DISPLAY commands. + */ + DMUB_CMD__SECURE_DISPLAY = 85, /** * Command type used to set DPIA HPD interrupt state @@ -3143,6 +3147,24 @@ struct dmub_rb_cmd_get_usbc_cable_id { } data; }; +enum dmub_cmd_secure_display_type { + DMUB_CMD__SECURE_DISPLAY_TEST_CMD = 0, + DMUB_CMD__SECURE_DISPLAY_CRC_STOP_UPDATE, + DMUB_CMD__SECURE_DISPLAY_CRC_WIN_NOTIFY +}; + +struct dmub_rb_cmd_secure_display { + struct dmub_cmd_header header; + struct dmub_cmd_roi_info { + uint16_t x_start; + uint16_t x_end; + uint16_t y_start; + uint16_t y_end; + uint8_t otg_id; + uint8_t phy_id; + } roi_info; +}; + /** * union dmub_rb_cmd - DMUB inbox command. */ @@ -3347,6 +3369,10 @@ union dmub_rb_cmd { * Definition of a DMUB_CMD__QUERY_HPD_STATE command. */ struct dmub_rb_cmd_query_hpd_state query_hpd; + /** + * Definition of a DMUB_CMD__SECURE_DISPLAY command. + */ + struct dmub_rb_cmd_secure_display secure_display; /** * Definition of a DMUB_CMD__DPIA_HPD_INT_ENABLE command. */ -- cgit From 62fa035b5605a993fa3b4526af8b6ed145e3ce1b Mon Sep 17 00:00:00 2001 From: Alan Liu Date: Thu, 20 Oct 2022 11:46:43 -0400 Subject: drm/amd/display: Drop struct crc_region and reuse struct rect [Why] reuse struct rect rather than adding a new struct. [How] - Userspace keeps inputting x_start, y_start, x_end, y_end - We translate data to x, y, width, height in code flow to store - translate back to x_start, y_start, x_end, y_end before programming HW Tested-by: Mark Broadworth Reviewed-by: Wayne Lin Acked-by: Rodrigo Siqueira Signed-off-by: Alan Liu Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c | 20 +++++++++++--------- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h | 7 +++++-- .../drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 16 ++++++++-------- drivers/gpu/drm/amd/display/dc/core/dc.c | 20 ++++++++++---------- drivers/gpu/drm/amd/display/dc/dc_stream.h | 2 +- drivers/gpu/drm/amd/display/dc/dc_types.h | 7 ------- drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c | 14 ++++++++++---- drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h | 2 +- 8 files changed, 46 insertions(+), 42 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c index a857f6454753..fb077e9af99f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c @@ -89,10 +89,10 @@ static void amdgpu_dm_set_crc_window_default(struct drm_crtc *crtc) struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); spin_lock_irq(&drm_dev->event_lock); - acrtc->dm_irq_params.window_param.roi.x_start = 0; - acrtc->dm_irq_params.window_param.roi.y_start = 0; - acrtc->dm_irq_params.window_param.roi.x_end = 0; - acrtc->dm_irq_params.window_param.roi.y_end = 0; + acrtc->dm_irq_params.window_param.x_start = 0; + acrtc->dm_irq_params.window_param.y_start = 0; + acrtc->dm_irq_params.window_param.x_end = 0; + acrtc->dm_irq_params.window_param.y_end = 0; acrtc->dm_irq_params.window_param.activated = false; acrtc->dm_irq_params.window_param.update_win = false; acrtc->dm_irq_params.window_param.skip_frame_cnt = 0; @@ -145,7 +145,7 @@ amdgpu_dm_forward_crc_window(struct work_struct *work) dm = crc_fw_wrk->dm; mutex_lock(&dm->dc_lock); - dc_stream_forward_crc_window(dm->dc, &crc_fw_wrk->roi, crc_fw_wrk->stream, crc_fw_wrk->is_stop_cmd); + dc_stream_forward_crc_window(dm->dc, &crc_fw_wrk->rect, crc_fw_wrk->stream, crc_fw_wrk->is_stop_cmd); mutex_unlock(&dm->dc_lock); kfree(crc_fw_wrk); @@ -496,10 +496,12 @@ void amdgpu_dm_crtc_handle_crc_window_irq(struct drm_crtc *crtc) INIT_WORK(&crc_fw_wrk->forward_roi_work, amdgpu_dm_forward_crc_window); crc_fw_wrk->dm = &adev->dm; crc_fw_wrk->stream = stream_state; - crc_fw_wrk->roi.x_start = acrtc->dm_irq_params.window_param.roi.x_start; - crc_fw_wrk->roi.y_start = acrtc->dm_irq_params.window_param.roi.y_start; - crc_fw_wrk->roi.x_end = acrtc->dm_irq_params.window_param.roi.x_end; - crc_fw_wrk->roi.y_end = acrtc->dm_irq_params.window_param.roi.y_end; + crc_fw_wrk->rect.x = acrtc->dm_irq_params.window_param.x_start; + crc_fw_wrk->rect.y = acrtc->dm_irq_params.window_param.y_start; + crc_fw_wrk->rect.width = acrtc->dm_irq_params.window_param.x_end - + acrtc->dm_irq_params.window_param.x_start; + crc_fw_wrk->rect.height = acrtc->dm_irq_params.window_param.y_end - + acrtc->dm_irq_params.window_param.y_start; schedule_work(&crc_fw_wrk->forward_roi_work); acrtc->dm_irq_params.window_param.update_win = false; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h index 16bfc2dc35ab..71bce608d751 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h @@ -41,7 +41,10 @@ enum amdgpu_dm_pipe_crc_source { #ifdef CONFIG_DRM_AMD_SECURE_DISPLAY struct crc_window_param { - struct crc_region roi; + uint16_t x_start; + uint16_t y_start; + uint16_t x_end; + uint16_t y_end; /* CRC windwo is activated or not*/ bool activated; /* Update crc window during vertical blank or not */ @@ -64,7 +67,7 @@ struct crc_fw_work { struct work_struct forward_roi_work; struct amdgpu_display_manager *dm; struct dc_stream_state *stream; - struct crc_region roi; + struct rect rect; bool is_stop_cmd; }; #endif diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index 8f5b98df26db..2c43cdd2e707 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -3085,7 +3085,7 @@ static int crc_win_x_start_set(void *data, u64 val) struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); spin_lock_irq(&drm_dev->event_lock); - acrtc->dm_irq_params.window_param.roi.x_start = (uint16_t) val; + acrtc->dm_irq_params.window_param.x_start = (uint16_t) val; acrtc->dm_irq_params.window_param.update_win = false; spin_unlock_irq(&drm_dev->event_lock); @@ -3102,7 +3102,7 @@ static int crc_win_x_start_get(void *data, u64 *val) struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); spin_lock_irq(&drm_dev->event_lock); - *val = acrtc->dm_irq_params.window_param.roi.x_start; + *val = acrtc->dm_irq_params.window_param.x_start; spin_unlock_irq(&drm_dev->event_lock); return 0; @@ -3122,7 +3122,7 @@ static int crc_win_y_start_set(void *data, u64 val) struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); spin_lock_irq(&drm_dev->event_lock); - acrtc->dm_irq_params.window_param.roi.y_start = (uint16_t) val; + acrtc->dm_irq_params.window_param.y_start = (uint16_t) val; acrtc->dm_irq_params.window_param.update_win = false; spin_unlock_irq(&drm_dev->event_lock); @@ -3139,7 +3139,7 @@ static int crc_win_y_start_get(void *data, u64 *val) struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); spin_lock_irq(&drm_dev->event_lock); - *val = acrtc->dm_irq_params.window_param.roi.y_start; + *val = acrtc->dm_irq_params.window_param.y_start; spin_unlock_irq(&drm_dev->event_lock); return 0; @@ -3158,7 +3158,7 @@ static int crc_win_x_end_set(void *data, u64 val) struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); spin_lock_irq(&drm_dev->event_lock); - acrtc->dm_irq_params.window_param.roi.x_end = (uint16_t) val; + acrtc->dm_irq_params.window_param.x_end = (uint16_t) val; acrtc->dm_irq_params.window_param.update_win = false; spin_unlock_irq(&drm_dev->event_lock); @@ -3175,7 +3175,7 @@ static int crc_win_x_end_get(void *data, u64 *val) struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); spin_lock_irq(&drm_dev->event_lock); - *val = acrtc->dm_irq_params.window_param.roi.x_end; + *val = acrtc->dm_irq_params.window_param.x_end; spin_unlock_irq(&drm_dev->event_lock); return 0; @@ -3194,7 +3194,7 @@ static int crc_win_y_end_set(void *data, u64 val) struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); spin_lock_irq(&drm_dev->event_lock); - acrtc->dm_irq_params.window_param.roi.y_end = (uint16_t) val; + acrtc->dm_irq_params.window_param.y_end = (uint16_t) val; acrtc->dm_irq_params.window_param.update_win = false; spin_unlock_irq(&drm_dev->event_lock); @@ -3211,7 +3211,7 @@ static int crc_win_y_end_get(void *data, u64 *val) struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); spin_lock_irq(&drm_dev->event_lock); - *val = acrtc->dm_irq_params.window_param.roi.y_end; + *val = acrtc->dm_irq_params.window_param.y_end; spin_unlock_irq(&drm_dev->event_lock); return 0; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 58352de24061..20c16ca935f7 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -493,7 +493,7 @@ bool dc_stream_get_crtc_position(struct dc *dc, #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) static inline void dc_stream_forward_dmub_crc_window(struct dc_dmub_srv *dmub_srv, - struct crc_region *roi, struct otg_phy_mux *mux_mapping, bool is_stop) + struct rect *rect, struct otg_phy_mux *mux_mapping, bool is_stop) { union dmub_rb_cmd cmd = {0}; @@ -506,10 +506,10 @@ dc_stream_forward_dmub_crc_window(struct dc_dmub_srv *dmub_srv, } else { cmd.secure_display.header.type = DMUB_CMD__SECURE_DISPLAY; cmd.secure_display.header.sub_type = DMUB_CMD__SECURE_DISPLAY_CRC_WIN_NOTIFY; - cmd.secure_display.roi_info.x_start = roi->x_start; - cmd.secure_display.roi_info.y_start = roi->y_start; - cmd.secure_display.roi_info.x_end = roi->x_end; - cmd.secure_display.roi_info.y_end = roi->y_end; + cmd.secure_display.roi_info.x_start = rect->x; + cmd.secure_display.roi_info.y_start = rect->y; + cmd.secure_display.roi_info.x_end = rect->x + rect->width; + cmd.secure_display.roi_info.y_end = rect->y + rect->height; } dc_dmub_srv_cmd_queue(dmub_srv, &cmd); @@ -518,17 +518,17 @@ dc_stream_forward_dmub_crc_window(struct dc_dmub_srv *dmub_srv, static inline void dc_stream_forward_dmcu_crc_window(struct dmcu *dmcu, - struct crc_region *roi, struct otg_phy_mux *mux_mapping, bool is_stop) + struct rect *rect, struct otg_phy_mux *mux_mapping, bool is_stop) { if (is_stop) dmcu->funcs->stop_crc_win_update(dmcu, mux_mapping); else - dmcu->funcs->forward_crc_window(dmcu, roi, mux_mapping); + dmcu->funcs->forward_crc_window(dmcu, rect, mux_mapping); } bool dc_stream_forward_crc_window(struct dc *dc, - struct crc_region *roi, struct dc_stream_state *stream, bool is_stop) + struct rect *rect, struct dc_stream_state *stream, bool is_stop) { struct dmcu *dmcu; struct dc_dmub_srv *dmub_srv; @@ -554,10 +554,10 @@ dc_stream_forward_crc_window(struct dc *dc, /* forward to dmub */ if (dmub_srv) - dc_stream_forward_dmub_crc_window(dmub_srv, roi, &mux_mapping, is_stop); + dc_stream_forward_dmub_crc_window(dmub_srv, rect, &mux_mapping, is_stop); /* forward to dmcu */ else if (dmcu && dmcu->funcs->is_dmcu_initialized(dmcu)) - dc_stream_forward_dmcu_crc_window(dmcu, roi, &mux_mapping, is_stop); + dc_stream_forward_dmcu_crc_window(dmcu, rect, &mux_mapping, is_stop); else return false; diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index 26f8f18e675c..4d30ae0ca721 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -522,7 +522,7 @@ bool dc_stream_get_crtc_position(struct dc *dc, #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) bool dc_stream_forward_crc_window(struct dc *dc, - struct crc_region *roi, + struct rect *rect, struct dc_stream_state *stream, bool is_stop); #endif diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index 27dd4304ce69..dc78e2404b48 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -994,13 +994,6 @@ struct display_endpoint_id { }; #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) -struct crc_region { - uint16_t x_start; - uint16_t y_start; - uint16_t x_end; - uint16_t y_end; -}; - struct otg_phy_mux { uint8_t phy_output_num; uint8_t otg_output_num; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c index fbb19e253f50..d3cc5ec46956 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c @@ -927,19 +927,20 @@ static bool dcn10_recv_edid_cea_ack(struct dmcu *dmcu, int *offset) #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) static void dcn10_forward_crc_window(struct dmcu *dmcu, - struct crc_region *crc_win, + struct rect *rect, struct otg_phy_mux *mux_mapping) { struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu); unsigned int dmcu_max_retry_on_wait_reg_ready = 801; unsigned int dmcu_wait_reg_ready_interval = 100; unsigned int crc_start = 0, crc_end = 0, otg_phy_mux = 0; + int x_start, y_start, x_end, y_end; /* If microcontroller is not running, do nothing */ if (dmcu->dmcu_state != DMCU_RUNNING) return; - if (!crc_win) + if (!rect) return; /* waitDMCUReadyForCmd */ @@ -947,9 +948,14 @@ static void dcn10_forward_crc_window(struct dmcu *dmcu, dmcu_wait_reg_ready_interval, dmcu_max_retry_on_wait_reg_ready); + x_start = rect->x; + y_start = rect->y; + x_end = x_start + rect->width; + y_end = y_start + rect->height; + /* build up nitification data */ - crc_start = (((unsigned int) crc_win->x_start) << 16) | crc_win->y_start; - crc_end = (((unsigned int) crc_win->x_end) << 16) | crc_win->y_end; + crc_start = (((unsigned int) x_start) << 16) | y_start; + crc_end = (((unsigned int) x_end) << 16) | y_end; otg_phy_mux = (((unsigned int) mux_mapping->otg_output_num) << 16) | mux_mapping->phy_output_num; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h index 9a2432608ddf..de3113ecbc77 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h @@ -86,7 +86,7 @@ struct dmcu_funcs { bool (*recv_edid_cea_ack)(struct dmcu *dmcu, int *offset); #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) void (*forward_crc_window)(struct dmcu *dmcu, - struct crc_region *crc_win, + struct rect *rect, struct otg_phy_mux *mux_mapping); void (*stop_crc_win_update)(struct dmcu *dmcu, struct otg_phy_mux *mux_mapping); -- cgit From f7f697403f2067ddbeff3344a4c2d20ff44ace79 Mon Sep 17 00:00:00 2001 From: Jun Lei Date: Thu, 20 Oct 2022 11:46:44 -0400 Subject: drm/amd/display: Limit dcn32 to 1950Mhz display clock [why] Hardware team recommends we limit dispclock to 1950Mhz for all DCN3.2.x [how] Limit to 1950 when initializing clocks. Tested-by: Mark Broadworth Reviewed-by: Alvin Lee Acked-by: Rodrigo Siqueira Signed-off-by: Jun Lei Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c index 1c612ccf1944..fd0313468fdb 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c @@ -157,6 +157,7 @@ void dcn32_init_clocks(struct clk_mgr *clk_mgr_base) struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); unsigned int num_levels; struct clk_limit_num_entries *num_entries_per_clk = &clk_mgr_base->bw_params->clk_table.num_entries_per_clk; + unsigned int i; memset(&(clk_mgr_base->clks), 0, sizeof(struct dc_clocks)); clk_mgr_base->clks.p_state_change_support = true; @@ -205,18 +206,17 @@ void dcn32_init_clocks(struct clk_mgr *clk_mgr_base) clk_mgr->dpm_present = true; if (clk_mgr_base->ctx->dc->debug.min_disp_clk_khz) { - unsigned int i; - for (i = 0; i < num_levels; i++) if (clk_mgr_base->bw_params->clk_table.entries[i].dispclk_mhz < khz_to_mhz_ceil(clk_mgr_base->ctx->dc->debug.min_disp_clk_khz)) clk_mgr_base->bw_params->clk_table.entries[i].dispclk_mhz = khz_to_mhz_ceil(clk_mgr_base->ctx->dc->debug.min_disp_clk_khz); } + for (i = 0; i < num_levels; i++) + if (clk_mgr_base->bw_params->clk_table.entries[i].dispclk_mhz > 1950) + clk_mgr_base->bw_params->clk_table.entries[i].dispclk_mhz = 1950; if (clk_mgr_base->ctx->dc->debug.min_dpp_clk_khz) { - unsigned int i; - for (i = 0; i < num_levels; i++) if (clk_mgr_base->bw_params->clk_table.entries[i].dppclk_mhz < khz_to_mhz_ceil(clk_mgr_base->ctx->dc->debug.min_dpp_clk_khz)) -- cgit From 1fb695d9e67d86c28f888b22d246c4333afa8a71 Mon Sep 17 00:00:00 2001 From: Anthony Koo Date: Thu, 20 Oct 2022 11:46:45 -0400 Subject: drm/amd/display: Document part of the DMUB cmd Add a simple documentation in the dmub_cmd. Tested-by: Mark Broadworth Reviewed-by: Aric Cyr Acked-by: Rodrigo Siqueira Signed-off-by: Anthony Koo Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index dc7c4d74cb5d..bc9344af1995 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -729,6 +729,7 @@ enum dmub_cmd_type { /** * Command type used for all VBIOS interface commands. */ + /** * Command type used for all SECURE_DISPLAY commands. */ @@ -3147,14 +3148,23 @@ struct dmub_rb_cmd_get_usbc_cable_id { } data; }; +/** + * Command type of a DMUB_CMD__SECURE_DISPLAY command + */ enum dmub_cmd_secure_display_type { - DMUB_CMD__SECURE_DISPLAY_TEST_CMD = 0, + DMUB_CMD__SECURE_DISPLAY_TEST_CMD = 0, /* test command to only check if inbox message works */ DMUB_CMD__SECURE_DISPLAY_CRC_STOP_UPDATE, DMUB_CMD__SECURE_DISPLAY_CRC_WIN_NOTIFY }; +/** + * Definition of a DMUB_CMD__SECURE_DISPLAY command + */ struct dmub_rb_cmd_secure_display { struct dmub_cmd_header header; + /** + * Data passed from driver to dmub firmware. + */ struct dmub_cmd_roi_info { uint16_t x_start; uint16_t x_end; @@ -3373,6 +3383,7 @@ union dmub_rb_cmd { * Definition of a DMUB_CMD__SECURE_DISPLAY command. */ struct dmub_rb_cmd_secure_display secure_display; + /** * Definition of a DMUB_CMD__DPIA_HPD_INT_ENABLE command. */ -- cgit From 5384d0e2b0e6afc717a523420a4b30e96dc9a99b Mon Sep 17 00:00:00 2001 From: Aric Cyr Date: Thu, 20 Oct 2022 11:46:46 -0400 Subject: drm/amd/display: 3.2.208 DC version 3.2.208 brings along the following: * Add more kernel doc * Enable secure display on DCN21 * Limit dcn32 to 1950Mhz display clock * PSR code refactor * Rework audio stream sequence * Generic bug fixes Tested-by: Mark Broadworth Acked-by: Rodrigo Siqueira Signed-off-by: Aric Cyr Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index e4e41f2e5054..3450aca538b5 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -47,7 +47,7 @@ struct aux_payload; struct set_config_cmd_payload; struct dmub_notification; -#define DC_VER "3.2.207" +#define DC_VER "3.2.208" #define MAX_SURFACES 3 #define MAX_PLANES 6 -- cgit From 4fd8575dc59c2e725c38f55f8167be9df1040ef9 Mon Sep 17 00:00:00 2001 From: Dillon Varone Date: Thu, 20 Oct 2022 11:46:47 -0400 Subject: drm/amd/display: Update latencies on DCN321 Update DF related latencies based on new measurements. Tested-by: Mark Broadworth Reviewed-by: Jun Lei Acked-by: Rodrigo Siqueira Signed-off-by: Dillon Varone Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c index dd90f241e906..7352f7514410 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c @@ -119,15 +119,15 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_21_soc = { }, }, .num_states = 1, - .sr_exit_time_us = 12.36, - .sr_enter_plus_exit_time_us = 16.72, + .sr_exit_time_us = 19.95, + .sr_enter_plus_exit_time_us = 24.36, .sr_exit_z8_time_us = 285.0, .sr_enter_plus_exit_z8_time_us = 320, .writeback_latency_us = 12.0, .round_trip_ping_latency_dcfclk_cycles = 263, - .urgent_latency_pixel_data_only_us = 4.0, - .urgent_latency_pixel_mixed_with_vm_data_us = 4.0, - .urgent_latency_vm_data_only_us = 4.0, + .urgent_latency_pixel_data_only_us = 9.35, + .urgent_latency_pixel_mixed_with_vm_data_us = 9.35, + .urgent_latency_vm_data_only_us = 9.35, .fclk_change_latency_us = 20, .usr_retraining_latency_us = 2, .smn_latency_us = 2, -- cgit From 33151fb787692edf8275120435c8cc41bfe0cf63 Mon Sep 17 00:00:00 2001 From: Dillon Varone Date: Thu, 20 Oct 2022 11:46:48 -0400 Subject: drm/amd/display: Set memclk levels to be at least 1 for dcn32 [Why] Cannot report 0 memclk levels even when SMU does not provide any. [How] When memclk levels reported by SMU is 0, set levels to 1. Tested-by: Mark Broadworth Reviewed-by: Martin Leung Acked-by: Rodrigo Siqueira Signed-off-by: Dillon Varone Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c index fd0313468fdb..6f77d8e538ab 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c @@ -669,6 +669,9 @@ static void dcn32_get_memclk_states_from_smu(struct clk_mgr *clk_mgr_base) &clk_mgr_base->bw_params->clk_table.entries[0].memclk_mhz, &num_entries_per_clk->num_memclk_levels); + /* memclk must have at least one level */ + num_entries_per_clk->num_memclk_levels = num_entries_per_clk->num_memclk_levels ? num_entries_per_clk->num_memclk_levels : 1; + dcn32_init_single_clock(clk_mgr, PPCLK_FCLK, &clk_mgr_base->bw_params->clk_table.entries[0].fclk_mhz, &num_entries_per_clk->num_fclk_levels); -- cgit From 3442f4e0e55555d14b099c17382453fdfd2508d5 Mon Sep 17 00:00:00 2001 From: Alvin Lee Date: Thu, 20 Oct 2022 11:46:49 -0400 Subject: drm/amd/display: Remove optimization for VRR updates Optimization caused unexpected regression, so remove for now. Tested-by: Mark Broadworth Reviewed-by: Aric Cyr Acked-by: Rodrigo Siqueira Signed-off-by: Alvin Lee Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 20c16ca935f7..f6776ccf7a0e 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -401,9 +401,6 @@ bool dc_stream_adjust_vmin_vmax(struct dc *dc, { int i; - if (memcmp(adjust, &stream->adjust, sizeof(struct dc_crtc_timing_adjust)) == 0) - return true; - stream->adjust.v_total_max = adjust->v_total_max; stream->adjust.v_total_mid = adjust->v_total_mid; stream->adjust.v_total_mid_frame_num = adjust->v_total_mid_frame_num; -- cgit From 35fe1915eebde4546cea5fd4e86e76f47d7b5dae Mon Sep 17 00:00:00 2001 From: Bhawanpreet Lakha Date: Thu, 20 Oct 2022 11:46:50 -0400 Subject: drm/amd/display: Fix HDCP 1.X 1A-04 failing [Why] On some linux based OS, the hotplug->HDCP start takes longer than 4seconds (by ~100ms) This is due to the HDCP delay (3 sec) so we only have 1 second to hotplug->stream enablement, which is not enough for certain OS configs. [How] Change the Delay to 0 seconds. From testing it seems like 0 Seconds can pass 1.x and 2.x compliances Tested-by: Mark Broadworth Reviewed-by: Aurabindo Pillai Acked-by: Rodrigo Siqueira Signed-off-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c index 6202e31c7e3a..a7fd98f57f94 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c @@ -495,7 +495,7 @@ static void update_config(void *handle, struct cp_psp_stream_config *config) link->dp.mst_enabled = config->mst_enabled; link->dp.usb4_enabled = config->usb4_enabled; display->adjust.disable = MOD_HDCP_DISPLAY_DISABLE_AUTHENTICATION; - link->adjust.auth_delay = 3; + link->adjust.auth_delay = 0; link->adjust.hdcp1.disable = 0; conn_state = aconnector->base.state; -- cgit From 6894534b56059f68a96a3fcf357e15671de0d24e Mon Sep 17 00:00:00 2001 From: Alvin Lee Date: Thu, 20 Oct 2022 11:46:51 -0400 Subject: drm/amd/display: Enable timing sync on DCN32 Missed enabling timing sync on DCN32 because DCN32 has a different DML param. Tested-by: Mark Broadworth Reviewed-by: Martin Leung Reviewed-by: Jun Lei Acked-by: Rodrigo Siqueira Signed-off-by: Alvin Lee Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c index ec2eae99b892..602e885ed52c 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c @@ -1228,6 +1228,7 @@ int dcn20_populate_dml_pipes_from_context( pipes[pipe_cnt].pipe.src.dcc = false; pipes[pipe_cnt].pipe.src.dcc_rate = 1; pipes[pipe_cnt].pipe.dest.synchronized_vblank_all_planes = synchronized_vblank; + pipes[pipe_cnt].pipe.dest.synchronize_timings = synchronized_vblank; pipes[pipe_cnt].pipe.dest.hblank_start = timing->h_total - timing->h_front_porch; pipes[pipe_cnt].pipe.dest.hblank_end = pipes[pipe_cnt].pipe.dest.hblank_start - timing->h_addressable -- cgit From c3575dd201895aa5cbb50712e3879a650cde9eb4 Mon Sep 17 00:00:00 2001 From: Max Tseng Date: Thu, 20 Oct 2022 11:46:52 -0400 Subject: drm/amd/display: cursor update command incomplete Missing send cursor_rect width & Height into DMUB. PSR-SU would use these information. But missing these assignment in last refactor commit Tested-by: Mark Broadworth Reviewed-by: Anthony Koo Acked-by: Rodrigo Siqueira Signed-off-by: Max Tseng Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c index 4996d2810edb..938dba5249d4 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c @@ -623,6 +623,10 @@ void hubp2_cursor_set_attributes( hubp->att.size.bits.width = attr->width; hubp->att.size.bits.height = attr->height; hubp->att.cur_ctl.bits.mode = attr->color_format; + + hubp->cur_rect.w = attr->width; + hubp->cur_rect.h = attr->height; + hubp->att.cur_ctl.bits.pitch = hw_pitch; hubp->att.cur_ctl.bits.line_per_chunk = lpc; hubp->att.cur_ctl.bits.cur_2x_magnify = attr->attribute_flags.bits.ENABLE_MAGNIFICATION; -- cgit From 6bf20b9ba7863ecfa14f5b4171f719256b787b34 Mon Sep 17 00:00:00 2001 From: Aric Cyr Date: Thu, 20 Oct 2022 11:46:53 -0400 Subject: drm/amd/display: Fix SDR visual confirm Apply SDR visual confirm to RGB10 and FP16 formats as well when needed. Tested-by: Mark Broadworth Reviewed-by: Jun Lei Acked-by: Rodrigo Siqueira Signed-off-by: Aric Cyr Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c index 7c2e3b8dc26a..471078fc3900 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c @@ -366,6 +366,7 @@ void get_hdr_visual_confirm_color( struct tg_color *color) { uint32_t color_value = MAX_TG_COLOR_VALUE; + bool is_sdr = false; /* Determine the overscan color based on the top-most (desktop) plane's context */ struct pipe_ctx *top_pipe_ctx = pipe_ctx; @@ -382,7 +383,8 @@ void get_hdr_visual_confirm_color( /* FreeSync 2 ARGB2101010 - set border color to pink */ color->color_r_cr = color_value; color->color_b_cb = color_value; - } + } else + is_sdr = true; break; case PIXEL_FORMAT_FP16: if (top_pipe_ctx->stream->out_transfer_func->tf == TRANSFER_FUNCTION_PQ) { @@ -391,14 +393,19 @@ void get_hdr_visual_confirm_color( } else if (top_pipe_ctx->stream->out_transfer_func->tf == TRANSFER_FUNCTION_GAMMA22) { /* FreeSync 2 HDR - set border color to green */ color->color_g_y = color_value; - } + } else + is_sdr = true; break; default: + is_sdr = true; + break; + } + + if (is_sdr) { /* SDR - set border color to Gray */ color->color_r_cr = color_value/2; color->color_b_cb = color_value/2; color->color_g_y = color_value/2; - break; } } -- cgit From 203ccaf586446b578909de1b763278033fb74b51 Mon Sep 17 00:00:00 2001 From: Haiyi Zhou Date: Thu, 20 Oct 2022 11:46:54 -0400 Subject: drm/amd/display: wait for vblank during pipe programming [WHY] Skipping vblank during global sync update request can result in underflow on certain displays. [HOW] Roll back to the previous behavior where DC waits for vblank during pipe programming. Fixes: 5d3e14421410 ("drm/amd/display: do not wait for vblank during pipe programming") Tested-by: Mark Broadworth Reviewed-by: Martin Leung Acked-by: Rodrigo Siqueira Signed-off-by: Haiyi Zhou Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c index 1ac0ed5be605..feff834d5410 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c @@ -1640,10 +1640,8 @@ static void dcn20_program_pipe( pipe_ctx->pipe_dlg_param.vupdate_width); if (pipe_ctx->stream->mall_stream_config.type != SUBVP_PHANTOM) { - pipe_ctx->stream_res.tg->funcs->wait_for_state( - pipe_ctx->stream_res.tg, CRTC_STATE_VBLANK); - pipe_ctx->stream_res.tg->funcs->wait_for_state( - pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE); + pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VBLANK); + pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE); } pipe_ctx->stream_res.tg->funcs->set_vtg_params( -- cgit From 1e8fd864afdc7a52df375e888a03b8472fc24f5d Mon Sep 17 00:00:00 2001 From: zhikzhai Date: Thu, 20 Oct 2022 11:46:55 -0400 Subject: drm/amd/display: skip commit minimal transition state [WHY] Now dynamic ODM will now be disabled when MPO is required safe transitions to avoid underflow, but we are triggering the way of minimal transition too often. Commit state of dc with no check will do pipeline setup which may re-initialize the component with no need such as audio. [HOW] Just do the minimal transition when all of pipes are in use, otherwise return true to skip. Tested-by: Mark Broadworth Reviewed-by: Dillon Varone Acked-by: Rodrigo Siqueira Signed-off-by: zhikzhai Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index f6776ccf7a0e..945b5210fba4 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -3738,10 +3738,32 @@ static bool commit_minimal_transition_state(struct dc *dc, bool temp_subvp_policy; enum dc_status ret = DC_ERROR_UNEXPECTED; unsigned int i, j; + unsigned int pipe_in_use = 0; if (!transition_context) return false; + /* check current pipes in use*/ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &transition_base_context->res_ctx.pipe_ctx[i]; + + if (pipe->plane_state) + pipe_in_use++; + } + + /* When the OS add a new surface if we have been used all of pipes with odm combine + * and mpc split feature, it need use commit_minimal_transition_state to transition safely. + * After OS exit MPO, it will back to use odm and mpc split with all of pipes, we need + * call it again. Otherwise return true to skip. + * + * Reduce the scenarios to use dc_commit_state_no_check in the stage of flip. Especially + * enter/exit MPO when DCN still have enough resources. + */ + if (pipe_in_use != dc->res_pool->pipe_count) { + dc_release_state(transition_context); + return true; + } + if (!dc->config.is_vmin_only_asic) { tmp_mpc_policy = dc->debug.pipe_split_policy; dc->debug.pipe_split_policy = MPC_SPLIT_AVOID; -- cgit From b1a98cf89a695d36c414653634ea7ba91b6e701f Mon Sep 17 00:00:00 2001 From: Ma Hanghong Date: Thu, 20 Oct 2022 11:46:56 -0400 Subject: drm/amd/display: Wrong colorimetry workaround [Why] For FreeSync HDR, native color space flag in AMD VSIF(BT.709) should be used when intepreting content and color space flag in VSC or AVI infoFrame should be ignored. However, it turned out some userspace application still use color flag in VSC or AVI infoFrame which is incorrect. [How] Transfer function is used when building the VSC and AVI infoFrame. Set colorimetry to BT.709 when all the following match: 1. Pixel format is YCbCr; 2. In FreeSync 2 HDR, color is COLOR_SPACE_2020_YCBCR; 3. Transfer function is TRANSFER_FUNC_GAMMA_22; Tested-by: Mark Broadworth Reviewed-by: Krunoslav Kovac Acked-by: Rodrigo Siqueira Signed-off-by: Ma Hanghong Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 5 ++++- drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 6 ++++++ drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h | 3 ++- drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c | 6 +++++- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 72aede3fcf9b..d14e57b19066 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -5697,6 +5697,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, bool scale = dm_state ? (dm_state->scaling != RMX_OFF) : false; int mode_refresh; int preferred_refresh = 0; + enum color_transfer_func tf = TRANSFER_FUNC_UNKNOWN; #if defined(CONFIG_DRM_AMD_DC_DCN) struct dsc_dec_dpcd_caps dsc_caps; #endif @@ -5820,7 +5821,9 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, if (stream->link->dpcd_caps.dprx_feature.bits.VSC_SDP_COLORIMETRY_SUPPORTED) stream->use_vsc_sdp_for_colorimetry = true; } - mod_build_vsc_infopacket(stream, &stream->vsc_infopacket, stream->output_color_space); + if (stream->out_transfer_func->tf == TRANSFER_FUNCTION_GAMMA22) + tf = TRANSFER_FUNC_GAMMA_22; + mod_build_vsc_infopacket(stream, &stream->vsc_infopacket, stream->output_color_space, tf); aconnector->psr_skip_count = AMDGPU_DM_PSR_ENTRY_DELAY; } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index ba2d4347f722..d99f1c4b9584 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -3015,6 +3015,12 @@ static void set_avi_info_frame( hdmi_info.bits.C0_C1 = COLORIMETRY_EXTENDED; } + if (pixel_encoding && color_space == COLOR_SPACE_2020_YCBCR && + stream->out_transfer_func->tf == TRANSFER_FUNCTION_GAMMA22) { + hdmi_info.bits.EC0_EC2 = 0; + hdmi_info.bits.C0_C1 = COLORIMETRY_ITU709; + } + /* TODO: un-hardcode aspect ratio */ aspect = stream->timing.aspect_ratio; diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h b/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h index 1d8b746b02f2..edf5845f6a1f 100644 --- a/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h +++ b/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h @@ -35,7 +35,8 @@ struct mod_vrr_params; void mod_build_vsc_infopacket(const struct dc_stream_state *stream, struct dc_info_packet *info_packet, - enum dc_color_space cs); + enum dc_color_space cs, + enum color_transfer_func tf); void mod_build_hf_vsif_infopacket(const struct dc_stream_state *stream, struct dc_info_packet *info_packet); diff --git a/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c b/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c index 27ceba9d6d65..69691058ab89 100644 --- a/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c +++ b/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c @@ -132,7 +132,8 @@ enum ColorimetryYCCDP { void mod_build_vsc_infopacket(const struct dc_stream_state *stream, struct dc_info_packet *info_packet, - enum dc_color_space cs) + enum dc_color_space cs, + enum color_transfer_func tf) { unsigned int vsc_packet_revision = vsc_packet_undefined; unsigned int i; @@ -382,6 +383,9 @@ void mod_build_vsc_infopacket(const struct dc_stream_state *stream, colorimetryFormat = ColorimetryYCC_DP_AdobeYCC; else if (cs == COLOR_SPACE_2020_YCBCR) colorimetryFormat = ColorimetryYCC_DP_ITU2020YCbCr; + + if (cs == COLOR_SPACE_2020_YCBCR && tf == TRANSFER_FUNC_GAMMA_22) + colorimetryFormat = ColorimetryYCC_DP_ITU709; break; default: -- cgit From 1682bd1a6b5fb094e914d9b73b711821fd84dcbd Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira Date: Thu, 20 Oct 2022 11:46:57 -0400 Subject: drm/amd/display: Expand kernel doc for DC This commit adds extra documentation for elements related to FAMs. Tested-by: Mark Broadworth Reviewed-by: Aurabindo Pillai Acked-by: Rodrigo Siqueira Signed-off-by: Rodrigo Siqueira Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc.h | 19 +++++++++++++--- drivers/gpu/drm/amd/display/dc/dc_stream.h | 11 ++++++++++ drivers/gpu/drm/amd/display/dc/dml/dc_features.h | 7 ++++++ .../drm/amd/display/dc/dml/display_mode_enums.h | 25 ++++++++++++++++++++++ .../gpu/drm/amd/display/dc/dml/display_mode_vba.h | 9 ++++++++ drivers/gpu/drm/amd/display/dc/inc/core_types.h | 7 ++++++ drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h | 7 ++++++ 7 files changed, 82 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 3450aca538b5..44f8db160520 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -494,9 +494,12 @@ enum dcn_zstate_support_state { DCN_ZSTATE_SUPPORT_ALLOW_Z10_ONLY, DCN_ZSTATE_SUPPORT_DISALLOW, }; -/* - * For any clocks that may differ per pipe - * only the max is stored in this structure + +/** + * dc_clocks - DC pipe clocks + * + * For any clocks that may differ per pipe only the max is stored in this + * structure */ struct dc_clocks { int dispclk_khz; @@ -523,6 +526,16 @@ struct dc_clocks { bool prev_p_state_change_support; bool fclk_prev_p_state_change_support; int num_ways; + + /** + * @fw_based_mclk_switching + * + * DC has a mechanism that leverage the variable refresh rate to switch + * memory clock in cases that we have a large latency to achieve the + * memory clock change and a short vblank window. DC has some + * requirements to enable this feature, and this field describes if the + * system support or not such a feature. + */ bool fw_based_mclk_switching; bool fw_based_mclk_switching_shut_down; int prev_num_ways; diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index 4d30ae0ca721..f4dfd3a49b68 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -201,7 +201,18 @@ struct dc_stream_state { bool use_vsc_sdp_for_colorimetry; bool ignore_msa_timing_param; + /** + * @allow_freesync: + * + * It say if Freesync is enabled or not. + */ bool allow_freesync; + + /** + * @vrr_active_variable: + * + * It describes if VRR is in use. + */ bool vrr_active_variable; bool freesync_on_desktop; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dc_features.h b/drivers/gpu/drm/amd/display/dc/dml/dc_features.h index 74e86732e301..2cbdd75429ff 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dc_features.h +++ b/drivers/gpu/drm/amd/display/dc/dml/dc_features.h @@ -29,6 +29,13 @@ #define DC__PRESENT 1 #define DC__PRESENT__1 1 #define DC__NUM_DPP 4 + +/** + * @DC__VOLTAGE_STATES: + * + * Define the maximum amount of states supported by the ASIC. Every ASIC has a + * specific number of states; this macro defines the maximum number of states. + */ #define DC__VOLTAGE_STATES 20 #define DC__NUM_DPP__4 1 #define DC__NUM_DPP__0_PRESENT 1 diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_enums.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_enums.h index f394b3f3922a..0bffae95f3a2 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_enums.h +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_enums.h @@ -105,14 +105,39 @@ enum source_macro_tile_size { enum cursor_bpp { dm_cur_2bit = 0, dm_cur_32bit = 1, dm_cur_64bit = 2 }; + +/** + * @enum clock_change_support - It represents possible reasons to change the DRAM clock. + * + * DC may change the DRAM clock during its execution, and this enum tracks all + * the available methods. Note that every ASIC has their specific way to deal + * with these clock switch. + */ enum clock_change_support { + /** + * @dm_dram_clock_change_uninitialized: If you see this, we might have + * a code initialization issue + */ dm_dram_clock_change_uninitialized = 0, + + /** + * @dm_dram_clock_change_vactive: Support DRAM switch in VActive + */ dm_dram_clock_change_vactive, + + /** + * @dm_dram_clock_change_vblank: Support DRAM switch in VBlank + */ dm_dram_clock_change_vblank, + dm_dram_clock_change_vactive_w_mall_full_frame, dm_dram_clock_change_vactive_w_mall_sub_vp, dm_dram_clock_change_vblank_w_mall_full_frame, dm_dram_clock_change_vblank_w_mall_sub_vp, + + /** + * @dm_dram_clock_change_unsupported: Do not support DRAM switch + */ dm_dram_clock_change_unsupported }; diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h index 630f3395e90a..d46aa4817e70 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h @@ -419,6 +419,15 @@ struct vba_vars_st { double MinPixelChunkSizeBytes; unsigned int DCCMetaBufferSizeBytes; // Pipe/Plane Parameters + + /** @VoltageLevel: + * Every ASIC has a fixed number of DPM states, and some devices might + * have some particular voltage configuration that does not map + * directly to the DPM states. This field tells how many states the + * target device supports; even though this field combines the DPM and + * special SOC voltages, it mostly matches the total number of DPM + * states. + */ int VoltageLevel; double FabricClock; double DRAMSpeed; diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h index 9498105c98ab..295845d49cb9 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h @@ -115,6 +115,13 @@ struct resource_funcs { int vlevel); void (*update_soc_for_wm_a)( struct dc *dc, struct dc_state *context); + + /** + * @populate_dml_pipes - Populate pipe data struct + * + * Returns: + * Total of pipes available in the specific ASIC. + */ int (*populate_dml_pipes)( struct dc *dc, struct dc_state *context, diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h b/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h index cd2be729846b..a819f0f97c5f 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h @@ -35,6 +35,13 @@ ******************************************************************************/ #define MAX_AUDIOS 7 + +/** + * @MAX_PIPES: + * + * Every ASIC support a fixed number of pipes; MAX_PIPES defines a large number + * to be used inside loops and for determining array sizes. + */ #define MAX_PIPES 6 #define MAX_DIG_LINK_ENCODERS 7 #define MAX_DWB_PIPES 1 -- cgit From 61708a47e84bc458fae9fbc8a9070fb62a9bcf6d Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira Date: Thu, 20 Oct 2022 11:46:58 -0400 Subject: drm/amd/display: Add DEC/CRB basic doc Add a kernel-doc to the DE-Tile function hook. Tested-by: Mark Broadworth Reviewed-by: Aurabindo Pillai Acked-by: Rodrigo Siqueira Signed-off-by: Rodrigo Siqueira Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.c | 4 ++++ drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h | 15 +++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.c index 9fbb72369c10..a88a71460521 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.c @@ -41,6 +41,10 @@ #define FN(reg_name, field_name) \ hubbub2->shifts->field_name, hubbub2->masks->field_name +/** + * @DCN32_CRB_SEGMENT_SIZE_KB: Maximum Configurable Return Buffer size for + * DCN32 + */ #define DCN32_CRB_SEGMENT_SIZE_KB 64 static void dcn32_init_crb(struct hubbub *hubbub) diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h index e7571c6f5ead..58f758fcbce1 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h @@ -167,6 +167,21 @@ struct hubbub_funcs { void (*force_pstate_change_control)(struct hubbub *hubbub, bool force, bool allow); void (*init_watermarks)(struct hubbub *hubbub); + + /** + * @program_det_size: + * + * DE-Tile buffers (DET) is a memory that is used to convert the tiled + * data into linear, which the rest of the display can use to generate + * the graphics output. One of the main features of this component is + * that each pipe has a configurable DET buffer which means that when a + * pipe is not enabled, the device can assign the memory to other + * enabled pipes to try to be more efficient. + * + * DET logic is handled by dchubbub. Some ASICs provide a feature named + * Configurable Return Buffer (CRB) segments which can be allocated to + * compressed or detiled buffers. + */ void (*program_det_size)(struct hubbub *hubbub, int hubp_inst, unsigned det_buffer_size_in_kbyte); void (*program_compbuf_size)(struct hubbub *hubbub, unsigned compbuf_size_kb, bool safe_to_increase); void (*init_crb)(struct hubbub *hubbub); -- cgit From a6126e14cfb200ecb915c66bccbfc077c704c1fa Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira Date: Thu, 20 Oct 2022 11:46:59 -0400 Subject: drm/amd/display: Add basic ODM description Add kernel-doc to some of the ODM-related functions. Tested-by: Mark Broadworth Reviewed-by: Aurabindo Pillai Acked-by: Rodrigo Siqueira Signed-off-by: Rodrigo Siqueira Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c | 16 ++++++++++++++++ drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h | 3 +++ drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h | 5 +++++ 3 files changed, 24 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c index 8224b9bf01d1..d0199ec045cb 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c @@ -1454,6 +1454,22 @@ enum dc_status dcn20_remove_stream_from_ctx(struct dc *dc, struct dc_state *new_ return result; } +/** + * dcn20_split_stream_for_odm - Check if stream can be splited for ODM + * + * @dc: DC object with resource pool info required for pipe split + * @res_ctx: Persistent state of resources + * @prev_odm_pipe: Reference to the previous ODM pipe + * @next_odm_pipe: Reference to the next ODM pipe + * + * This function takes a logically active pipe and a logically free pipe and + * halves all the scaling parameters that need to be halved while populating + * the free pipe with the required resources and configuring the next/previous + * ODM pipe pointers. + * + * Return: + * Return true if split stream for ODM is possible, otherwise, return false. + */ bool dcn20_split_stream_for_odm( const struct dc *dc, struct resource_context *res_ctx, diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h index 6b3e6de374bd..42db4b7b79fd 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h @@ -243,6 +243,9 @@ struct stream_encoder_funcs { uint32_t hubp_requestor_id, enum dynamic_metadata_mode dmdata_mode); + /** + * @dp_set_odm_combine: Sets up DP stream encoder for ODM. + */ void (*dp_set_odm_combine)( struct stream_encoder *enc, bool odm_combine); diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h index 25a1df45b264..65f18f9dad34 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h @@ -301,6 +301,11 @@ struct timing_generator_funcs { void (*get_dsc_status)(struct timing_generator *optc, uint32_t *dsc_mode); void (*set_odm_bypass)(struct timing_generator *optc, const struct dc_crtc_timing *dc_crtc_timing); + + /** + * @set_odm_combine: Set up the ODM block to read from the correct + * OPP(s) and turn on/off ODM memory. + */ void (*set_odm_combine)(struct timing_generator *optc, int *opp_id, int opp_cnt, struct dc_crtc_timing *timing); void (*set_h_timing_div_manual_mode)(struct timing_generator *optc, bool manual_mode); -- cgit From fa0fc4fb09b4306ce77093987ee7b84ead697182 Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira Date: Thu, 20 Oct 2022 11:47:00 -0400 Subject: drm/amd/display: Add kernel doc to some of the dc fields Add kernel-doc to some important elements from DC struct that might help to understand DC sequence. Tested-by: Mark Broadworth Reviewed-by: Aurabindo Pillai Acked-by: Rodrigo Siqueira Signed-off-by: Rodrigo Siqueira Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 5 ++- drivers/gpu/drm/amd/display/dc/dc_link.h | 8 +++++ drivers/gpu/drm/amd/display/dc/inc/core_types.h | 38 +++++++++++++++++------ 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index d99f1c4b9584..7caf3139fabc 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -2562,9 +2562,12 @@ enum dc_status resource_map_pool_resources( /** * dc_resource_state_copy_construct_current() - Creates a new dc_state from existing state - * Is a shallow copy. Increments refcounts on existing streams and planes. + * * @dc: copy out of dc->current_state * @dst_ctx: copy into this + * + * This function makes a shallow copy of the current DC state and increments + * refcounts on existing streams and planes. */ void dc_resource_state_copy_construct_current( const struct dc *dc, diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h index 17f080f8af6c..edb4532eaa39 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_link.h +++ b/drivers/gpu/drm/amd/display/dc/dc_link.h @@ -166,6 +166,14 @@ struct dc_link { enum dc_irq_source irq_source_hpd_rx;/* aka DP Short Pulse */ bool is_hpd_filter_disabled; bool dp_ss_off; + + /** + * @link_state_valid: + * + * If there is no link and local sink, this variable should be set to + * false. Otherwise, it should be set to true; usually, the function + * core_link_enable_stream sets this field to true. + */ bool link_state_valid; bool aux_access_disabled; bool sync_lt_in_progress; diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h index 295845d49cb9..fe34cfde22a6 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h @@ -514,29 +514,47 @@ struct bw_context { union bw_output bw; struct display_mode_lib dml; }; + /** - * struct dc_state - The full description of a state requested by a user - * - * @streams: Stream properties - * @stream_status: The planes on a given stream - * @res_ctx: Persistent state of resources - * @bw_ctx: The output from bandwidth and watermark calculations and the DML - * @pp_display_cfg: PowerPlay clocks and settings - * @dcn_bw_vars: non-stack memory to support bandwidth calculations - * + * struct dc_state - The full description of a state requested by users */ struct dc_state { + /** + * @streams: Stream state properties + */ struct dc_stream_state *streams[MAX_PIPES]; + + /** + * @stream_status: Planes status on a given stream + */ struct dc_stream_status stream_status[MAX_PIPES]; + + /** + * @stream_count: Total of streams in use + */ uint8_t stream_count; uint8_t stream_mask; + /** + * @res_ctx: Persistent state of resources + */ struct resource_context res_ctx; + /** + * @bw_ctx: The output from bandwidth and watermark calculations and the DML + */ struct bw_context bw_ctx; - /* Note: these are big structures, do *not* put on stack! */ + /** + * @pp_display_cfg: PowerPlay clocks and settings + * Note: this is a big struct, do *not* put on stack! + */ struct dm_pp_display_configuration pp_display_cfg; + + /** + * @dcn_bw_vars: non-stack memory to support bandwidth calculations + * Note: this is a big struct, do *not* put on stack! + */ struct dcn_bw_internal_vars dcn_bw_vars; struct clk_mgr *clk_mgr; -- cgit From 6a0114e0e31cdf391b96ab347618baa9201c12ad Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira Date: Thu, 20 Oct 2022 11:47:01 -0400 Subject: drm/amd/display: Add kernel doc for commit sequence Add basic kernel-doc that describes some of the struct and functions that are part of the DC commit sequence.. Tested-by: Mark Broadworth Reviewed-by: Aurabindo Pillai Acked-by: Rodrigo Siqueira Signed-off-by: Rodrigo Siqueira Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 63 +++++++++++++++++++---- drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 11 ++++ drivers/gpu/drm/amd/display/dc/inc/core_types.h | 16 +++++- 3 files changed, 79 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 945b5210fba4..2858917a66be 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -1714,8 +1714,13 @@ void dc_z10_save_init(struct dc *dc) dc->hwss.z10_save_init(dc); } -/* - * Applies given context to HW and copy it into current context. +/** + * dc_commit_state_no_check - Apply context to the hardware + * + * @dc: DC object with the current status to be updated + * @context: New state that will become the current status at the end of this function + * + * Applies given context to the hardware and copy it into current context. * It's up to the user to release the src context afterwards. */ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *context) @@ -3651,10 +3656,24 @@ static void commit_planes_for_stream(struct dc *dc, } } -/* Determines if the incoming context requires a applying transition state with unnecessary - * pipe splitting and ODM disabled, due to hardware limitations. In a case where - * the OPP associated with an MPCC might change due to plane additions, this function +/** + * could_mpcc_tree_change_for_active_pipes - Check if an OPP associated with MPCC might change + * + * @dc: Used to get the current state status + * @stream: Target stream, which we want to remove the attached planes + * @surface_count: Number of surface update + * @is_plane_addition: [in] Fill out with true if it is a plane addition case + * + * DCN32x and newer support a feature named Dynamic ODM which can conflict with + * the MPO if used simultaneously in some specific configurations (e.g., + * 4k@144). This function checks if the incoming context requires applying a + * transition state with unnecessary pipe splitting and ODM disabled to + * circumvent our hardware limitations to prevent this edge case. If the OPP + * associated with an MPCC might change due to plane additions, this function * returns true. + * + * Return: + * Return true if OPP and MPCC might change, otherwise, return false. */ static bool could_mpcc_tree_change_for_active_pipes(struct dc *dc, struct dc_stream_state *stream, @@ -3729,6 +3748,24 @@ static bool could_mpcc_tree_change_for_active_pipes(struct dc *dc, return force_minimal_pipe_splitting; } +/** + * commit_minimal_transition_state - Create a transition pipe split state + * + * @dc: Used to get the current state status + * @transition_base_context: New transition state + * + * In some specific configurations, such as pipe split on multi-display with + * MPO and/or Dynamic ODM, removing a plane may cause unsupported pipe + * programming when moving to new planes. To mitigate those types of problems, + * this function adds a transition state that minimizes pipe usage before + * programming the new configuration. When adding a new plane, the current + * state requires the least pipes, so it is applied without splitting. When + * removing a plane, the new state requires the least pipes, so it is applied + * without splitting. + * + * Return: + * Return false if something is wrong in the transition state. + */ static bool commit_minimal_transition_state(struct dc *dc, struct dc_state *transition_base_context) { @@ -3742,6 +3779,10 @@ static bool commit_minimal_transition_state(struct dc *dc, if (!transition_context) return false; + /* Setup: + * Store the current ODM and MPC config in some temp variables to be + * restored after we commit the transition state. + */ /* check current pipes in use*/ for (i = 0; i < dc->res_pool->pipe_count; i++) { @@ -3777,7 +3818,7 @@ static bool commit_minimal_transition_state(struct dc *dc, dc_resource_state_copy_construct(transition_base_context, transition_context); - //commit minimal state + /* commit minimal state */ if (dc->res_pool->funcs->validate_bandwidth(dc, transition_context, false)) { for (i = 0; i < transition_context->stream_count; i++) { struct dc_stream_status *stream_status = &transition_context->stream_status[i]; @@ -3795,10 +3836,12 @@ static bool commit_minimal_transition_state(struct dc *dc, ret = dc_commit_state_no_check(dc, transition_context); } - /*always release as dc_commit_state_no_check retains in good case*/ + /* always release as dc_commit_state_no_check retains in good case */ dc_release_state(transition_context); - /*restore previous pipe split and odm policy*/ + /* TearDown: + * Restore original configuration for ODM and MPO. + */ if (!dc->config.is_vmin_only_asic) dc->debug.pipe_split_policy = tmp_mpc_policy; @@ -3806,12 +3849,12 @@ static bool commit_minimal_transition_state(struct dc *dc, dc->debug.force_disable_subvp = temp_subvp_policy; if (ret != DC_OK) { - /*this should never happen*/ + /* this should never happen */ BREAK_TO_DEBUGGER(); return false; } - /*force full surface update*/ + /* force full surface update */ for (i = 0; i < dc->current_state->stream_count; i++) { for (j = 0; j < dc->current_state->stream_status[i].plane_count; j++) { dc->current_state->stream_status[i].plane_states[j]->update_flags.raw = 0xFFFFFFFF; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index 7caf3139fabc..da164685547d 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -1768,6 +1768,17 @@ bool dc_remove_plane_from_context( return true; } +/** + * dc_rem_all_planes_for_stream - Remove planes attached to the target stream. + * + * @dc: Current dc state. + * @stream: Target stream, which we want to remove the attached plans. + * @context: New context. + * + * Return: + * Return true if DC was able to remove all planes from the target + * stream, otherwise, return false. + */ bool dc_rem_all_planes_for_stream( const struct dc *dc, struct dc_stream_state *stream, diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h index fe34cfde22a6..85495ef026f5 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h @@ -420,7 +420,10 @@ struct pipe_ctx { struct pll_settings pll_settings; - /* link config records software decision for what link config should be + /** + * @link_config: + * + * link config records software decision for what link config should be * enabled given current link capability and stream during hw resource * mapping. This is to decouple the dependency on link capability during * dc commit or update. @@ -542,6 +545,10 @@ struct dc_state { /** * @bw_ctx: The output from bandwidth and watermark calculations and the DML + * + * Each context must have its own instance of VBA, and in order to + * initialize and obtain IP and SOC, the base DML instance from DC is + * initially copied into every context. */ struct bw_context bw_ctx; @@ -559,6 +566,13 @@ struct dc_state { struct clk_mgr *clk_mgr; + /** + * @refcount: refcount reference + * + * Notice that dc_state is used around the code to capture the current + * context, so we need to pass it everywhere. That's why we want to use + * kref in this struct. + */ struct kref refcount; struct { -- cgit From 887e8cec55f20c39e14e04eb5f8a013ba75312ce Mon Sep 17 00:00:00 2001 From: Yifan Zhang Date: Mon, 24 Oct 2022 12:47:47 +0800 Subject: drm/amdgpu: set fb_modifiers_not_supported in vkms This patch to fix the gdm3 start failure with virual display: /usr/libexec/gdm-x-session[1711]: (II) AMDGPU(0): Setting screen physical size to 270 x 203 /usr/libexec/gdm-x-session[1711]: (EE) AMDGPU(0): Failed to make import prime FD as pixmap: 22 /usr/libexec/gdm-x-session[1711]: (EE) AMDGPU(0): failed to set mode: Invalid argument /usr/libexec/gdm-x-session[1711]: (WW) AMDGPU(0): Failed to set mode on CRTC 0 /usr/libexec/gdm-x-session[1711]: (EE) AMDGPU(0): Failed to enable any CRTC gnome-shell[1840]: Running GNOME Shell (using mutter 42.2) as a X11 window and compositing manager /usr/libexec/gdm-x-session[1711]: (EE) AMDGPU(0): failed to set mode: Invalid argument vkms doesn't have modifiers support, set fb_modifiers_not_supported to bring the gdm back. Signed-off-by: Yifan Zhang Acked-by: Guchun Chen Reviewed-by: Tim Huang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c index f4b5301ea2a0..500a1dc4fe02 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c @@ -500,6 +500,8 @@ static int amdgpu_vkms_sw_init(void *handle) adev_to_drm(adev)->mode_config.fb_base = adev->gmc.aper_base; + adev_to_drm(adev)->mode_config.fb_modifiers_not_supported = true; + r = amdgpu_display_modeset_create_props(adev); if (r) return r; -- cgit From 9552b19edcf640103e4b6ad2ab0b46ae8d92b6be Mon Sep 17 00:00:00 2001 From: Aric Cyr Date: Thu, 20 Oct 2022 11:47:02 -0400 Subject: drm/amd/display: 3.2.209 DC version 3.2.209 brings along the following: * Improve color manipulation * Add corrections to DML and some flag configuration * Updates for DCN32x * Expand kernel-doc Tested-by: Mark Broadworth Acked-by: Rodrigo Siqueira Signed-off-by: Aric Cyr Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 44f8db160520..c43bafa289e6 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -47,7 +47,7 @@ struct aux_payload; struct set_config_cmd_payload; struct dmub_notification; -#define DC_VER "3.2.208" +#define DC_VER "3.2.209" #define MAX_SURFACES 3 #define MAX_PLANES 6 -- cgit From e366f36958f60c431a7430c8c421c9db0ec6738d Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira Date: Tue, 18 Oct 2022 16:27:59 -0400 Subject: drm/amd/display: Rework comments on dc file The file dc.c has multiple comments that do not follow the kernel-doc or are made in a distracting way. This commit alleviates part of this issue by reorganizing some comments inside the dc file. Signed-off-by: Rodrigo Siqueira Reviewed-by: Hamza Mahfooz Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 161 ++++++++++++------------------- drivers/gpu/drm/amd/display/dc/dc.h | 32 ++---- 2 files changed, 70 insertions(+), 123 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 2858917a66be..d446e6098948 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -135,9 +135,7 @@ static const char DC_BUILD_ID[] = "production-build"; * one or two (in the pipe-split case). */ -/******************************************************************************* - * Private functions - ******************************************************************************/ +/* Private functions */ static inline void elevate_update_type(enum surface_update_type *original, enum surface_update_type new) { @@ -421,18 +419,14 @@ bool dc_stream_adjust_vmin_vmax(struct dc *dc, } /** - ***************************************************************************** - * Function: dc_stream_get_last_vrr_vtotal + * dc_stream_get_last_used_drr_vtotal - dc_stream_get_last_vrr_vtotal * - * @brief - * Looks up the pipe context of dc_stream_state and gets the - * last VTOTAL used by DRR (Dynamic Refresh Rate) + * @dc: [in] dc reference + * @stream: [in] Initial dc stream state + * @adjust: [in] Updated parameters for vertical_total_min and * - * @param [in] dc: dc reference - * @param [in] stream: Initial dc stream state - * @param [in] adjust: Updated parameters for vertical_total_min and - * vertical_total_max - ***************************************************************************** + * Looks up the pipe context of dc_stream_state and gets the last VTOTAL used + * by DRR (Dynamic Refresh Rate) */ bool dc_stream_get_last_used_drr_vtotal(struct dc *dc, struct dc_stream_state *stream, @@ -1209,9 +1203,7 @@ static void wait_for_no_pipes_pending(struct dc *dc, struct dc_state *context) PERF_TRACE(); } -/******************************************************************************* - * Public functions - ******************************************************************************/ +/* Public functions */ struct dc *dc_create(const struct dc_init_data *init_params) { @@ -4552,21 +4544,17 @@ void dc_mclk_switch_using_fw_based_vblank_stretch_shut_down(struct dc *dc) dc->current_state->bw_ctx.bw.dcn.clk.fw_based_mclk_switching_shut_down = true; } -/* - ***************************************************************************** - * Function: dc_is_dmub_outbox_supported - +/** + * dc_is_dmub_outbox_supported - Check if DMUB firmware support outbox notification * - * @brief - * Checks whether DMUB FW supports outbox notifications, if supported - * DM should register outbox interrupt prior to actually enabling interrupts - * via dc_enable_dmub_outbox + * @dc: [in] dc structure * - * @param - * [in] dc: dc structure + * Checks whether DMUB FW supports outbox notifications, if supported DM + * should register outbox interrupt prior to actually enabling interrupts + * via dc_enable_dmub_outbox * - * @return - * True if DMUB FW supports outbox notifications, False otherwise - ***************************************************************************** + * Return: + * True if DMUB FW supports outbox notifications, False otherwise */ bool dc_is_dmub_outbox_supported(struct dc *dc) { @@ -4584,21 +4572,17 @@ bool dc_is_dmub_outbox_supported(struct dc *dc) return dc->debug.enable_dmub_aux_for_legacy_ddc; } -/* - ***************************************************************************** - * Function: dc_enable_dmub_notifications +/** + * dc_enable_dmub_notifications - Check if dmub fw supports outbox * - * @brief - * Calls dc_is_dmub_outbox_supported to check if dmub fw supports outbox - * notifications. All DMs shall switch to dc_is_dmub_outbox_supported. - * This API shall be removed after switching. + * @dc: [in] dc structure * - * @param - * [in] dc: dc structure + * Calls dc_is_dmub_outbox_supported to check if dmub fw supports outbox + * notifications. All DMs shall switch to dc_is_dmub_outbox_supported. This + * API shall be removed after switching. * - * @return - * True if DMUB FW supports outbox notifications, False otherwise - ***************************************************************************** + * Return: + * True if DMUB FW supports outbox notifications, False otherwise */ bool dc_enable_dmub_notifications(struct dc *dc) { @@ -4606,18 +4590,11 @@ bool dc_enable_dmub_notifications(struct dc *dc) } /** - ***************************************************************************** - * Function: dc_enable_dmub_outbox + * dc_enable_dmub_outbox - Enables DMUB unsolicited notification * - * @brief - * Enables DMUB unsolicited notifications to x86 via outbox + * dc: [in] dc structure * - * @param - * [in] dc: dc structure - * - * @return - * None - ***************************************************************************** + * Enables DMUB unsolicited notifications to x86 via outbox. */ void dc_enable_dmub_outbox(struct dc *dc) { @@ -4718,21 +4695,17 @@ uint8_t get_link_index_from_dpia_port_index(const struct dc *dc, } /** - ***************************************************************************** - * Function: dc_process_dmub_set_config_async + * dc_process_dmub_set_config_async - Submits set_config command * - * @brief - * Submits set_config command to dmub via inbox message + * @dc: [in] dc structure + * @link_index: [in] link_index: link index + * @payload: [in] aux payload + * @notify: [out] set_config immediate reply * - * @param - * [in] dc: dc structure - * [in] link_index: link index - * [in] payload: aux payload - * [out] notify: set_config immediate reply + * Submits set_config command to dmub via inbox message. * - * @return - * True if successful, False if failure - ***************************************************************************** + * Return: + * True if successful, False if failure */ bool dc_process_dmub_set_config_async(struct dc *dc, uint32_t link_index, @@ -4768,21 +4741,17 @@ bool dc_process_dmub_set_config_async(struct dc *dc, } /** - ***************************************************************************** - * Function: dc_process_dmub_set_mst_slots + * dc_process_dmub_set_mst_slots - Submits MST solt allocation * - * @brief - * Submits mst slot allocation command to dmub via inbox message + * @dc: [in] dc structure + * @link_index: [in] link index + * @mst_alloc_slots: [in] mst slots to be allotted + * @mst_slots_in_use: [out] mst slots in use returned in failure case * - * @param - * [in] dc: dc structure - * [in] link_index: link index - * [in] mst_alloc_slots: mst slots to be allotted - * [out] mst_slots_in_use: mst slots in use returned in failure case + * Submits mst slot allocation command to dmub via inbox message * - * @return - * DC_OK if successful, DC_ERROR if failure - ***************************************************************************** + * Return: + * DC_OK if successful, DC_ERROR if failure */ enum dc_status dc_process_dmub_set_mst_slots(const struct dc *dc, uint32_t link_index, @@ -4822,19 +4791,12 @@ enum dc_status dc_process_dmub_set_mst_slots(const struct dc *dc, } /** - ***************************************************************************** - * Function: dc_process_dmub_dpia_hpd_int_enable - * - * @brief - * Submits dpia hpd int enable command to dmub via inbox message + * dc_process_dmub_dpia_hpd_int_enable - Submits DPIA DPD interruption * - * @param - * [in] dc: dc structure - * [in] hpd_int_enable: 1 for hpd int enable, 0 to disable + * @dc [in]: dc structure + * @hpd_int_enable [in]: 1 for hpd int enable, 0 to disable * - * @return - * None - ***************************************************************************** + * Submits dpia hpd int enable command to dmub via inbox message */ void dc_process_dmub_dpia_hpd_int_enable(const struct dc *dc, uint32_t hpd_int_enable) @@ -4863,16 +4825,13 @@ void dc_disable_accelerated_mode(struct dc *dc) /** - ***************************************************************************** - * dc_notify_vsync_int_state() - notifies vsync enable/disable state + * dc_notify_vsync_int_state - notifies vsync enable/disable state * @dc: dc structure - * @stream: stream where vsync int state changed - * @enable: whether vsync is enabled or disabled + * @stream: stream where vsync int state changed + * @enable: whether vsync is enabled or disabled * - * Called when vsync is enabled/disabled - * Will notify DMUB to start/stop ABM interrupts after steady state is reached - * - ***************************************************************************** + * Called when vsync is enabled/disabled Will notify DMUB to start/stop ABM + * interrupts after steady state is reached. */ void dc_notify_vsync_int_state(struct dc *dc, struct dc_stream_state *stream, bool enable) { @@ -4914,14 +4873,18 @@ void dc_notify_vsync_int_state(struct dc *dc, struct dc_stream_state *stream, bo if (pipe->stream_res.abm && pipe->stream_res.abm->funcs->set_abm_pause) pipe->stream_res.abm->funcs->set_abm_pause(pipe->stream_res.abm, !enable, i, pipe->stream_res.tg->inst); } -/* - * dc_extended_blank_supported: Decide whether extended blank is supported + +/** + * dc_extended_blank_supported 0 Decide whether extended blank is supported * - * Extended blank is a freesync optimization feature to be enabled in the future. - * During the extra vblank period gained from freesync, we have the ability to enter z9/z10. + * @dc: [in] Current DC state * - * @param [in] dc: Current DC state - * @return: Indicate whether extended blank is supported (true or false) + * Extended blank is a freesync optimization feature to be enabled in the + * future. During the extra vblank period gained from freesync, we have the + * ability to enter z9/z10. + * + * Return: + * Indicate whether extended blank is supported (true or false) */ bool dc_extended_blank_supported(struct dc *dc) { diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index c43bafa289e6..2a6406440032 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -56,9 +56,7 @@ struct dmub_notification; #define MIN_VIEWPORT_SIZE 12 #define MAX_NUM_EDP 2 -/******************************************************************************* - * Display Core Interfaces - ******************************************************************************/ +/* Display Core Interfaces */ struct dc_versions { const char *dc_ver; struct dmcu_version dmcu_version; @@ -1000,9 +998,7 @@ void dc_init_callbacks(struct dc *dc, void dc_deinit_callbacks(struct dc *dc); void dc_destroy(struct dc **dc); -/******************************************************************************* - * Surface Interfaces - ******************************************************************************/ +/* Surface Interfaces */ enum { TRANSFER_FUNC_POINTS = 1025 @@ -1363,9 +1359,7 @@ struct dc_state *dc_copy_state(struct dc_state *src_ctx); void dc_retain_state(struct dc_state *context); void dc_release_state(struct dc_state *context); -/******************************************************************************* - * Link Interfaces - ******************************************************************************/ +/* Link Interfaces */ struct dpcd_caps { union dpcd_rev dpcd_rev; @@ -1467,9 +1461,7 @@ struct hdcp_caps { uint32_t dc_get_opp_for_plane(struct dc *dc, struct dc_plane_state *plane); -/******************************************************************************* - * Sink Interfaces - A sink corresponds to a display output device - ******************************************************************************/ +/* Sink Interfaces - A sink corresponds to a display output device */ struct dc_container_id { // 128bit GUID in binary form @@ -1552,9 +1544,7 @@ struct dc_cursor { }; -/******************************************************************************* - * Interrupt interfaces - ******************************************************************************/ +/* Interrupt interfaces */ enum dc_irq_source dc_interrupt_to_irq_source( struct dc *dc, uint32_t src_id, @@ -1566,9 +1556,7 @@ enum dc_irq_source dc_get_hpd_irq_source_at_index( void dc_notify_vsync_int_state(struct dc *dc, struct dc_stream_state *stream, bool enable); -/******************************************************************************* - * Power Interfaces - ******************************************************************************/ +/* Power Interfaces */ void dc_set_power_state( struct dc *dc, @@ -1641,14 +1629,10 @@ enum dc_status dc_process_dmub_set_mst_slots(const struct dc *dc, void dc_process_dmub_dpia_hpd_int_enable(const struct dc *dc, uint32_t hpd_int_enable); -/******************************************************************************* - * DSC Interfaces - ******************************************************************************/ +/* DSC Interfaces */ #include "dc_dsc.h" -/******************************************************************************* - * Disable acc mode Interfaces - ******************************************************************************/ +/* Disable acc mode Interfaces */ void dc_disable_accelerated_mode(struct dc *dc); #endif /* DC_INTERFACE_H_ */ -- cgit From 5468c36d628524effbb89a9503eb1a2318804759 Mon Sep 17 00:00:00 2001 From: Fangzhi Zuo Date: Thu, 20 Oct 2022 16:06:26 -0400 Subject: drm/amd/display: Filter Invalid 420 Modes for HDMI TMDS [Why] Invalidate unsupported 420 modes on HDMI TMDS. HDMI TMDS does not support ODM. Any modes that are horizontally wider than 4096, cannot be supported via TMDS. So they must be filtered out and should not pass validation. [How] Create fake plane for the new stream, and validate global state by going through dml validation routine. Tested-by: Mark Broadworth Acked-by: Rodrigo Siqueira Signed-off-by: Fangzhi Zuo Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 67 +++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index d14e57b19066..9f2bf3488a78 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -6156,6 +6156,70 @@ static void handle_edid_mgmt(struct amdgpu_dm_connector *aconnector) create_eml_sink(aconnector); } +static enum dc_status dm_validate_stream_and_context(struct dc *dc, + struct dc_stream_state *stream) +{ + enum dc_status dc_result = DC_ERROR_UNEXPECTED; + struct dc_plane_state *dc_plane_state = NULL; + struct dc_state *dc_state = NULL; + + if (!stream) + goto cleanup; + + dc_plane_state = dc_create_plane_state(dc); + if (!dc_plane_state) + goto cleanup; + + dc_state = dc_create_state(dc); + if (!dc_state) + goto cleanup; + + /* populate stream to plane */ + dc_plane_state->src_rect.height = stream->src.height; + dc_plane_state->src_rect.width = stream->src.width; + dc_plane_state->dst_rect.height = stream->src.height; + dc_plane_state->dst_rect.width = stream->src.width; + dc_plane_state->clip_rect.height = stream->src.height; + dc_plane_state->clip_rect.width = stream->src.width; + dc_plane_state->plane_size.surface_pitch = ((stream->src.width + 255) / 256) * 256; + dc_plane_state->plane_size.surface_size.height = stream->src.height; + dc_plane_state->plane_size.surface_size.width = stream->src.width; + dc_plane_state->plane_size.chroma_size.height = stream->src.height; + dc_plane_state->plane_size.chroma_size.width = stream->src.width; + dc_plane_state->tiling_info.gfx9.swizzle = DC_SW_UNKNOWN; + dc_plane_state->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB8888; + dc_plane_state->tiling_info.gfx9.swizzle = DC_SW_UNKNOWN; + dc_plane_state->rotation = ROTATION_ANGLE_0; + dc_plane_state->is_tiling_rotated = false; + dc_plane_state->tiling_info.gfx8.array_mode = DC_ARRAY_LINEAR_GENERAL; + + dc_result = dc_validate_stream(dc, stream); + if (dc_result == DC_OK) + dc_result = dc_validate_plane(dc, dc_plane_state); + + if (dc_result == DC_OK) + dc_result = dc_add_stream_to_ctx(dc, dc_state, stream); + + if (dc_result == DC_OK && !dc_add_plane_to_context( + dc, + stream, + dc_plane_state, + dc_state)) + dc_result = DC_FAIL_ATTACH_SURFACES; + + if (dc_result == DC_OK) + dc_result = dc_validate_global_state(dc, dc_state, true); + +cleanup: + if (dc_state) + dc_release_state(dc_state); + + if (dc_plane_state) + dc_plane_state_release(dc_plane_state); + + return dc_result; +} + struct dc_stream_state * create_validate_stream_for_sink(struct amdgpu_dm_connector *aconnector, const struct drm_display_mode *drm_mode, @@ -6182,6 +6246,9 @@ create_validate_stream_for_sink(struct amdgpu_dm_connector *aconnector, if (dc_result == DC_OK && stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) dc_result = dm_dp_mst_is_port_support_mode(aconnector, stream); + if (dc_result == DC_OK) + dc_result = dm_validate_stream_and_context(adev->dm.dc, stream); + if (dc_result != DC_OK) { DRM_DEBUG_KMS("Mode %dx%d (clk %d) failed DC validation with error %d (%s)\n", drm_mode->hdisplay, -- cgit From 3f1a02ebeeebe3b8937391646cead0752144f1cb Mon Sep 17 00:00:00 2001 From: Paulo Miguel Almeida Date: Tue, 25 Oct 2022 22:12:00 +1300 Subject: drm/amdkfd: remove unused kfd_pm4_headers_diq header file kfd_pm4_headers_diq.h header is a leftover from the old H/W debugger module support added on commit fbeb661bfa895dc ("drm/amdkfd: Add skeleton H/W debugger module support"). That implementation was removed after a while and the last file that included that header was removed on commit 5bdd3eb253544b1 ("drm/amdkfd: Remove unused old debugger implementation"). This patch removes the unused header file kfd_pm4_headers_diq.h Signed-off-by: Paulo Miguel Almeida Reviewed-by: Felix Kuehling Signed-off-by: Felix Kuehling Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_pm4_headers_diq.h | 291 ----------------------- 1 file changed, 291 deletions(-) delete mode 100644 drivers/gpu/drm/amd/amdkfd/kfd_pm4_headers_diq.h diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_pm4_headers_diq.h b/drivers/gpu/drm/amd/amdkfd/kfd_pm4_headers_diq.h deleted file mode 100644 index f9cd28690151..000000000000 --- a/drivers/gpu/drm/amd/amdkfd/kfd_pm4_headers_diq.h +++ /dev/null @@ -1,291 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR MIT */ -/* - * Copyright 2014-2022 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef KFD_PM4_HEADERS_DIQ_H_ -#define KFD_PM4_HEADERS_DIQ_H_ - -/*--------------------_INDIRECT_BUFFER-------------------- */ - -#ifndef _PM4__INDIRECT_BUFFER_DEFINED -#define _PM4__INDIRECT_BUFFER_DEFINED -enum _INDIRECT_BUFFER_cache_policy_enum { - cache_policy___indirect_buffer__lru = 0, - cache_policy___indirect_buffer__stream = 1, - cache_policy___indirect_buffer__bypass = 2 -}; - -enum { - IT_INDIRECT_BUFFER_PASID = 0x5C -}; - -struct pm4__indirect_buffer_pasid { - union { - union PM4_MES_TYPE_3_HEADER header; /* header */ - unsigned int ordinal1; - }; - - union { - struct { - unsigned int reserved1:2; - unsigned int ib_base_lo:30; - } bitfields2; - unsigned int ordinal2; - }; - - union { - struct { - unsigned int ib_base_hi:16; - unsigned int reserved2:16; - } bitfields3; - unsigned int ordinal3; - }; - - union { - unsigned int control; - unsigned int ordinal4; - }; - - union { - struct { - unsigned int pasid:10; - unsigned int reserved4:22; - } bitfields5; - unsigned int ordinal5; - }; - -}; - -#endif - -/*--------------------_RELEASE_MEM-------------------- */ - -#ifndef _PM4__RELEASE_MEM_DEFINED -#define _PM4__RELEASE_MEM_DEFINED -enum _RELEASE_MEM_event_index_enum { - event_index___release_mem__end_of_pipe = 5, - event_index___release_mem__shader_done = 6 -}; - -enum _RELEASE_MEM_cache_policy_enum { - cache_policy___release_mem__lru = 0, - cache_policy___release_mem__stream = 1, - cache_policy___release_mem__bypass = 2 -}; - -enum _RELEASE_MEM_dst_sel_enum { - dst_sel___release_mem__memory_controller = 0, - dst_sel___release_mem__tc_l2 = 1, - dst_sel___release_mem__queue_write_pointer_register = 2, - dst_sel___release_mem__queue_write_pointer_poll_mask_bit = 3 -}; - -enum _RELEASE_MEM_int_sel_enum { - int_sel___release_mem__none = 0, - int_sel___release_mem__send_interrupt_only = 1, - int_sel___release_mem__send_interrupt_after_write_confirm = 2, - int_sel___release_mem__send_data_after_write_confirm = 3 -}; - -enum _RELEASE_MEM_data_sel_enum { - data_sel___release_mem__none = 0, - data_sel___release_mem__send_32_bit_low = 1, - data_sel___release_mem__send_64_bit_data = 2, - data_sel___release_mem__send_gpu_clock_counter = 3, - data_sel___release_mem__send_cp_perfcounter_hi_lo = 4, - data_sel___release_mem__store_gds_data_to_memory = 5 -}; - -struct pm4__release_mem { - union { - union PM4_MES_TYPE_3_HEADER header; /*header */ - unsigned int ordinal1; - }; - - union { - struct { - unsigned int event_type:6; - unsigned int reserved1:2; - enum _RELEASE_MEM_event_index_enum event_index:4; - unsigned int tcl1_vol_action_ena:1; - unsigned int tc_vol_action_ena:1; - unsigned int reserved2:1; - unsigned int tc_wb_action_ena:1; - unsigned int tcl1_action_ena:1; - unsigned int tc_action_ena:1; - unsigned int reserved3:6; - unsigned int atc:1; - enum _RELEASE_MEM_cache_policy_enum cache_policy:2; - unsigned int reserved4:5; - } bitfields2; - unsigned int ordinal2; - }; - - union { - struct { - unsigned int reserved5:16; - enum _RELEASE_MEM_dst_sel_enum dst_sel:2; - unsigned int reserved6:6; - enum _RELEASE_MEM_int_sel_enum int_sel:3; - unsigned int reserved7:2; - enum _RELEASE_MEM_data_sel_enum data_sel:3; - } bitfields3; - unsigned int ordinal3; - }; - - union { - struct { - unsigned int reserved8:2; - unsigned int address_lo_32b:30; - } bitfields4; - struct { - unsigned int reserved9:3; - unsigned int address_lo_64b:29; - } bitfields5; - unsigned int ordinal4; - }; - - unsigned int address_hi; - - unsigned int data_lo; - - unsigned int data_hi; - -}; -#endif - - -/*--------------------_SET_CONFIG_REG-------------------- */ - -#ifndef _PM4__SET_CONFIG_REG_DEFINED -#define _PM4__SET_CONFIG_REG_DEFINED - -struct pm4__set_config_reg { - union { - union PM4_MES_TYPE_3_HEADER header; /*header */ - unsigned int ordinal1; - }; - - union { - struct { - unsigned int reg_offset:16; - unsigned int reserved1:7; - unsigned int vmid_shift:5; - unsigned int insert_vmid:1; - unsigned int reserved2:3; - } bitfields2; - unsigned int ordinal2; - }; - - unsigned int reg_data[1]; /*1..N of these fields */ - -}; -#endif - -/*--------------------_WAIT_REG_MEM-------------------- */ - -#ifndef _PM4__WAIT_REG_MEM_DEFINED -#define _PM4__WAIT_REG_MEM_DEFINED -enum _WAIT_REG_MEM_function_enum { - function___wait_reg_mem__always_pass = 0, - function___wait_reg_mem__less_than_ref_value = 1, - function___wait_reg_mem__less_than_equal_to_the_ref_value = 2, - function___wait_reg_mem__equal_to_the_reference_value = 3, - function___wait_reg_mem__not_equal_reference_value = 4, - function___wait_reg_mem__greater_than_or_equal_reference_value = 5, - function___wait_reg_mem__greater_than_reference_value = 6, - function___wait_reg_mem__reserved = 7 -}; - -enum _WAIT_REG_MEM_mem_space_enum { - mem_space___wait_reg_mem__register_space = 0, - mem_space___wait_reg_mem__memory_space = 1 -}; - -enum _WAIT_REG_MEM_operation_enum { - operation___wait_reg_mem__wait_reg_mem = 0, - operation___wait_reg_mem__wr_wait_wr_reg = 1 -}; - -struct pm4__wait_reg_mem { - union { - union PM4_MES_TYPE_3_HEADER header; /*header */ - unsigned int ordinal1; - }; - - union { - struct { - enum _WAIT_REG_MEM_function_enum function:3; - unsigned int reserved1:1; - enum _WAIT_REG_MEM_mem_space_enum mem_space:2; - enum _WAIT_REG_MEM_operation_enum operation:2; - unsigned int reserved2:24; - } bitfields2; - unsigned int ordinal2; - }; - - union { - struct { - unsigned int reserved3:2; - unsigned int memory_poll_addr_lo:30; - } bitfields3; - struct { - unsigned int register_poll_addr:16; - unsigned int reserved4:16; - } bitfields4; - struct { - unsigned int register_write_addr:16; - unsigned int reserved5:16; - } bitfields5; - unsigned int ordinal3; - }; - - union { - struct { - unsigned int poll_address_hi:16; - unsigned int reserved6:16; - } bitfields6; - struct { - unsigned int register_write_addr:16; - unsigned int reserved7:16; - } bitfields7; - unsigned int ordinal4; - }; - - unsigned int reference; - - unsigned int mask; - - union { - struct { - unsigned int poll_interval:16; - unsigned int reserved8:16; - } bitfields8; - unsigned int ordinal7; - }; - -}; -#endif - - -#endif /* KFD_PM4_HEADERS_DIQ_H_ */ -- cgit From 2513574853f388008b81a900d56c2f75e7f35be2 Mon Sep 17 00:00:00 2001 From: Paulo Miguel Almeida Date: Tue, 25 Oct 2022 21:20:19 +1300 Subject: drm/amdkfd: remove unused struct cdit_header struct cdit_header was never used across any of the amd drivers nor this is exposed to UAPI so it can be removed. This patch removes struct cdit_header and refactor code accordingly Signed-off-by: Paulo Miguel Almeida Reviewed-by: Felix Kuehling Signed-off-by: Felix Kuehling Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_crat.h | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.h b/drivers/gpu/drm/amd/amdkfd/kfd_crat.h index 482ba84a728d..22893ff7b9a1 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.h @@ -29,11 +29,10 @@ #pragma pack(1) /* - * 4CC signature values for the CRAT and CDIT ACPI tables + * 4CC signature value for the CRAT ACPI table */ #define CRAT_SIGNATURE "CRAT" -#define CDIT_SIGNATURE "CDIT" /* * Component Resource Association Table (CRAT) @@ -292,27 +291,6 @@ struct crat_subtype_generic { uint32_t flags; }; -/* - * Component Locality Distance Information Table (CDIT) - */ -#define CDIT_OEMID_LENGTH 6 -#define CDIT_OEMTABLEID_LENGTH 8 - -struct cdit_header { - uint32_t signature; - uint32_t length; - uint8_t revision; - uint8_t checksum; - uint8_t oem_id[CDIT_OEMID_LENGTH]; - uint8_t oem_table_id[CDIT_OEMTABLEID_LENGTH]; - uint32_t oem_revision; - uint32_t creator_id; - uint32_t creator_revision; - uint32_t total_entries; - uint16_t num_domains; - uint8_t entry[1]; -}; - #pragma pack() struct kfd_dev; -- cgit From cbe4d43ea5e903ae3e8555cc39047b0ed027738a Mon Sep 17 00:00:00 2001 From: Tao Zhou Date: Mon, 17 Oct 2022 18:22:13 +0800 Subject: drm/amdgpu: add RAS page retirement functions for MCA Define page retirement functions for MCA platform. v2: remove page retirement handling from MCA poison handler, let MCA notifier do page retirement. v3: remove specific poison handler for MCA to simplify code. Signed-off-by: Tao Zhou Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c | 53 +++++++++++++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h | 2 ++ 2 files changed, 55 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c index aad3c8b4c810..3c83129f4090 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c @@ -22,6 +22,59 @@ */ #include "amdgpu.h" +#include "umc_v6_7.h" + +static int amdgpu_umc_convert_error_address(struct amdgpu_device *adev, + struct ras_err_data *err_data, uint64_t err_addr, + uint32_t ch_inst, uint32_t umc_inst) +{ + switch (adev->ip_versions[UMC_HWIP][0]) { + case IP_VERSION(6, 7, 0): + umc_v6_7_convert_error_address(adev, + err_data, err_addr, ch_inst, umc_inst); + break; + default: + dev_warn(adev->dev, + "UMC address to Physical address translation is not supported\n"); + return AMDGPU_RAS_FAIL; + } + + return AMDGPU_RAS_SUCCESS; +} + +int amdgpu_umc_page_retirement_mca(struct amdgpu_device *adev, + uint64_t err_addr, uint32_t ch_inst, uint32_t umc_inst) +{ + struct ras_err_data err_data = {0, 0, 0, NULL}; + int ret = AMDGPU_RAS_FAIL; + + err_data.err_addr = + kcalloc(adev->umc.max_ras_err_cnt_per_query, + sizeof(struct eeprom_table_record), GFP_KERNEL); + if (!err_data.err_addr) { + dev_warn(adev->dev, + "Failed to alloc memory for umc error record in MCA notifier!\n"); + return AMDGPU_RAS_FAIL; + } + + /* + * Translate UMC channel address to Physical address + */ + ret = amdgpu_umc_convert_error_address(adev, &err_data, err_addr, + ch_inst, umc_inst); + if (ret) + goto out; + + if (amdgpu_bad_page_threshold != 0) { + amdgpu_ras_add_bad_pages(adev, err_data.err_addr, + err_data.err_addr_cnt); + amdgpu_ras_save_bad_pages(adev); + } + +out: + kfree(err_data.err_addr); + return ret; +} static int amdgpu_umc_do_page_retirement(struct amdgpu_device *adev, void *ras_error_status, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h index 3629d8f292ef..659a10de29c9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h @@ -98,4 +98,6 @@ void amdgpu_umc_fill_error_record(struct ras_err_data *err_data, int amdgpu_umc_process_ras_data_cb(struct amdgpu_device *adev, void *ras_error_status, struct amdgpu_iv_entry *entry); +int amdgpu_umc_page_retirement_mca(struct amdgpu_device *adev, + uint64_t err_addr, uint32_t ch_inst, uint32_t umc_inst); #endif -- cgit From 24b822928b5139b85ee9a818a65e343b7e3bb4fe Mon Sep 17 00:00:00 2001 From: Tao Zhou Date: Mon, 17 Oct 2022 18:26:17 +0800 Subject: drm/amdgpu: use page retirement API in MCA notifier Make the code more readable. Signed-off-by: Tao Zhou Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c | 36 +++------------------------------ 1 file changed, 3 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index 21a47f2bb87b..28463b47ce33 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -36,7 +36,6 @@ #include "ivsrcid/nbio/irqsrcs_nbif_7_4.h" #include "atom.h" #include "amdgpu_reset.h" -#include "umc_v6_7.h" #ifdef CONFIG_X86_MCE_AMD #include @@ -2849,7 +2848,6 @@ static int amdgpu_bad_page_notifier(struct notifier_block *nb, struct amdgpu_device *adev = NULL; uint32_t gpu_id = 0; uint32_t umc_inst = 0, ch_inst = 0; - struct ras_err_data err_data = {0, 0, 0, NULL}; /* * If the error was generated in UMC_V2, which belongs to GPU UMCs, @@ -2888,38 +2886,10 @@ static int amdgpu_bad_page_notifier(struct notifier_block *nb, dev_info(adev->dev, "Uncorrectable error detected in UMC inst: %d, chan_idx: %d", umc_inst, ch_inst); - err_data.err_addr = - kcalloc(adev->umc.max_ras_err_cnt_per_query, - sizeof(struct eeprom_table_record), GFP_KERNEL); - if (!err_data.err_addr) { - dev_warn(adev->dev, - "Failed to alloc memory for umc error record in mca notifier!\n"); - return NOTIFY_DONE; - } - - /* - * Translate UMC channel address to Physical address - */ - switch (adev->ip_versions[UMC_HWIP][0]) { - case IP_VERSION(6, 7, 0): - umc_v6_7_convert_error_address(adev, - &err_data, m->addr, ch_inst, umc_inst); - break; - default: - dev_warn(adev->dev, - "UMC address to Physical address translation is not supported\n"); - kfree(err_data.err_addr); + if (!amdgpu_umc_page_retirement_mca(adev, m->addr, ch_inst, umc_inst)) + return NOTIFY_OK; + else return NOTIFY_DONE; - } - - if (amdgpu_bad_page_threshold != 0) { - amdgpu_ras_add_bad_pages(adev, err_data.err_addr, - err_data.err_addr_cnt); - amdgpu_ras_save_bad_pages(adev); - } - - kfree(err_data.err_addr); - return NOTIFY_OK; } static struct notifier_block amdgpu_bad_page_nb = { -- cgit From ae45a18b80d9d0d29f0ecfc52fb4e7831671b299 Mon Sep 17 00:00:00 2001 From: Tao Zhou Date: Mon, 17 Oct 2022 18:31:20 +0800 Subject: drm/amdgpu: add RAS poison handling for MCA For MCA poison, if unmap queue fails, only gpu reset should be triggered without page retirement handling, MCA notifier will do it. v2: handle MCA poison consumption in umc_poison_handler directly. Signed-off-by: Tao Zhou Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c index 3c83129f4090..758942150c09 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c @@ -169,19 +169,28 @@ int amdgpu_umc_poison_handler(struct amdgpu_device *adev, void *ras_error_status, bool reset) { - int ret; - struct ras_err_data *err_data = (struct ras_err_data *)ras_error_status; - struct ras_common_if head = { - .block = AMDGPU_RAS_BLOCK__UMC, - }; - struct ras_manager *obj = amdgpu_ras_find_obj(adev, &head); + int ret = AMDGPU_RAS_SUCCESS; - ret = - amdgpu_umc_do_page_retirement(adev, ras_error_status, NULL, reset); + if (!adev->gmc.xgmi.connected_to_cpu) { + struct ras_err_data *err_data = (struct ras_err_data *)ras_error_status; + struct ras_common_if head = { + .block = AMDGPU_RAS_BLOCK__UMC, + }; + struct ras_manager *obj = amdgpu_ras_find_obj(adev, &head); - if (ret == AMDGPU_RAS_SUCCESS && obj) { - obj->err_data.ue_count += err_data->ue_count; - obj->err_data.ce_count += err_data->ce_count; + ret = + amdgpu_umc_do_page_retirement(adev, ras_error_status, NULL, reset); + + if (ret == AMDGPU_RAS_SUCCESS && obj) { + obj->err_data.ue_count += err_data->ue_count; + obj->err_data.ce_count += err_data->ce_count; + } + } else if (reset) { + /* MCA poison handler is only responsible for GPU reset, + * let MCA notifier do page retirement. + */ + kgd2kfd_set_sram_ecc_flag(adev->kfd.dev); + amdgpu_ras_reset_gpu(adev); } return ret; -- cgit From 1ed0e176902483e67cd02530d387a7551b0e99a4 Mon Sep 17 00:00:00 2001 From: Tao Zhou Date: Tue, 18 Oct 2022 10:31:09 +0800 Subject: drm/amdgpu: remove ras_error_status parameter for UMC poison handler Make the code simpler. Signed-off-by: Tao Zhou Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 4 +--- drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c | 3 +-- drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c | 13 +++++-------- drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h | 4 +--- 4 files changed, 8 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 0561812aa0a4..37db39ba8718 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -753,9 +753,7 @@ bool amdgpu_amdkfd_have_atomics_support(struct amdgpu_device *adev) void amdgpu_amdkfd_ras_poison_consumption_handler(struct amdgpu_device *adev, bool reset) { - struct ras_err_data err_data = {0, 0, 0, NULL}; - - amdgpu_umc_poison_handler(adev, &err_data, reset); + amdgpu_umc_poison_handler(adev, reset); } bool amdgpu_amdkfd_ras_query_utcl2_poison_status(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index 28463b47ce33..693bce07eb46 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -1561,7 +1561,6 @@ static void amdgpu_ras_interrupt_poison_consumption_handler(struct ras_manager * { bool poison_stat = false; struct amdgpu_device *adev = obj->adev; - struct ras_err_data err_data = {0, 0, 0, NULL}; struct amdgpu_ras_block_object *block_obj = amdgpu_ras_get_ras_block(adev, obj->head.block, 0); @@ -1584,7 +1583,7 @@ static void amdgpu_ras_interrupt_poison_consumption_handler(struct ras_manager * } if (!adev->gmc.xgmi.connected_to_cpu) - amdgpu_umc_poison_handler(adev, &err_data, false); + amdgpu_umc_poison_handler(adev, false); if (block_obj->hw_ops->handle_poison_consumption) poison_stat = block_obj->hw_ops->handle_poison_consumption(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c index 758942150c09..f76c19fc0392 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c @@ -165,25 +165,22 @@ static int amdgpu_umc_do_page_retirement(struct amdgpu_device *adev, return AMDGPU_RAS_SUCCESS; } -int amdgpu_umc_poison_handler(struct amdgpu_device *adev, - void *ras_error_status, - bool reset) +int amdgpu_umc_poison_handler(struct amdgpu_device *adev, bool reset) { int ret = AMDGPU_RAS_SUCCESS; if (!adev->gmc.xgmi.connected_to_cpu) { - struct ras_err_data *err_data = (struct ras_err_data *)ras_error_status; + struct ras_err_data err_data = {0, 0, 0, NULL}; struct ras_common_if head = { .block = AMDGPU_RAS_BLOCK__UMC, }; struct ras_manager *obj = amdgpu_ras_find_obj(adev, &head); - ret = - amdgpu_umc_do_page_retirement(adev, ras_error_status, NULL, reset); + ret = amdgpu_umc_do_page_retirement(adev, &err_data, NULL, reset); if (ret == AMDGPU_RAS_SUCCESS && obj) { - obj->err_data.ue_count += err_data->ue_count; - obj->err_data.ce_count += err_data->ce_count; + obj->err_data.ue_count += err_data.ue_count; + obj->err_data.ce_count += err_data.ce_count; } } else if (reset) { /* MCA poison handler is only responsible for GPU reset, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h index 659a10de29c9..a6951160f13a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h @@ -83,9 +83,7 @@ struct amdgpu_umc { }; int amdgpu_umc_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block); -int amdgpu_umc_poison_handler(struct amdgpu_device *adev, - void *ras_error_status, - bool reset); +int amdgpu_umc_poison_handler(struct amdgpu_device *adev, bool reset); int amdgpu_umc_process_ecc_irq(struct amdgpu_device *adev, struct amdgpu_irq_src *source, struct amdgpu_iv_entry *entry); -- cgit From 7117007edad2299f2f093cdcfa813beb646d913e Mon Sep 17 00:00:00 2001 From: Alan Liu Date: Mon, 24 Oct 2022 14:15:30 +0800 Subject: drm/amdgpu: Move the mutex_lock to protect the return status of securedisplay command buffer [Why] Before we call psp_securedisplay_invoke(), we call psp_prep_securedisplay_cmd_buf() to prepare and initialize the command buffer. However, we didn't use the mutex_lock to protect the status of command buffer. So when multiple threads are using the command buffer, after thread A return from psp_securedisplay_invoke() and the command buffer status is set to SUCCESS, another thread B may call psp_prep_securedisplay_cmd_buf() and initialize the status to FAILURE again, and cause Thread A to get a failure return status. [How] Move the mutex_lock out of psp_securedisplay_invoke() to its caller to cover psp_prep_securedisplay_cmd_buf() and the code checking the return status of command buffer. Signed-off-by: Alan Liu Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 9 +++++---- drivers/gpu/drm/amd/amdgpu/amdgpu_securedisplay.c | 4 ++++ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c | 4 ++++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index effa7df3ddbf..7bbf869f4f0d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c @@ -1938,10 +1938,15 @@ static int psp_securedisplay_initialize(struct psp_context *psp) } else return ret; + mutex_lock(&psp->securedisplay_context.mutex); + psp_prep_securedisplay_cmd_buf(psp, &securedisplay_cmd, TA_SECUREDISPLAY_COMMAND__QUERY_TA); ret = psp_securedisplay_invoke(psp, TA_SECUREDISPLAY_COMMAND__QUERY_TA); + + mutex_unlock(&psp->securedisplay_context.mutex); + if (ret) { psp_securedisplay_terminate(psp); /* free securedisplay shared memory */ @@ -1990,12 +1995,8 @@ int psp_securedisplay_invoke(struct psp_context *psp, uint32_t ta_cmd_id) ta_cmd_id != TA_SECUREDISPLAY_COMMAND__SEND_ROI_CRC) return -EINVAL; - mutex_lock(&psp->securedisplay_context.mutex); - ret = psp_ta_invoke(psp, ta_cmd_id, &psp->securedisplay_context.context); - mutex_unlock(&psp->securedisplay_context.mutex); - return ret; } /* SECUREDISPLAY end */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_securedisplay.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_securedisplay.c index cc7597a15fe9..2c1d82fc4c34 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_securedisplay.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_securedisplay.c @@ -121,6 +121,7 @@ static ssize_t amdgpu_securedisplay_debugfs_write(struct file *f, const char __u switch (op) { case 1: + mutex_lock(&psp->securedisplay_context.mutex); psp_prep_securedisplay_cmd_buf(psp, &securedisplay_cmd, TA_SECUREDISPLAY_COMMAND__QUERY_TA); ret = psp_securedisplay_invoke(psp, TA_SECUREDISPLAY_COMMAND__QUERY_TA); @@ -131,8 +132,10 @@ static ssize_t amdgpu_securedisplay_debugfs_write(struct file *f, const char __u else psp_securedisplay_parse_resp_status(psp, securedisplay_cmd->status); } + mutex_unlock(&psp->securedisplay_context.mutex); break; case 2: + mutex_lock(&psp->securedisplay_context.mutex); psp_prep_securedisplay_cmd_buf(psp, &securedisplay_cmd, TA_SECUREDISPLAY_COMMAND__SEND_ROI_CRC); securedisplay_cmd->securedisplay_in_message.send_roi_crc.phy_id = phy_id; @@ -146,6 +149,7 @@ static ssize_t amdgpu_securedisplay_debugfs_write(struct file *f, const char __u psp_securedisplay_parse_resp_status(psp, securedisplay_cmd->status); } } + mutex_unlock(&psp->securedisplay_context.mutex); break; default: dev_err(adev->dev, "Invalid input: %s\n", str); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c index fb077e9af99f..66df2394d7e4 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c @@ -123,6 +123,8 @@ static void amdgpu_dm_crtc_notify_ta_to_read(struct work_struct *work) phy_id = crc_rd_wrk->phy_inst; spin_unlock_irq(&crc_rd_wrk->crc_rd_work_lock); + mutex_lock(&psp->securedisplay_context.mutex); + psp_prep_securedisplay_cmd_buf(psp, &securedisplay_cmd, TA_SECUREDISPLAY_COMMAND__SEND_ROI_CRC); securedisplay_cmd->securedisplay_in_message.send_roi_crc.phy_id = @@ -133,6 +135,8 @@ static void amdgpu_dm_crtc_notify_ta_to_read(struct work_struct *work) psp_securedisplay_parse_resp_status(psp, securedisplay_cmd->status); } } + + mutex_unlock(&psp->securedisplay_context.mutex); } static void -- cgit From 1d522b51e3ab3d65628a5e92c3176df10eab67d4 Mon Sep 17 00:00:00 2001 From: Graham Sider Date: Tue, 25 Oct 2022 14:42:13 -0400 Subject: drm/amdgpu: correct MES debugfs versions Use mes.sched_version, mes.kiq_version for debugfs as mes.ucode_fw_version does not contain correct versioning information. Signed-off-by: Graham Sider Reviewed-by: Jack Xiao Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index bf1ff8f0e712..4e42dcb1950f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -337,12 +337,14 @@ static int amdgpu_firmware_info(struct drm_amdgpu_info_firmware *fw_info, fw_info->feature = adev->psp.cap_feature_version; break; case AMDGPU_INFO_FW_MES_KIQ: - fw_info->ver = adev->mes.ucode_fw_version[0]; - fw_info->feature = 0; + fw_info->ver = adev->mes.kiq_version & AMDGPU_MES_VERSION_MASK; + fw_info->feature = (adev->mes.kiq_version & AMDGPU_MES_FEAT_VERSION_MASK) + >> AMDGPU_MES_FEAT_VERSION_SHIFT; break; case AMDGPU_INFO_FW_MES: - fw_info->ver = adev->mes.ucode_fw_version[1]; - fw_info->feature = 0; + fw_info->ver = adev->mes.sched_version & AMDGPU_MES_VERSION_MASK; + fw_info->feature = (adev->mes.sched_version & AMDGPU_MES_FEAT_VERSION_MASK) + >> AMDGPU_MES_FEAT_VERSION_SHIFT; break; case AMDGPU_INFO_FW_IMU: fw_info->ver = adev->gfx.imu_fw_version; -- cgit From 6040517e4a29d3828160c571681eec9ffe10043f Mon Sep 17 00:00:00 2001 From: Graham Sider Date: Tue, 25 Oct 2022 14:47:05 -0400 Subject: drm/amdgpu: remove deprecated MES version vars MES scheduler and kiq versions are stored in mes.sched_version and mes.kiq_version, respectively, which are read from a register after their queues are initialized. Remove mes.ucode_fw_version and mes.data_fw_version which tried to read this versioning info from the firmware headers (which don't contain this information). Signed-off-by: Graham Sider Reviewed-by: Jack Xiao Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h | 2 -- drivers/gpu/drm/amd/amdgpu/mes_v10_1.c | 4 ---- drivers/gpu/drm/amd/amdgpu/mes_v11_0.c | 4 ---- 3 files changed, 10 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h index ad980f4b66e1..97c05d08a551 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h @@ -91,14 +91,12 @@ struct amdgpu_mes { struct amdgpu_bo *ucode_fw_obj[AMDGPU_MAX_MES_PIPES]; uint64_t ucode_fw_gpu_addr[AMDGPU_MAX_MES_PIPES]; uint32_t *ucode_fw_ptr[AMDGPU_MAX_MES_PIPES]; - uint32_t ucode_fw_version[AMDGPU_MAX_MES_PIPES]; uint64_t uc_start_addr[AMDGPU_MAX_MES_PIPES]; /* mes ucode data */ struct amdgpu_bo *data_fw_obj[AMDGPU_MAX_MES_PIPES]; uint64_t data_fw_gpu_addr[AMDGPU_MAX_MES_PIPES]; uint32_t *data_fw_ptr[AMDGPU_MAX_MES_PIPES]; - uint32_t data_fw_version[AMDGPU_MAX_MES_PIPES]; uint64_t data_start_addr[AMDGPU_MAX_MES_PIPES]; /* eop gpu obj */ diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v10_1.c b/drivers/gpu/drm/amd/amdgpu/mes_v10_1.c index 067d10073a56..1abdf8b7ab50 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_v10_1.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_v10_1.c @@ -415,10 +415,6 @@ static int mes_v10_1_init_microcode(struct amdgpu_device *adev, mes_hdr = (const struct mes_firmware_header_v1_0 *) adev->mes.fw[pipe]->data; - adev->mes.ucode_fw_version[pipe] = - le32_to_cpu(mes_hdr->mes_ucode_version); - adev->mes.ucode_fw_version[pipe] = - le32_to_cpu(mes_hdr->mes_ucode_data_version); adev->mes.uc_start_addr[pipe] = le32_to_cpu(mes_hdr->mes_uc_start_addr_lo) | ((uint64_t)(le32_to_cpu(mes_hdr->mes_uc_start_addr_hi)) << 32); diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c index f141fadd2d86..8ca3417fcfe5 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c @@ -485,10 +485,6 @@ static int mes_v11_0_init_microcode(struct amdgpu_device *adev, mes_hdr = (const struct mes_firmware_header_v1_0 *) adev->mes.fw[pipe]->data; - adev->mes.ucode_fw_version[pipe] = - le32_to_cpu(mes_hdr->mes_ucode_version); - adev->mes.ucode_fw_version[pipe] = - le32_to_cpu(mes_hdr->mes_ucode_data_version); adev->mes.uc_start_addr[pipe] = le32_to_cpu(mes_hdr->mes_uc_start_addr_lo) | ((uint64_t)(le32_to_cpu(mes_hdr->mes_uc_start_addr_hi)) << 32); -- cgit From 64a9f19a5addffe585e872945c0544fed24f83a8 Mon Sep 17 00:00:00 2001 From: Ao Zhong Date: Wed, 26 Oct 2022 13:02:19 +0200 Subject: drm/amd/display: move remaining FPU code to dml folder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the process of enabling DCN support for arm64, I found that the dcn10_resource_construct_fp function in dcn10/dcn10_resource.c still needs to use FPU. This will cause compilation to fail on ARM64 platforms because -mgeneral-regs-only is enabled by default to disable the hardware FPU. So move dcn10_resource_construct_fp from dcn10 folder to dml/dcn10 folder to enable hardware FPU for that function. Reviewed-by: Rodrigo Siqueira Acked-by: Christian König Signed-off-by: Ao Zhong Signed-off-by: Rodrigo Siqueira Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/dc/dcn10/dcn10_resource.c | 44 +--------------------- .../gpu/drm/amd/display/dc/dml/dcn10/dcn10_fpu.c | 36 ++++++++++++++++++ .../gpu/drm/amd/display/dc/dml/dcn10/dcn10_fpu.h | 2 + 3 files changed, 40 insertions(+), 42 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c index 56d30baf12df..6bfac8088ab0 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c @@ -1295,47 +1295,6 @@ static uint32_t read_pipe_fuses(struct dc_context *ctx) return value; } -/* - * Some architectures don't support soft-float (e.g. aarch64), on those - * this function has to be called with hardfloat enabled, make sure not - * to inline it so whatever fp stuff is done stays inside - */ -static noinline void dcn10_resource_construct_fp( - struct dc *dc) -{ - if (dc->ctx->dce_version == DCN_VERSION_1_01) { - struct dcn_soc_bounding_box *dcn_soc = dc->dcn_soc; - struct dcn_ip_params *dcn_ip = dc->dcn_ip; - struct display_mode_lib *dml = &dc->dml; - - dml->ip.max_num_dpp = 3; - /* TODO how to handle 23.84? */ - dcn_soc->dram_clock_change_latency = 23; - dcn_ip->max_num_dpp = 3; - } - if (ASICREV_IS_RV1_F0(dc->ctx->asic_id.hw_internal_rev)) { - dc->dcn_soc->urgent_latency = 3; - dc->debug.disable_dmcu = true; - dc->dcn_soc->fabric_and_dram_bandwidth_vmax0p9 = 41.60f; - } - - - dc->dcn_soc->number_of_channels = dc->ctx->asic_id.vram_width / ddr4_dram_width; - ASSERT(dc->dcn_soc->number_of_channels < 3); - if (dc->dcn_soc->number_of_channels == 0)/*old sbios bug*/ - dc->dcn_soc->number_of_channels = 2; - - if (dc->dcn_soc->number_of_channels == 1) { - dc->dcn_soc->fabric_and_dram_bandwidth_vmax0p9 = 19.2f; - dc->dcn_soc->fabric_and_dram_bandwidth_vnom0p8 = 17.066f; - dc->dcn_soc->fabric_and_dram_bandwidth_vmid0p72 = 14.933f; - dc->dcn_soc->fabric_and_dram_bandwidth_vmin0p65 = 12.8f; - if (ASICREV_IS_RV1_F0(dc->ctx->asic_id.hw_internal_rev)) { - dc->dcn_soc->fabric_and_dram_bandwidth_vmax0p9 = 20.80f; - } - } -} - static bool verify_clock_values(struct dm_pp_clock_levels_with_voltage *clks) { int i; @@ -1510,8 +1469,9 @@ static bool dcn10_resource_construct( memcpy(dc->dcn_ip, &dcn10_ip_defaults, sizeof(dcn10_ip_defaults)); memcpy(dc->dcn_soc, &dcn10_soc_defaults, sizeof(dcn10_soc_defaults)); - /* Other architectures we build for build this with soft-float */ + DC_FP_START(); dcn10_resource_construct_fp(dc); + DC_FP_END(); if (!dc->config.is_vmin_only_asic) if (ASICREV_IS_RAVEN2(dc->ctx->asic_id.hw_internal_rev)) diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn10/dcn10_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn10/dcn10_fpu.c index 99644d896222..c5e84190c17a 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn10/dcn10_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn10/dcn10_fpu.c @@ -27,6 +27,8 @@ #include "dcn10/dcn10_resource.h" #include "dcn10_fpu.h" +#include "resource.h" +#include "amdgpu_dm/dc_fpu.h" /** * DOC: DCN10 FPU manipulation Overview @@ -121,3 +123,37 @@ struct _vcs_dpi_soc_bounding_box_st dcn1_0_soc = { .writeback_dram_clock_change_latency_us = 23.0, .return_bus_width_bytes = 64, }; + +void dcn10_resource_construct_fp(struct dc *dc) +{ + dc_assert_fp_enabled(); + if (dc->ctx->dce_version == DCN_VERSION_1_01) { + struct dcn_soc_bounding_box *dcn_soc = dc->dcn_soc; + struct dcn_ip_params *dcn_ip = dc->dcn_ip; + struct display_mode_lib *dml = &dc->dml; + + dml->ip.max_num_dpp = 3; + /* TODO how to handle 23.84? */ + dcn_soc->dram_clock_change_latency = 23; + dcn_ip->max_num_dpp = 3; + } + if (ASICREV_IS_RV1_F0(dc->ctx->asic_id.hw_internal_rev)) { + dc->dcn_soc->urgent_latency = 3; + dc->debug.disable_dmcu = true; + dc->dcn_soc->fabric_and_dram_bandwidth_vmax0p9 = 41.60f; + } + + dc->dcn_soc->number_of_channels = dc->ctx->asic_id.vram_width / ddr4_dram_width; + ASSERT(dc->dcn_soc->number_of_channels < 3); + if (dc->dcn_soc->number_of_channels == 0)/*old sbios bug*/ + dc->dcn_soc->number_of_channels = 2; + + if (dc->dcn_soc->number_of_channels == 1) { + dc->dcn_soc->fabric_and_dram_bandwidth_vmax0p9 = 19.2f; + dc->dcn_soc->fabric_and_dram_bandwidth_vnom0p8 = 17.066f; + dc->dcn_soc->fabric_and_dram_bandwidth_vmid0p72 = 14.933f; + dc->dcn_soc->fabric_and_dram_bandwidth_vmin0p65 = 12.8f; + if (ASICREV_IS_RV1_F0(dc->ctx->asic_id.hw_internal_rev)) + dc->dcn_soc->fabric_and_dram_bandwidth_vmax0p9 = 20.80f; + } +} diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn10/dcn10_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn10/dcn10_fpu.h index e74ed4b4ce5b..63219ecd8478 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn10/dcn10_fpu.h +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn10/dcn10_fpu.h @@ -27,4 +27,6 @@ #ifndef __DCN10_FPU_H__ #define __DCN10_FPU_H__ +void dcn10_resource_construct_fp(struct dc *dc); + #endif /* __DCN20_FPU_H__ */ -- cgit From 58ddbecb14c792b7fe0d92ae5e25c9179d62ff25 Mon Sep 17 00:00:00 2001 From: Ao Zhong Date: Tue, 25 Oct 2022 23:17:49 +0200 Subject: drm/amd/display: move remaining FPU code to dml folder pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_luma = 0; pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_chroma = 0; these two operations in dcn32/dcn32_resource.c still need to use FPU, This will cause compilation to fail on ARM64 platforms because -mgeneral-regs-only is enabled by default to disable the hardware FPU. Therefore, imitate the dcn31_zero_pipe_dcc_fraction function in dml/dcn31/dcn31_fpu.c, declare the dcn32_zero_pipe_dcc_fraction function in dcn32_fpu.c, and move above two operations into this function. Reviewed-by: Rodrigo Siqueira Signed-off-by: Ao Zhong Signed-off-by: Rodrigo Siqueira Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c | 5 +++-- drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c | 8 ++++++++ drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h | 3 +++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c index a88dd7b3d1c1..287b7fa9bf41 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c @@ -1918,8 +1918,9 @@ int dcn32_populate_dml_pipes_from_context( timing = &pipe->stream->timing; pipes[pipe_cnt].pipe.src.gpuvm = true; - pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_luma = 0; - pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_chroma = 0; + DC_FP_START(); + dcn32_zero_pipe_dcc_fraction(pipes, pipe_cnt); + DC_FP_END(); pipes[pipe_cnt].pipe.dest.vfront_porch = timing->v_front_porch; pipes[pipe_cnt].pipe.src.gpuvm_min_page_size_kbytes = 256; // according to spreadsheet pipes[pipe_cnt].pipe.src.unbounded_req_mode = false; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c index d8e68f13c288..b6cd10f3181c 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c @@ -2506,3 +2506,11 @@ void dcn32_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_pa } } +void dcn32_zero_pipe_dcc_fraction(display_e2e_pipe_params_st *pipes, + int pipe_cnt) +{ + dc_assert_fp_enabled(); + + pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_luma = 0; + pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_chroma = 0; +} diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h index 3a3dc2ce4c73..ab010e7e840b 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h @@ -73,4 +73,7 @@ int dcn32_find_dummy_latency_index_for_fw_based_mclk_switch(struct dc *dc, void dcn32_patch_dpm_table(struct clk_bw_params *bw_params); +void dcn32_zero_pipe_dcc_fraction(display_e2e_pipe_params_st *pipes, + int pipe_cnt); + #endif -- cgit From d232afb1f3417ae8194ccf19ad3a8360e70e104e Mon Sep 17 00:00:00 2001 From: gehao Date: Wed, 26 Oct 2022 17:54:05 +0800 Subject: drm/amd/display: prevent memory leak In dce6(0,1,4)_create_resource_pool and dce80_create_resource_pool the allocated memory should be released if construct pool fails. Reviewed-by: Rodrigo Siqueira Signed-off-by: gehao Signed-off-by: Rodrigo Siqueira Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dce60/dce60_resource.c | 3 +++ drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dce60/dce60_resource.c b/drivers/gpu/drm/amd/display/dc/dce60/dce60_resource.c index fc6aa098bda0..8db9f7514466 100644 --- a/drivers/gpu/drm/amd/display/dc/dce60/dce60_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce60/dce60_resource.c @@ -1128,6 +1128,7 @@ struct resource_pool *dce60_create_resource_pool( if (dce60_construct(num_virtual_links, dc, pool)) return &pool->base; + kfree(pool); BREAK_TO_DEBUGGER(); return NULL; } @@ -1325,6 +1326,7 @@ struct resource_pool *dce61_create_resource_pool( if (dce61_construct(num_virtual_links, dc, pool)) return &pool->base; + kfree(pool); BREAK_TO_DEBUGGER(); return NULL; } @@ -1518,6 +1520,7 @@ struct resource_pool *dce64_create_resource_pool( if (dce64_construct(num_virtual_links, dc, pool)) return &pool->base; + kfree(pool); BREAK_TO_DEBUGGER(); return NULL; } diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c index b28025960050..5825e6f412bd 100644 --- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c @@ -1137,6 +1137,7 @@ struct resource_pool *dce80_create_resource_pool( if (dce80_construct(num_virtual_links, dc, pool)) return &pool->base; + kfree(pool); BREAK_TO_DEBUGGER(); return NULL; } @@ -1336,6 +1337,7 @@ struct resource_pool *dce81_create_resource_pool( if (dce81_construct(num_virtual_links, dc, pool)) return &pool->base; + kfree(pool); BREAK_TO_DEBUGGER(); return NULL; } -- cgit From 9682069a03c1ff031a67d80e7a58cf2b11d7f758 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Wed, 26 Oct 2022 10:00:54 +0800 Subject: drm/amdkfd: Fix NULL pointer dereference in svm_migrate_to_ram() ./drivers/gpu/drm/amd/amdkfd/kfd_migrate.c:985:58-62: ERROR: p is NULL but dereferenced. Link: https://bugzilla.openanolis.cn/show_bug.cgi?id=2549 Reported-by: Abaci Robot Signed-off-by: Yang Li Reviewed-by: Felix Kuehling Signed-off-by: Felix Kuehling Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c index d4e6de2a6bf6..3723e90e3a90 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c @@ -973,12 +973,10 @@ out_unlock_prange: out_unlock_svms: mutex_unlock(&p->svms.lock); out_unref_process: + pr_debug("CPU fault svms 0x%p address 0x%lx done\n", &p->svms, addr); kfd_unref_process(p); out_mmput: mmput(mm); - - pr_debug("CPU fault svms 0x%p address 0x%lx done\n", &p->svms, addr); - return r ? VM_FAULT_SIGBUS : 0; } -- cgit From bf7d777289d106963fd2080d298e6b88b7263b66 Mon Sep 17 00:00:00 2001 From: Candice Li Date: Tue, 25 Oct 2022 18:07:44 +0800 Subject: drm/amdgpu: Optimize RAS TA initialization and TA unload funcs 1. Save TA unload psp response status 2. Add RAS TA loading status check for initializaiton 3. Drop RAS context teardown to allow RAS TA to be reloaded Reviewed-by: Hawking Zhang Signed-off-by: Candice Li Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index 7bbf869f4f0d..b8d07e863ed8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c @@ -988,6 +988,8 @@ int psp_ta_unload(struct psp_context *psp, struct ta_context *context) ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr); + context->resp_status = cmd->resp.status; + release_psp_cmd_buf(psp); return ret; @@ -1560,6 +1562,11 @@ static int psp_ras_initialize(struct psp_context *psp) if (amdgpu_sriov_vf(adev)) return 0; + if (psp->ras_context.context.initialized) { + dev_warn(adev->dev, "RAS WARN: TA has already been loaded\n"); + return 0; + } + if (!adev->psp.ras_context.context.bin_desc.size_bytes || !adev->psp.ras_context.context.bin_desc.start_addr) { dev_info(adev->dev, "RAS: optional ras ta ucode is not available\n"); @@ -1610,7 +1617,7 @@ static int psp_ras_initialize(struct psp_context *psp) psp->ras_context.context.mem_context.shared_mem_size = PSP_RAS_SHARED_MEM_SIZE; psp->ras_context.context.ta_load_type = GFX_CMD_ID_LOAD_TA; - if (!psp->ras_context.context.initialized) { + if (!psp->ras_context.context.mem_context.shared_buf) { ret = psp_ta_init_shared_buf(psp, &psp->ras_context.context.mem_context); if (ret) return ret; @@ -1631,7 +1638,6 @@ static int psp_ras_initialize(struct psp_context *psp) else { if (ras_cmd->ras_status) dev_warn(psp->adev->dev, "RAS Init Status: 0x%X\n", ras_cmd->ras_status); - amdgpu_ras_fini(psp->adev); } return ret; -- cgit From 896b7addf2dc24908ad87f8ebeff83b2a83b8e04 Mon Sep 17 00:00:00 2001 From: Candice Li Date: Tue, 25 Oct 2022 18:32:15 +0800 Subject: drm/amdgpu: Optimize TA load/unload/invoke debugfs interfaces 1. Add a function pointer structure ta_funcs to psp context 2. Make the interfaces generic to all TAs 3. Leverage exisitng TA context and remove unused functions 4. Fix return code bugs v2: Add comments for ta funcs macros and correct typo Reviewed-by: Hawking Zhang Signed-off-by: Candice Li Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 38 +---- drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h | 12 +- drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.c | 217 ++++++++++++++++++++--------- drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.h | 5 + 4 files changed, 168 insertions(+), 104 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index b8d07e863ed8..2fcb5bfbef89 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c @@ -1071,42 +1071,6 @@ int psp_ta_init_shared_buf(struct psp_context *psp, &mem_ctx->shared_buf); } -static void psp_prep_ta_invoke_indirect_cmd_buf(struct psp_gfx_cmd_resp *cmd, - uint32_t ta_cmd_id, - struct ta_context *context) -{ - cmd->cmd_id = GFX_CMD_ID_INVOKE_CMD; - cmd->cmd.cmd_invoke_cmd.session_id = context->session_id; - cmd->cmd.cmd_invoke_cmd.ta_cmd_id = ta_cmd_id; - - cmd->cmd.cmd_invoke_cmd.buf.num_desc = 1; - cmd->cmd.cmd_invoke_cmd.buf.total_size = context->mem_context.shared_mem_size; - cmd->cmd.cmd_invoke_cmd.buf.buf_desc[0].buf_size = context->mem_context.shared_mem_size; - cmd->cmd.cmd_invoke_cmd.buf.buf_desc[0].buf_phy_addr_lo = - lower_32_bits(context->mem_context.shared_mc_addr); - cmd->cmd.cmd_invoke_cmd.buf.buf_desc[0].buf_phy_addr_hi = - upper_32_bits(context->mem_context.shared_mc_addr); -} - -int psp_ta_invoke_indirect(struct psp_context *psp, - uint32_t ta_cmd_id, - struct ta_context *context) -{ - int ret; - struct psp_gfx_cmd_resp *cmd = acquire_psp_cmd_buf(psp); - - psp_prep_ta_invoke_indirect_cmd_buf(cmd, ta_cmd_id, context); - - ret = psp_cmd_submit_buf(psp, NULL, cmd, - psp->fence_buf_mc_addr); - - context->resp_status = cmd->resp.status; - - release_psp_cmd_buf(psp); - - return ret; -} - static void psp_prep_ta_invoke_cmd_buf(struct psp_gfx_cmd_resp *cmd, uint32_t ta_cmd_id, uint32_t session_id) @@ -1549,7 +1513,7 @@ int psp_ras_terminate(struct psp_context *psp) return ret; } -static int psp_ras_initialize(struct psp_context *psp) +int psp_ras_initialize(struct psp_context *psp) { int ret; uint32_t boot_cfg = 0xFF; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h index 58ce3ebb446c..cbd4194a2883 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h @@ -136,6 +136,12 @@ struct psp_funcs int (*vbflash_stat)(struct psp_context *psp); }; +struct ta_funcs { + int (*fn_ta_initialize)(struct psp_context *psp); + int (*fn_ta_invoke)(struct psp_context *psp, uint32_t ta_cmd_id); + int (*fn_ta_terminate)(struct psp_context *psp); +}; + #define AMDGPU_XGMI_MAX_CONNECTED_NODES 64 struct psp_xgmi_node_info { uint64_t node_id; @@ -309,6 +315,7 @@ struct psp_context struct psp_gfx_cmd_resp *cmd; const struct psp_funcs *funcs; + const struct ta_funcs *ta_funcs; /* firmware buffer */ struct amdgpu_bo *fw_pri_bo; @@ -463,9 +470,6 @@ int psp_ta_load(struct psp_context *psp, struct ta_context *context); int psp_ta_invoke(struct psp_context *psp, uint32_t ta_cmd_id, struct ta_context *context); -int psp_ta_invoke_indirect(struct psp_context *psp, - uint32_t ta_cmd_id, - struct ta_context *context); int psp_xgmi_initialize(struct psp_context *psp, bool set_extended_data, bool load_ta); int psp_xgmi_terminate(struct psp_context *psp); @@ -479,7 +483,7 @@ int psp_xgmi_get_topology_info(struct psp_context *psp, int psp_xgmi_set_topology_info(struct psp_context *psp, int number_devices, struct psp_xgmi_topology_info *topology); - +int psp_ras_initialize(struct psp_context *psp); int psp_ras_invoke(struct psp_context *psp, uint32_t ta_cmd_id); int psp_ras_enable_features(struct psp_context *psp, union ta_ras_cmd_input *info, bool enable); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.c index 0988e00612e5..468a67b302d4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.c @@ -41,30 +41,46 @@ static uint32_t get_bin_version(const uint8_t *bin) return hdr->ucode_version; } -static void prep_ta_mem_context(struct psp_context *psp, - struct ta_context *context, +static int prep_ta_mem_context(struct ta_mem_context *mem_context, uint8_t *shared_buf, uint32_t shared_buf_len) { - context->mem_context.shared_mem_size = PAGE_ALIGN(shared_buf_len); - psp_ta_init_shared_buf(psp, &context->mem_context); + if (mem_context->shared_mem_size < shared_buf_len) + return -EINVAL; + memset(mem_context->shared_buf, 0, mem_context->shared_mem_size); + memcpy((void *)mem_context->shared_buf, shared_buf, shared_buf_len); - memcpy((void *)context->mem_context.shared_buf, shared_buf, shared_buf_len); + return 0; } static bool is_ta_type_valid(enum ta_type_id ta_type) { - bool ret = false; + switch (ta_type) { + case TA_TYPE_RAS: + return true; + default: + return false; + } +} + +static const struct ta_funcs ras_ta_funcs = { + .fn_ta_initialize = psp_ras_initialize, + .fn_ta_invoke = psp_ras_invoke, + .fn_ta_terminate = psp_ras_terminate +}; +static void set_ta_context_funcs(struct psp_context *psp, + enum ta_type_id ta_type, + struct ta_context **pcontext) +{ switch (ta_type) { case TA_TYPE_RAS: - ret = true; + *pcontext = &psp->ras_context.context; + psp->ta_funcs = &ras_ta_funcs; break; default: break; } - - return ret; } static const struct file_operations ta_load_debugfs_fops = { @@ -85,8 +101,7 @@ static const struct file_operations ta_invoke_debugfs_fops = { .owner = THIS_MODULE }; - -/** +/* * DOC: AMDGPU TA debugfs interfaces * * Three debugfs interfaces can be opened by a program to @@ -111,15 +126,18 @@ static const struct file_operations ta_invoke_debugfs_fops = { * * - For TA invoke debugfs interface: * Transmit buffer: + * - TA type (4bytes) * - TA ID (4bytes) * - TA CMD ID (4bytes) - * - TA shard buf length (4bytes) + * - TA shard buf length + * (4bytes, value not beyond TA shared memory size) * - TA shared buf * Receive buffer: * - TA shared buf * * - For TA unload debugfs interface: * Transmit buffer: + * - TA type (4bytes) * - TA ID (4bytes) */ @@ -131,59 +149,92 @@ static ssize_t ta_if_load_debugfs_write(struct file *fp, const char *buf, size_t uint32_t copy_pos = 0; int ret = 0; - struct amdgpu_device *adev = (struct amdgpu_device *)file_inode(fp)->i_private; - struct psp_context *psp = &adev->psp; - struct ta_context context = {0}; + struct amdgpu_device *adev = (struct amdgpu_device *)file_inode(fp)->i_private; + struct psp_context *psp = &adev->psp; + struct ta_context *context = NULL; if (!buf) return -EINVAL; ret = copy_from_user((void *)&ta_type, &buf[copy_pos], sizeof(uint32_t)); if (ret || (!is_ta_type_valid(ta_type))) - return -EINVAL; + return -EFAULT; copy_pos += sizeof(uint32_t); ret = copy_from_user((void *)&ta_bin_len, &buf[copy_pos], sizeof(uint32_t)); if (ret) - return -EINVAL; + return -EFAULT; copy_pos += sizeof(uint32_t); ta_bin = kzalloc(ta_bin_len, GFP_KERNEL); if (!ta_bin) - ret = -ENOMEM; + return -ENOMEM; if (copy_from_user((void *)ta_bin, &buf[copy_pos], ta_bin_len)) { ret = -EFAULT; goto err_free_bin; } - ret = psp_ras_terminate(psp); - if (ret) { - dev_err(adev->dev, "Failed to unload embedded RAS TA\n"); + /* Set TA context and functions */ + set_ta_context_funcs(psp, ta_type, &context); + + if (!psp->ta_funcs || !psp->ta_funcs->fn_ta_terminate) { + dev_err(adev->dev, "Unsupported function to terminate TA\n"); + ret = -EOPNOTSUPP; goto err_free_bin; } - context.ta_type = ta_type; - context.ta_load_type = GFX_CMD_ID_LOAD_TA; - context.bin_desc.fw_version = get_bin_version(ta_bin); - context.bin_desc.size_bytes = ta_bin_len; - context.bin_desc.start_addr = ta_bin; + /* + * Allocate TA shared buf in case shared buf was freed + * due to loading TA failed before. + */ + if (!context->mem_context.shared_buf) { + ret = psp_ta_init_shared_buf(psp, &context->mem_context); + if (ret) { + ret = -ENOMEM; + goto err_free_bin; + } + } + + ret = psp_fn_ta_terminate(psp); + if (ret || context->resp_status) { + dev_err(adev->dev, + "Failed to unload embedded TA (%d) and status (0x%X)\n", + ret, context->resp_status); + if (!ret) + ret = -EINVAL; + goto err_free_ta_shared_buf; + } + + /* Prepare TA context for TA initialization */ + context->ta_type = ta_type; + context->bin_desc.fw_version = get_bin_version(ta_bin); + context->bin_desc.size_bytes = ta_bin_len; + context->bin_desc.start_addr = ta_bin; - ret = psp_ta_load(psp, &context); + if (!psp->ta_funcs->fn_ta_initialize) { + dev_err(adev->dev, "Unsupported function to initialize TA\n"); + ret = -EOPNOTSUPP; + goto err_free_ta_shared_buf; + } - if (ret || context.resp_status) { - dev_err(adev->dev, "TA load via debugfs failed (%d) status %d\n", - ret, context.resp_status); + ret = psp_fn_ta_initialize(psp); + if (ret || context->resp_status) { + dev_err(adev->dev, "Failed to load TA via debugfs (%d) and status (0x%X)\n", + ret, context->resp_status); if (!ret) ret = -EINVAL; - goto err_free_bin; + goto err_free_ta_shared_buf; } - context.initialized = true; - if (copy_to_user((char *)buf, (void *)&context.session_id, sizeof(uint32_t))) + if (copy_to_user((char *)buf, (void *)&context->session_id, sizeof(uint32_t))) ret = -EFAULT; +err_free_ta_shared_buf: + /* Only free TA shared buf when returns error code */ + if (ret && context->mem_context.shared_buf) + psp_ta_free_shared_buf(&context->mem_context); err_free_bin: kfree(ta_bin); @@ -192,58 +243,85 @@ err_free_bin: static ssize_t ta_if_unload_debugfs_write(struct file *fp, const char *buf, size_t len, loff_t *off) { - uint32_t ta_id = 0; - int ret = 0; + uint32_t ta_type = 0; + uint32_t ta_id = 0; + uint32_t copy_pos = 0; + int ret = 0; - struct amdgpu_device *adev = (struct amdgpu_device *)file_inode(fp)->i_private; - struct psp_context *psp = &adev->psp; - struct ta_context context = {0}; + struct amdgpu_device *adev = (struct amdgpu_device *)file_inode(fp)->i_private; + struct psp_context *psp = &adev->psp; + struct ta_context *context = NULL; if (!buf) return -EINVAL; - ret = copy_from_user((void *)&ta_id, buf, sizeof(uint32_t)); + ret = copy_from_user((void *)&ta_type, &buf[copy_pos], sizeof(uint32_t)); + if (ret || (!is_ta_type_valid(ta_type))) + return -EFAULT; + + copy_pos += sizeof(uint32_t); + + ret = copy_from_user((void *)&ta_id, &buf[copy_pos], sizeof(uint32_t)); if (ret) - return -EINVAL; + return -EFAULT; - context.session_id = ta_id; + set_ta_context_funcs(psp, ta_type, &context); + context->session_id = ta_id; - ret = psp_ta_unload(psp, &context); - if (!ret) - context.initialized = false; + if (!psp->ta_funcs || !psp->ta_funcs->fn_ta_terminate) { + dev_err(adev->dev, "Unsupported function to terminate TA\n"); + return -EOPNOTSUPP; + } + + ret = psp_fn_ta_terminate(psp); + if (ret || context->resp_status) { + dev_err(adev->dev, "Failed to unload TA via debugfs (%d) and status (0x%X)\n", + ret, context->resp_status); + if (!ret) + ret = -EINVAL; + } + + if (context->mem_context.shared_buf) + psp_ta_free_shared_buf(&context->mem_context); return ret; } static ssize_t ta_if_invoke_debugfs_write(struct file *fp, const char *buf, size_t len, loff_t *off) { + uint32_t ta_type = 0; uint32_t ta_id = 0; uint32_t cmd_id = 0; uint32_t shared_buf_len = 0; - uint8_t *shared_buf = NULL; + uint8_t *shared_buf = NULL; uint32_t copy_pos = 0; int ret = 0; - struct amdgpu_device *adev = (struct amdgpu_device *)file_inode(fp)->i_private; - struct psp_context *psp = &adev->psp; - struct ta_context context = {0}; + struct amdgpu_device *adev = (struct amdgpu_device *)file_inode(fp)->i_private; + struct psp_context *psp = &adev->psp; + struct ta_context *context = NULL; if (!buf) return -EINVAL; + ret = copy_from_user((void *)&ta_type, &buf[copy_pos], sizeof(uint32_t)); + if (ret) + return -EFAULT; + copy_pos += sizeof(uint32_t); + ret = copy_from_user((void *)&ta_id, &buf[copy_pos], sizeof(uint32_t)); if (ret) - return -EINVAL; + return -EFAULT; copy_pos += sizeof(uint32_t); ret = copy_from_user((void *)&cmd_id, &buf[copy_pos], sizeof(uint32_t)); if (ret) - return -EINVAL; + return -EFAULT; copy_pos += sizeof(uint32_t); ret = copy_from_user((void *)&shared_buf_len, &buf[copy_pos], sizeof(uint32_t)); if (ret) - return -EINVAL; + return -EFAULT; copy_pos += sizeof(uint32_t); shared_buf = kzalloc(shared_buf_len, GFP_KERNEL); @@ -254,26 +332,39 @@ static ssize_t ta_if_invoke_debugfs_write(struct file *fp, const char *buf, size goto err_free_shared_buf; } - context.session_id = ta_id; + set_ta_context_funcs(psp, ta_type, &context); + + if (!context->initialized) { + dev_err(adev->dev, "TA is not initialized\n"); + ret = -EINVAL; + goto err_free_shared_buf; + } + + if (!psp->ta_funcs || !psp->ta_funcs->fn_ta_invoke) { + dev_err(adev->dev, "Unsupported function to invoke TA\n"); + ret = -EOPNOTSUPP; + goto err_free_shared_buf; + } - prep_ta_mem_context(psp, &context, shared_buf, shared_buf_len); + context->session_id = ta_id; - ret = psp_ta_invoke_indirect(psp, cmd_id, &context); + ret = prep_ta_mem_context(&context->mem_context, shared_buf, shared_buf_len); + if (ret) + goto err_free_shared_buf; - if (ret || context.resp_status) { - dev_err(adev->dev, "TA invoke via debugfs failed (%d) status %d\n", - ret, context.resp_status); - if (!ret) + ret = psp_fn_ta_invoke(psp, cmd_id); + if (ret || context->resp_status) { + dev_err(adev->dev, "Failed to invoke TA via debugfs (%d) and status (0x%X)\n", + ret, context->resp_status); + if (!ret) { ret = -EINVAL; - goto err_free_ta_shared_buf; + goto err_free_shared_buf; + } } - if (copy_to_user((char *)buf, context.mem_context.shared_buf, shared_buf_len)) + if (copy_to_user((char *)buf, context->mem_context.shared_buf, shared_buf_len)) ret = -EFAULT; -err_free_ta_shared_buf: - psp_ta_free_shared_buf(&context.mem_context); - err_free_shared_buf: kfree(shared_buf); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.h index cfc1542f63ef..14cd1c81c3e6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.h @@ -24,6 +24,11 @@ #ifndef __AMDGPU_PSP_TA_H__ #define __AMDGPU_PSP_TA_H__ +/* Calling set_ta_context_funcs is required before using the following macros */ +#define psp_fn_ta_initialize(psp) ((psp)->ta_funcs->fn_ta_initialize((psp))) +#define psp_fn_ta_invoke(psp, ta_cmd_id) ((psp)->ta_funcs->fn_ta_invoke((psp), (ta_cmd_id))) +#define psp_fn_ta_terminate(psp) ((psp)->ta_funcs->fn_ta_terminate((psp))) + void amdgpu_ta_if_debugfs_init(struct amdgpu_device *adev); #endif -- cgit From bc22f8ec464af9e14263c3ed6a1c2be86618c804 Mon Sep 17 00:00:00 2001 From: Candice Li Date: Mon, 10 Oct 2022 16:26:37 +0800 Subject: drm/amdgpu: Update ras eeprom support for smu v13_0_0 and v13_0_10 Enable RAS EEPROM support for smu v13_0_0 and v13_0_10. Signed-off-by: Candice Li Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index 84c241b9a2a1..7dc39154822c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -90,6 +90,16 @@ static bool __is_ras_eeprom_supported(struct amdgpu_device *adev) { + if (adev->asic_type == CHIP_IP_DISCOVERY) { + switch (adev->ip_versions[MP1_HWIP][0]) { + case IP_VERSION(13, 0, 0): + case IP_VERSION(13, 0, 10): + return true; + default: + return false; + } + } + return adev->asic_type == CHIP_VEGA20 || adev->asic_type == CHIP_ARCTURUS || adev->asic_type == CHIP_SIENNA_CICHLID || -- cgit From c9bdc6c3cf39df6db9c611d05fc512b1276b1cc8 Mon Sep 17 00:00:00 2001 From: Candice Li Date: Tue, 11 Oct 2022 15:08:38 +0800 Subject: drm/amdgpu: Add EEPROM I2C address support for ip discovery 1. Update EEPROM_I2C_MADDR_SMU_13_0_0 to EEPROM_I2C_MADDR_54H 2. Add EEPROM I2C address support for smu v13_0_0 and v13_0_10. Signed-off-by: Candice Li Reviewed-by: Tao Zhou Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index 7dc39154822c..7268ae65c140 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -38,7 +38,7 @@ #define EEPROM_I2C_MADDR_ARCTURUS_D342 0x0 #define EEPROM_I2C_MADDR_SIENNA_CICHLID 0x0 #define EEPROM_I2C_MADDR_ALDEBARAN 0x0 -#define EEPROM_I2C_MADDR_SMU_13_0_0 (0x54UL << 16) +#define EEPROM_I2C_MADDR_54H (0x54UL << 16) /* * The 2 macros bellow represent the actual size in bytes that @@ -124,6 +124,19 @@ static bool __get_eeprom_i2c_addr_arct(struct amdgpu_device *adev, return true; } +static bool __get_eeprom_i2c_addr_ip_discovery(struct amdgpu_device *adev, + struct amdgpu_ras_eeprom_control *control) +{ + switch (adev->ip_versions[MP1_HWIP][0]) { + case IP_VERSION(13, 0, 0): + case IP_VERSION(13, 0, 10): + control->i2c_address = EEPROM_I2C_MADDR_54H; + return true; + default: + return false; + } +} + static bool __get_eeprom_i2c_addr(struct amdgpu_device *adev, struct amdgpu_ras_eeprom_control *control) { @@ -163,13 +176,16 @@ static bool __get_eeprom_i2c_addr(struct amdgpu_device *adev, control->i2c_address = EEPROM_I2C_MADDR_ALDEBARAN; break; + case CHIP_IP_DISCOVERY: + return __get_eeprom_i2c_addr_ip_discovery(adev, control); + default: return false; } switch (adev->ip_versions[MP1_HWIP][0]) { case IP_VERSION(13, 0, 0): - control->i2c_address = EEPROM_I2C_MADDR_SMU_13_0_0; + control->i2c_address = EEPROM_I2C_MADDR_54H; break; default: -- cgit From aa193f7eff8ff753577351140b8af13b76cdc7c2 Mon Sep 17 00:00:00 2001 From: Hamza Mahfooz Date: Fri, 21 Oct 2022 16:37:34 -0400 Subject: drm/edid: add a quirk for two LG monitors to get them to work on 10bpc The LG 27GP950 and LG 27GN950 have visible display corruption when trying to use 10bpc modes. So, to fix this, cap their maximum DSC target bitrate to 15bpp. Suggested-by: Roman Li Reviewed-by: Harry Wentland Signed-off-by: Hamza Mahfooz Signed-off-by: Alex Deucher --- drivers/gpu/drm/drm_edid.c | 12 ++++++++++++ include/drm/drm_connector.h | 6 ++++++ 2 files changed, 18 insertions(+) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 4005dab6147d..b36abfa91581 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -87,6 +87,8 @@ static int oui(u8 first, u8 second, u8 third) #define EDID_QUIRK_FORCE_10BPC (1 << 11) /* Non desktop display (i.e. HMD) */ #define EDID_QUIRK_NON_DESKTOP (1 << 12) +/* Cap the DSC target bitrate to 15bpp */ +#define EDID_QUIRK_CAP_DSC_15BPP (1 << 13) #define MICROSOFT_IEEE_OUI 0xca125c @@ -147,6 +149,12 @@ static const struct edid_quirk { EDID_QUIRK('F', 'C', 'M', 13600, EDID_QUIRK_PREFER_LARGE_75 | EDID_QUIRK_DETAILED_IN_CM), + /* LG 27GP950 */ + EDID_QUIRK('G', 'S', 'M', 0x5bbf, EDID_QUIRK_CAP_DSC_15BPP), + + /* LG 27GN950 */ + EDID_QUIRK('G', 'S', 'M', 0x5b9a, EDID_QUIRK_CAP_DSC_15BPP), + /* LGD panel of HP zBook 17 G2, eDP 10 bpc, but reports unknown bpc */ EDID_QUIRK('L', 'G', 'D', 764, EDID_QUIRK_FORCE_10BPC), @@ -6166,6 +6174,7 @@ static void drm_reset_display_info(struct drm_connector *connector) info->mso_stream_count = 0; info->mso_pixel_overlap = 0; + info->max_dsc_bpp = 0; } static u32 update_display_info(struct drm_connector *connector, @@ -6252,6 +6261,9 @@ out: info->non_desktop = true; } + if (quirks & EDID_QUIRK_CAP_DSC_15BPP) + info->max_dsc_bpp = 15; + return quirks; } diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 56aee949c6fa..4d830fc55a3d 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -656,6 +656,12 @@ struct drm_display_info { * @mso_pixel_overlap: eDP MSO segment pixel overlap, 0-8 pixels. */ u8 mso_pixel_overlap; + + /** + * @max_dsc_bpp: Maximum DSC target bitrate, if it is set to 0 the + * monitor's default value is used instead. + */ + u32 max_dsc_bpp; }; int drm_display_info_set_bus_formats(struct drm_display_info *info, -- cgit From 6e5abe94c6eb9b281398e39819217e8fdd1c336f Mon Sep 17 00:00:00 2001 From: Hamza Mahfooz Date: Mon, 24 Oct 2022 14:53:24 -0400 Subject: drm/amd/display: use max_dsc_bpp in amdgpu_dm Since, the quirk is handled in the DRM core now, we can use that value instead of the internal value. Reviewed-by: Harry Wentland Signed-off-by: Hamza Mahfooz Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 6 ++---- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c | 11 +++++++++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 9f2bf3488a78..94620f9b166c 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -5607,16 +5607,14 @@ static void apply_dsc_policy_for_stream(struct amdgpu_dm_connector *aconnector, { struct drm_connector *drm_connector = &aconnector->base; uint32_t link_bandwidth_kbps; - uint32_t max_dsc_target_bpp_limit_override = 0; struct dc *dc = sink->ctx->dc; uint32_t max_supported_bw_in_kbps, timing_bw_in_kbps; uint32_t dsc_max_supported_bw_in_kbps; + uint32_t max_dsc_target_bpp_limit_override = + drm_connector->display_info.max_dsc_bpp; link_bandwidth_kbps = dc_link_bandwidth_kbps(aconnector->dc_link, dc_link_get_link_cap(aconnector->dc_link)); - if (stream->link && stream->link->local_sink) - max_dsc_target_bpp_limit_override = - stream->link->local_sink->edid_caps.panel_patch.max_dsc_target_bpp_limit; /* Set DSC policy according to dsc_clock_en */ dc_dsc_policy_set_enable_dsc_when_not_needed( diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index 6ff96b4bdda5..d7907974f25a 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -642,15 +642,18 @@ static void set_dsc_configs_from_fairness_vars(struct dsc_mst_fairness_params *p int count, int k) { + struct drm_connector *drm_connector; int i; for (i = 0; i < count; i++) { + drm_connector = ¶ms[i].aconnector->base; + memset(¶ms[i].timing->dsc_cfg, 0, sizeof(params[i].timing->dsc_cfg)); if (vars[i + k].dsc_enabled && dc_dsc_compute_config( params[i].sink->ctx->dc->res_pool->dscs[0], ¶ms[i].sink->dsc_caps.dsc_dec_caps, params[i].sink->ctx->dc->debug.dsc_min_slice_height_override, - params[i].sink->edid_caps.panel_patch.max_dsc_target_bpp_limit, + drm_connector->display_info.max_dsc_bpp, 0, params[i].timing, ¶ms[i].timing->dsc_cfg)) { @@ -692,12 +695,16 @@ static int bpp_x16_from_pbn(struct dsc_mst_fairness_params param, int pbn) struct dc_dsc_config dsc_config; u64 kbps; + struct drm_connector *drm_connector = ¶m.aconnector->base; + uint32_t max_dsc_target_bpp_limit_override = + drm_connector->display_info.max_dsc_bpp; + kbps = div_u64((u64)pbn * 994 * 8 * 54, 64); dc_dsc_compute_config( param.sink->ctx->dc->res_pool->dscs[0], ¶m.sink->dsc_caps.dsc_dec_caps, param.sink->ctx->dc->debug.dsc_min_slice_height_override, - param.sink->edid_caps.panel_patch.max_dsc_target_bpp_limit, + max_dsc_target_bpp_limit_override, (int) kbps, param.timing, &dsc_config); return dsc_config.bits_per_pixel; -- cgit From 6803dfd3a69ccb318772463a86e40929fd4fbac7 Mon Sep 17 00:00:00 2001 From: Hamza Mahfooz Date: Tue, 25 Oct 2022 15:04:36 -0400 Subject: Revert "drm/amd/display: Limit max DSC target bpp for specific monitors" This reverts commit 55eea8ef98641f6e1e1c202bd3a49a57c1dd4059. This quirk is now handled in the DRM core, so we can drop all of the internal code that was added to handle it. Reviewed-by: Harry Wentland Signed-off-by: Hamza Mahfooz Signed-off-by: Alex Deucher --- .../drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 35 ---------------------- 1 file changed, 35 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c index f0b01c8dc4a6..f72c013d3a5b 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c @@ -42,39 +42,6 @@ #include "dm_helpers.h" #include "ddc_service_types.h" -struct monitor_patch_info { - unsigned int manufacturer_id; - unsigned int product_id; - void (*patch_func)(struct dc_edid_caps *edid_caps, unsigned int param); - unsigned int patch_param; -}; -static void set_max_dsc_bpp_limit(struct dc_edid_caps *edid_caps, unsigned int param); - -static const struct monitor_patch_info monitor_patch_table[] = { -{0x6D1E, 0x5BBF, set_max_dsc_bpp_limit, 15}, -{0x6D1E, 0x5B9A, set_max_dsc_bpp_limit, 15}, -}; - -static void set_max_dsc_bpp_limit(struct dc_edid_caps *edid_caps, unsigned int param) -{ - if (edid_caps) - edid_caps->panel_patch.max_dsc_target_bpp_limit = param; -} - -static int amdgpu_dm_patch_edid_caps(struct dc_edid_caps *edid_caps) -{ - int i, ret = 0; - - for (i = 0; i < ARRAY_SIZE(monitor_patch_table); i++) - if ((edid_caps->manufacturer_id == monitor_patch_table[i].manufacturer_id) - && (edid_caps->product_id == monitor_patch_table[i].product_id)) { - monitor_patch_table[i].patch_func(edid_caps, monitor_patch_table[i].patch_param); - ret++; - } - - return ret; -} - /* dm_helpers_parse_edid_caps * * Parse edid caps @@ -149,8 +116,6 @@ enum dc_edid_status dm_helpers_parse_edid_caps( kfree(sads); kfree(sadb); - amdgpu_dm_patch_edid_caps(edid_caps); - return result; } -- cgit From 7863c1552632223967f561654422cd2016c2520c Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 26 Oct 2022 14:03:55 -0500 Subject: drm/amd: Fail the suspend if resources can't be evicted MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a system does not have swap and memory is under 100% usage, amdgpu will fail to evict resources. Currently the suspend carries on proceeding to reset the GPU: ``` [drm] evicting device resources failed [drm:amdgpu_device_ip_suspend_phase2 [amdgpu]] *ERROR* suspend of IP block failed -12 [drm] free PSP TMR buffer [TTM] Failed allocating page table [drm] evicting device resources failed amdgpu 0000:03:00.0: amdgpu: MODE1 reset amdgpu 0000:03:00.0: amdgpu: GPU mode1 reset amdgpu 0000:03:00.0: amdgpu: GPU smu mode1 reset ``` At this point if the suspend actually succeeded I think that amdgpu would have recovered because the GPU would have power cut off and restored. However the kernel fails to continue the suspend from the memory pressure and amdgpu fails to run the "resume" from the aborted suspend. ``` ACPI: PM: Preparing to enter system sleep state S3 SLUB: Unable to allocate memory on node -1, gfp=0xdc0(GFP_KERNEL|__GFP_ZERO) cache: Acpi-State, object size: 80, buffer size: 80, default order: 0, min order: 0 node 0: slabs: 22, objs: 1122, free: 0 ACPI Error: AE_NO_MEMORY, Could not update object reference count (20210730/utdelete-651) [drm:psp_hw_start [amdgpu]] *ERROR* PSP load kdb failed! [drm:psp_resume [amdgpu]] *ERROR* PSP resume failed [drm:amdgpu_device_fw_loading [amdgpu]] *ERROR* resume of IP block failed -62 amdgpu 0000:03:00.0: amdgpu: amdgpu_device_ip_resume failed (-62). PM: dpm_run_callback(): pci_pm_resume+0x0/0x100 returns -62 amdgpu 0000:03:00.0: PM: failed to resume async: error -62 ``` To avoid this series of unfortunate events, fail amdgpu's suspend when the memory eviction fails. This will let the system gracefully recover and the user can try suspend again when the memory pressure is relieved. Reported-by: post@davidak.de Link: https://gitlab.freedesktop.org/drm/amd/-/issues/2223 Signed-off-by: Mario Limonciello Reviewed-by: Alex Deucher Acked-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 6f958603c8cc..ae10acede495 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -4060,15 +4060,18 @@ void amdgpu_device_fini_sw(struct amdgpu_device *adev) * at suspend time. * */ -static void amdgpu_device_evict_resources(struct amdgpu_device *adev) +static int amdgpu_device_evict_resources(struct amdgpu_device *adev) { + int ret; + /* No need to evict vram on APUs for suspend to ram or s2idle */ if ((adev->in_s3 || adev->in_s0ix) && (adev->flags & AMD_IS_APU)) - return; + return 0; - if (amdgpu_ttm_evict_resources(adev, TTM_PL_VRAM)) + ret = amdgpu_ttm_evict_resources(adev, TTM_PL_VRAM); + if (ret) DRM_WARN("evicting device resources failed\n"); - + return ret; } /* @@ -4118,7 +4121,9 @@ int amdgpu_device_suspend(struct drm_device *dev, bool fbcon) if (!adev->in_s0ix) amdgpu_amdkfd_suspend(adev, adev->in_runpm); - amdgpu_device_evict_resources(adev); + r = amdgpu_device_evict_resources(adev); + if (r) + return r; amdgpu_fence_driver_hw_fini(adev); -- cgit From 087b8542c0b0d26066547bd2a2b08c58fd63df25 Mon Sep 17 00:00:00 2001 From: Graham Sider Date: Wed, 26 Oct 2022 15:08:24 -0400 Subject: drm/amdgpu: disable GFXOFF during compute for GFX11 Temporary workaround to fix issues observed in some compute applications when GFXOFF is enabled on GFX11. Signed-off-by: Graham Sider Acked-by: Alex Deucher Reviewed-by: Harish Kasiviswanathan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 37db39ba8718..0d764c15f6bf 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -706,6 +706,13 @@ err: void amdgpu_amdkfd_set_compute_idle(struct amdgpu_device *adev, bool idle) { + /* Temporary workaround to fix issues observed in some + * compute applications when GFXOFF is enabled on GFX11. + */ + if (IP_VERSION_MAJ(adev->ip_versions[GC_HWIP][0]) == 11) { + pr_debug("GFXOFF is %s\n", idle ? "enabled" : "disabled"); + amdgpu_gfx_off_ctrl(adev, idle); + } amdgpu_dpm_switch_power_profile(adev, PP_SMC_POWER_PROFILE_COMPUTE, !idle); -- cgit From d69a3b762dc4c9fe257b89c2a9ae809770a81d38 Mon Sep 17 00:00:00 2001 From: Mukul Joshi Date: Mon, 9 May 2022 10:44:10 -0400 Subject: drm/amdkfd: Cleanup kfd_dev struct MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cleanup kfd_dev struct by removing ddev and pdev as both drm_device and pci_dev can be fetched from amdgpu_device. Signed-off-by: Mukul Joshi Tested-by: Amber Lin Reviewed-by: Felix Kuehling Acked-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h | 3 +-- drivers/gpu/drm/amd/amdkfd/kfd_crat.c | 12 ++++++------ drivers/gpu/drm/amd/amdkfd/kfd_device.c | 16 ++++++---------- drivers/gpu/drm/amd/amdkfd/kfd_iommu.c | 29 +++++++++++++++-------------- drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 4 +--- drivers/gpu/drm/amd/amdkfd/kfd_process.c | 12 ++++++------ drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 2 +- drivers/gpu/drm/amd/amdkfd/kfd_topology.c | 25 ++++++++++++------------- 9 files changed, 49 insertions(+), 56 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 0d764c15f6bf..8816853e50c0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -195,7 +195,7 @@ void amdgpu_amdkfd_device_init(struct amdgpu_device *adev) } adev->kfd.init_complete = kgd2kfd_device_init(adev->kfd.dev, - adev_to_drm(adev), &gpu_resources); + &gpu_resources); amdgpu_amdkfd_total_mem_size += adev->gmc.real_vram_size; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h index 647220a8762d..f50e3ba4d7a5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h @@ -353,7 +353,6 @@ int kgd2kfd_init(void); void kgd2kfd_exit(void); struct kfd_dev *kgd2kfd_probe(struct amdgpu_device *adev, bool vf); bool kgd2kfd_device_init(struct kfd_dev *kfd, - struct drm_device *ddev, const struct kgd2kfd_shared_resources *gpu_resources); void kgd2kfd_device_exit(struct kfd_dev *kfd); void kgd2kfd_suspend(struct kfd_dev *kfd, bool run_pm); @@ -381,7 +380,7 @@ struct kfd_dev *kgd2kfd_probe(struct amdgpu_device *adev, bool vf) } static inline -bool kgd2kfd_device_init(struct kfd_dev *kfd, struct drm_device *ddev, +bool kgd2kfd_device_init(struct kfd_dev *kfd, const struct kgd2kfd_shared_resources *gpu_resources) { return false; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c index 5e0bad7e0b77..339f60a4cddd 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c @@ -2114,8 +2114,8 @@ static void kfd_find_numa_node_in_srat(struct kfd_dev *kdev) struct acpi_table_header *table_header = NULL; struct acpi_subtable_header *sub_header = NULL; unsigned long table_end, subtable_len; - u32 pci_id = pci_domain_nr(kdev->pdev->bus) << 16 | - pci_dev_id(kdev->pdev); + u32 pci_id = pci_domain_nr(kdev->adev->pdev->bus) << 16 | + pci_dev_id(kdev->adev->pdev); u32 bdf; acpi_status status; struct acpi_srat_cpu_affinity *cpu; @@ -2190,7 +2190,7 @@ static void kfd_find_numa_node_in_srat(struct kfd_dev *kdev) numa_node = 0; if (numa_node != NUMA_NO_NODE) - set_dev_node(&kdev->pdev->dev, numa_node); + set_dev_node(&kdev->adev->pdev->dev, numa_node); } #endif @@ -2251,14 +2251,14 @@ static int kfd_fill_gpu_direct_io_link_to_cpu(int *avail_size, sub_type_hdr->proximity_domain_from = proximity_domain; #ifdef CONFIG_ACPI_NUMA - if (kdev->pdev->dev.numa_node == NUMA_NO_NODE) + if (kdev->adev->pdev->dev.numa_node == NUMA_NO_NODE) kfd_find_numa_node_in_srat(kdev); #endif #ifdef CONFIG_NUMA - if (kdev->pdev->dev.numa_node == NUMA_NO_NODE) + if (kdev->adev->pdev->dev.numa_node == NUMA_NO_NODE) sub_type_hdr->proximity_domain_to = 0; else - sub_type_hdr->proximity_domain_to = kdev->pdev->dev.numa_node; + sub_type_hdr->proximity_domain_to = kdev->adev->pdev->dev.numa_node; #else sub_type_hdr->proximity_domain_to = 0; #endif diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index 65a1d4f9004b..ee8e5f8b007d 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -227,7 +227,6 @@ struct kfd_dev *kgd2kfd_probe(struct amdgpu_device *adev, bool vf) { struct kfd_dev *kfd = NULL; const struct kfd2kgd_calls *f2g = NULL; - struct pci_dev *pdev = adev->pdev; uint32_t gfx_target_version = 0; switch (adev->asic_type) { @@ -429,7 +428,6 @@ struct kfd_dev *kgd2kfd_probe(struct amdgpu_device *adev, bool vf) kfd->adev = adev; kfd_device_info_init(kfd, vf, gfx_target_version); - kfd->pdev = pdev; kfd->init_complete = false; kfd->kfd2kgd = f2g; atomic_set(&kfd->compute_profile, 0); @@ -511,12 +509,10 @@ static void kfd_smi_init(struct kfd_dev *dev) } bool kgd2kfd_device_init(struct kfd_dev *kfd, - struct drm_device *ddev, const struct kgd2kfd_shared_resources *gpu_resources) { unsigned int size, map_process_packet_size; - kfd->ddev = ddev; kfd->mec_fw_version = amdgpu_amdkfd_get_fw_version(kfd->adev, KGD_ENGINE_MEC1); kfd->mec2_fw_version = amdgpu_amdkfd_get_fw_version(kfd->adev, @@ -541,7 +537,7 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd, kfd->mec_fw_version < kfd->device_info.no_atomic_fw_version)) { dev_info(kfd_device, "skipped device %x:%x, PCI rejects atomics %d<%d\n", - kfd->pdev->vendor, kfd->pdev->device, + kfd->adev->pdev->vendor, kfd->adev->pdev->device, kfd->mec_fw_version, kfd->device_info.no_atomic_fw_version); return false; @@ -650,8 +646,8 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd, kfd_smi_init(kfd); kfd->init_complete = true; - dev_info(kfd_device, "added device %x:%x\n", kfd->pdev->vendor, - kfd->pdev->device); + dev_info(kfd_device, "added device %x:%x\n", kfd->adev->pdev->vendor, + kfd->adev->pdev->device); pr_debug("Starting kfd with the following scheduling policy %d\n", kfd->dqm->sched_policy); @@ -676,7 +672,7 @@ alloc_gtt_mem_failure: amdgpu_amdkfd_free_gws(kfd->adev, kfd->gws); dev_err(kfd_device, "device %x:%x NOT added due to errors\n", - kfd->pdev->vendor, kfd->pdev->device); + kfd->adev->pdev->vendor, kfd->adev->pdev->device); out: return kfd->init_complete; } @@ -789,7 +785,7 @@ int kgd2kfd_resume_iommu(struct kfd_dev *kfd) if (err) dev_err(kfd_device, "Failed to resume IOMMU for device %x:%x\n", - kfd->pdev->vendor, kfd->pdev->device); + kfd->adev->pdev->vendor, kfd->adev->pdev->device); return err; } @@ -801,7 +797,7 @@ static int kfd_resume(struct kfd_dev *kfd) if (err) dev_err(kfd_device, "Error starting queue manager for device %x:%x\n", - kfd->pdev->vendor, kfd->pdev->device); + kfd->adev->pdev->vendor, kfd->adev->pdev->device); return err; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_iommu.c b/drivers/gpu/drm/amd/amdkfd/kfd_iommu.c index fbd0afe4da42..ec1bf611624e 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_iommu.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_iommu.c @@ -49,7 +49,7 @@ int kfd_iommu_check_device(struct kfd_dev *kfd) return -ENODEV; iommu_info.flags = 0; - err = amd_iommu_device_info(kfd->pdev, &iommu_info); + err = amd_iommu_device_info(kfd->adev->pdev, &iommu_info); if (err) return err; @@ -71,7 +71,7 @@ int kfd_iommu_device_init(struct kfd_dev *kfd) return 0; iommu_info.flags = 0; - err = amd_iommu_device_info(kfd->pdev, &iommu_info); + err = amd_iommu_device_info(kfd->adev->pdev, &iommu_info); if (err < 0) { dev_err(kfd_device, "error getting iommu info. is the iommu enabled?\n"); @@ -121,7 +121,7 @@ int kfd_iommu_bind_process_to_device(struct kfd_process_device *pdd) return -EINVAL; } - err = amd_iommu_bind_pasid(dev->pdev, p->pasid, p->lead_thread); + err = amd_iommu_bind_pasid(dev->adev->pdev, p->pasid, p->lead_thread); if (!err) pdd->bound = PDD_BOUND; @@ -139,7 +139,8 @@ void kfd_iommu_unbind_process(struct kfd_process *p) for (i = 0; i < p->n_pdds; i++) if (p->pdds[i]->bound == PDD_BOUND) - amd_iommu_unbind_pasid(p->pdds[i]->dev->pdev, p->pasid); + amd_iommu_unbind_pasid(p->pdds[i]->dev->adev->pdev, + p->pasid); } /* Callback for process shutdown invoked by the IOMMU driver */ @@ -222,7 +223,7 @@ static int kfd_bind_processes_to_device(struct kfd_dev *kfd) continue; } - err = amd_iommu_bind_pasid(kfd->pdev, p->pasid, + err = amd_iommu_bind_pasid(kfd->adev->pdev, p->pasid, p->lead_thread); if (err < 0) { pr_err("Unexpected pasid 0x%x binding failure\n", @@ -282,9 +283,9 @@ void kfd_iommu_suspend(struct kfd_dev *kfd) kfd_unbind_processes_from_device(kfd); - amd_iommu_set_invalidate_ctx_cb(kfd->pdev, NULL); - amd_iommu_set_invalid_ppr_cb(kfd->pdev, NULL); - amd_iommu_free_device(kfd->pdev); + amd_iommu_set_invalidate_ctx_cb(kfd->adev->pdev, NULL); + amd_iommu_set_invalid_ppr_cb(kfd->adev->pdev, NULL); + amd_iommu_free_device(kfd->adev->pdev); } /** kfd_iommu_resume - Restore IOMMU after resume @@ -302,20 +303,20 @@ int kfd_iommu_resume(struct kfd_dev *kfd) pasid_limit = kfd_get_pasid_limit(); - err = amd_iommu_init_device(kfd->pdev, pasid_limit); + err = amd_iommu_init_device(kfd->adev->pdev, pasid_limit); if (err) return -ENXIO; - amd_iommu_set_invalidate_ctx_cb(kfd->pdev, + amd_iommu_set_invalidate_ctx_cb(kfd->adev->pdev, iommu_pasid_shutdown_callback); - amd_iommu_set_invalid_ppr_cb(kfd->pdev, + amd_iommu_set_invalid_ppr_cb(kfd->adev->pdev, iommu_invalid_ppr_cb); err = kfd_bind_processes_to_device(kfd); if (err) { - amd_iommu_set_invalidate_ctx_cb(kfd->pdev, NULL); - amd_iommu_set_invalid_ppr_cb(kfd->pdev, NULL); - amd_iommu_free_device(kfd->pdev); + amd_iommu_set_invalidate_ctx_cb(kfd->adev->pdev, NULL); + amd_iommu_set_invalid_ppr_cb(kfd->adev->pdev, NULL); + amd_iommu_free_device(kfd->adev->pdev); return err; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index bf610e3b683b..552c3ac85a13 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -254,8 +254,6 @@ struct kfd_dev { struct amdgpu_device *adev; struct kfd_device_info device_info; - struct pci_dev *pdev; - struct drm_device *ddev; unsigned int id; /* topology stub index */ @@ -1365,7 +1363,7 @@ void kfd_dec_compute_active(struct kfd_dev *dev); static inline int kfd_devcgroup_check_permission(struct kfd_dev *kfd) { #if defined(CONFIG_CGROUP_DEVICE) || defined(CONFIG_CGROUP_BPF) - struct drm_device *ddev = kfd->ddev; + struct drm_device *ddev = adev_to_drm(kfd->adev); return devcgroup_check_permission(DEVCG_DEV_CHAR, DRM_MAJOR, ddev->render->index, diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c index 951b63677248..a26257171ab7 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c @@ -1050,8 +1050,8 @@ static void kfd_process_destroy_pdds(struct kfd_process *p) * for auto suspend */ if (pdd->runtime_inuse) { - pm_runtime_mark_last_busy(pdd->dev->ddev->dev); - pm_runtime_put_autosuspend(pdd->dev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(pdd->dev->adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(pdd->dev->adev)->dev); pdd->runtime_inuse = false; } @@ -1633,9 +1633,9 @@ struct kfd_process_device *kfd_bind_process_to_device(struct kfd_dev *dev, * pdd is destroyed. */ if (!pdd->runtime_inuse) { - err = pm_runtime_get_sync(dev->ddev->dev); + err = pm_runtime_get_sync(adev_to_drm(dev->adev)->dev); if (err < 0) { - pm_runtime_put_autosuspend(dev->ddev->dev); + pm_runtime_put_autosuspend(adev_to_drm(dev->adev)->dev); return ERR_PTR(err); } } @@ -1655,8 +1655,8 @@ struct kfd_process_device *kfd_bind_process_to_device(struct kfd_dev *dev, out: /* balance runpm reference count and exit with error */ if (!pdd->runtime_inuse) { - pm_runtime_mark_last_busy(dev->ddev->dev); - pm_runtime_put_autosuspend(dev->ddev->dev); + pm_runtime_mark_last_busy(adev_to_drm(dev->adev)->dev); + pm_runtime_put_autosuspend(adev_to_drm(dev->adev)->dev); } return ERR_PTR(err); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index 0100812478b2..afe7c4998676 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -259,7 +259,7 @@ void svm_range_free_dma_mappings(struct svm_range *prange) pr_debug("failed to find device idx %d\n", gpuidx); continue; } - dev = &pdd->dev->pdev->dev; + dev = &pdd->dev->adev->pdev->dev; svm_range_dma_unmap(dev, dma_addr, 0, prange->npages); kvfree(dma_addr); prange->dma_addr[gpuidx] = NULL; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c index 3f0a4a415907..ec8c9c10d348 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c @@ -115,7 +115,7 @@ struct kfd_dev *kfd_device_by_pci_dev(const struct pci_dev *pdev) down_read(&topology_lock); list_for_each_entry(top_dev, &topology_device_list, list) - if (top_dev->gpu && top_dev->gpu->pdev == pdev) { + if (top_dev->gpu && top_dev->gpu->adev->pdev == pdev) { device = top_dev->gpu; break; } @@ -1169,13 +1169,12 @@ static uint32_t kfd_generate_gpu_id(struct kfd_dev *gpu) local_mem_size = gpu->local_mem_info.local_mem_size_private + gpu->local_mem_info.local_mem_size_public; - - buf[0] = gpu->pdev->devfn; - buf[1] = gpu->pdev->subsystem_vendor | - (gpu->pdev->subsystem_device << 16); - buf[2] = pci_domain_nr(gpu->pdev->bus); - buf[3] = gpu->pdev->device; - buf[4] = gpu->pdev->bus->number; + buf[0] = gpu->adev->pdev->devfn; + buf[1] = gpu->adev->pdev->subsystem_vendor | + (gpu->adev->pdev->subsystem_device << 16); + buf[2] = pci_domain_nr(gpu->adev->pdev->bus); + buf[3] = gpu->adev->pdev->device; + buf[4] = gpu->adev->pdev->bus->number; buf[5] = lower_32_bits(local_mem_size); buf[6] = upper_32_bits(local_mem_size); @@ -1269,7 +1268,7 @@ static void kfd_set_iolink_no_atomics(struct kfd_topology_device *dev, if (target_gpu_dev) { uint32_t cap; - pcie_capability_read_dword(target_gpu_dev->gpu->pdev, + pcie_capability_read_dword(target_gpu_dev->gpu->adev->pdev, PCI_EXP_DEVCAP2, &cap); if (!(cap & (PCI_EXP_DEVCAP2_ATOMIC_COMP32 | @@ -1688,13 +1687,13 @@ int kfd_topology_add_device(struct kfd_dev *gpu) cu_info.num_shader_arrays_per_engine; dev->node_props.gfx_target_version = gpu->device_info.gfx_target_version; - dev->node_props.vendor_id = gpu->pdev->vendor; - dev->node_props.device_id = gpu->pdev->device; + dev->node_props.vendor_id = gpu->adev->pdev->vendor; + dev->node_props.device_id = gpu->adev->pdev->device; dev->node_props.capability |= ((dev->gpu->adev->rev_id << HSA_CAP_ASIC_REVISION_SHIFT) & HSA_CAP_ASIC_REVISION_MASK); - dev->node_props.location_id = pci_dev_id(gpu->pdev); - dev->node_props.domain = pci_domain_nr(gpu->pdev->bus); + dev->node_props.location_id = pci_dev_id(gpu->adev->pdev); + dev->node_props.domain = pci_domain_nr(gpu->adev->pdev->bus); dev->node_props.max_engine_clk_fcompute = amdgpu_amdkfd_get_max_engine_clock_in_mhz(dev->gpu->adev); dev->node_props.max_engine_clk_ccompute = -- cgit From 5156133094dd6b57325fa107aca8be5be679452e Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Wed, 26 Oct 2022 15:01:09 +0800 Subject: drm/amd/display: make wake_up_aux_channel static This symbol is not used outside of dc_link_dp.c, so marks it static. drivers/gpu/drm/amd/amdgpu/../display/dc/core/dc_link_dp.c:5230:16: warning: no previous prototype for function 'wake_up_aux_channel'. Link: https://bugzilla.openanolis.cn/show_bug.cgi?id=2581 Reported-by: Abaci Robot Signed-off-by: Jiapeng Chong Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c index 420119efcf5f..e5ab751a5ca1 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -5227,7 +5227,7 @@ static void retrieve_cable_id(struct dc_link *link) &link->dpcd_caps.cable_id, &usbc_cable_id); } -enum dc_status wake_up_aux_channel(struct dc_link *link) +static enum dc_status wake_up_aux_channel(struct dc_link *link) { enum dc_status status = DC_ERROR_UNEXPECTED; uint32_t aux_channel_retry_cnt = 0; -- cgit From 0645b7a64b908ef5cdbf9f117f53d283983fe285 Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Wed, 26 Oct 2022 15:01:10 +0800 Subject: drm/amd/display: Modify mismatched function name No functional modification involved. drivers/gpu/drm/amd/amdgpu/../display/dc/dc_dmub_srv.c:615: warning: expecting prototype for setup_subvp_dmub_command(). Prototype was for populate_subvp_cmd_pipe_info() instead. Link: https://bugzilla.openanolis.cn/show_bug.cgi?id=2587 Reported-by: Abaci Robot Signed-off-by: Jiapeng Chong Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c index 774e06936661..67eef5beab95 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c @@ -595,7 +595,7 @@ static void update_subvp_prefetch_end_to_mall_start(struct dc *dc, } /** - * setup_subvp_dmub_command - Helper to populate the SubVP pipe info for the DMUB subvp command + * populate_subvp_cmd_pipe_info - Helper to populate the SubVP pipe info for the DMUB subvp command * * @dc: [in] current dc state * @context: [in] new dc state -- cgit From 682aa4373f156512245d391b15dde798d4594a13 Mon Sep 17 00:00:00 2001 From: Umesh Nerlige Ramappa Date: Wed, 26 Oct 2022 22:20:47 +0000 Subject: drm/i915/perf: Fix OA filtering logic for GuC mode With GuC mode of submission, GuC is in control of defining the context id field that is part of the OA reports. To filter reports, UMD and KMD must know what sw context id was chosen by GuC. There is not interface between KMD and GuC to determine this, so read the upper-dword of EXECLIST_STATUS to filter/squash OA reports for the specific context. v2: Explain guc id stealing w.r.t OA use case Signed-off-by: Umesh Nerlige Ramappa Reviewed-by: Ashutosh Dixit Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20221026222102.5526-2-umesh.nerlige.ramappa@intel.com --- drivers/gpu/drm/i915/gt/intel_lrc.h | 2 + drivers/gpu/drm/i915/i915_perf.c | 144 +++++++++++++++++++++++++++++++----- 2 files changed, 127 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.h b/drivers/gpu/drm/i915/gt/intel_lrc.h index a390f0813c8b..7111bae759f3 100644 --- a/drivers/gpu/drm/i915/gt/intel_lrc.h +++ b/drivers/gpu/drm/i915/gt/intel_lrc.h @@ -110,6 +110,8 @@ enum { #define XEHP_SW_CTX_ID_WIDTH 16 #define XEHP_SW_COUNTER_SHIFT 58 #define XEHP_SW_COUNTER_WIDTH 6 +#define GEN12_GUC_SW_CTX_ID_SHIFT 39 +#define GEN12_GUC_SW_CTX_ID_WIDTH 16 static inline void lrc_runtime_start(struct intel_context *ce) { diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index 15816df916c7..255335868b6a 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -1231,6 +1231,128 @@ retry: return stream->pinned_ctx; } +static int +__store_reg_to_mem(struct i915_request *rq, i915_reg_t reg, u32 ggtt_offset) +{ + u32 *cs, cmd; + + cmd = MI_STORE_REGISTER_MEM | MI_SRM_LRM_GLOBAL_GTT; + if (GRAPHICS_VER(rq->engine->i915) >= 8) + cmd++; + + cs = intel_ring_begin(rq, 4); + if (IS_ERR(cs)) + return PTR_ERR(cs); + + *cs++ = cmd; + *cs++ = i915_mmio_reg_offset(reg); + *cs++ = ggtt_offset; + *cs++ = 0; + + intel_ring_advance(rq, cs); + + return 0; +} + +static int +__read_reg(struct intel_context *ce, i915_reg_t reg, u32 ggtt_offset) +{ + struct i915_request *rq; + int err; + + rq = i915_request_create(ce); + if (IS_ERR(rq)) + return PTR_ERR(rq); + + i915_request_get(rq); + + err = __store_reg_to_mem(rq, reg, ggtt_offset); + + i915_request_add(rq); + if (!err && i915_request_wait(rq, 0, HZ / 2) < 0) + err = -ETIME; + + i915_request_put(rq); + + return err; +} + +static int +gen12_guc_sw_ctx_id(struct intel_context *ce, u32 *ctx_id) +{ + struct i915_vma *scratch; + u32 *val; + int err; + + scratch = __vm_create_scratch_for_read_pinned(&ce->engine->gt->ggtt->vm, 4); + if (IS_ERR(scratch)) + return PTR_ERR(scratch); + + err = i915_vma_sync(scratch); + if (err) + goto err_scratch; + + err = __read_reg(ce, RING_EXECLIST_STATUS_HI(ce->engine->mmio_base), + i915_ggtt_offset(scratch)); + if (err) + goto err_scratch; + + val = i915_gem_object_pin_map_unlocked(scratch->obj, I915_MAP_WB); + if (IS_ERR(val)) { + err = PTR_ERR(val); + goto err_scratch; + } + + *ctx_id = *val; + i915_gem_object_unpin_map(scratch->obj); + +err_scratch: + i915_vma_unpin_and_release(&scratch, 0); + return err; +} + +/* + * For execlist mode of submission, pick an unused context id + * 0 - (NUM_CONTEXT_TAG -1) are used by other contexts + * XXX_MAX_CONTEXT_HW_ID is used by idle context + * + * For GuC mode of submission read context id from the upper dword of the + * EXECLIST_STATUS register. Note that we read this value only once and expect + * that the value stays fixed for the entire OA use case. There are cases where + * GuC KMD implementation may deregister a context to reuse it's context id, but + * we prevent that from happening to the OA context by pinning it. + */ +static int gen12_get_render_context_id(struct i915_perf_stream *stream) +{ + u32 ctx_id, mask; + int ret; + + if (intel_engine_uses_guc(stream->engine)) { + ret = gen12_guc_sw_ctx_id(stream->pinned_ctx, &ctx_id); + if (ret) + return ret; + + mask = ((1U << GEN12_GUC_SW_CTX_ID_WIDTH) - 1) << + (GEN12_GUC_SW_CTX_ID_SHIFT - 32); + } else if (GRAPHICS_VER_FULL(stream->engine->i915) >= IP_VER(12, 50)) { + ctx_id = (XEHP_MAX_CONTEXT_HW_ID - 1) << + (XEHP_SW_CTX_ID_SHIFT - 32); + + mask = ((1U << XEHP_SW_CTX_ID_WIDTH) - 1) << + (XEHP_SW_CTX_ID_SHIFT - 32); + } else { + ctx_id = (GEN12_MAX_CONTEXT_HW_ID - 1) << + (GEN11_SW_CTX_ID_SHIFT - 32); + + mask = ((1U << GEN11_SW_CTX_ID_WIDTH) - 1) << + (GEN11_SW_CTX_ID_SHIFT - 32); + } + stream->specific_ctx_id = ctx_id & mask; + stream->specific_ctx_id_mask = mask; + + return 0; +} + /** * oa_get_render_ctx_id - determine and hold ctx hw id * @stream: An i915-perf stream opened for OA metrics @@ -1244,6 +1366,7 @@ retry: static int oa_get_render_ctx_id(struct i915_perf_stream *stream) { struct intel_context *ce; + int ret = 0; ce = oa_pin_context(stream); if (IS_ERR(ce)) @@ -1290,24 +1413,7 @@ static int oa_get_render_ctx_id(struct i915_perf_stream *stream) case 11: case 12: - if (GRAPHICS_VER_FULL(ce->engine->i915) >= IP_VER(12, 50)) { - stream->specific_ctx_id_mask = - ((1U << XEHP_SW_CTX_ID_WIDTH) - 1) << - (XEHP_SW_CTX_ID_SHIFT - 32); - stream->specific_ctx_id = - (XEHP_MAX_CONTEXT_HW_ID - 1) << - (XEHP_SW_CTX_ID_SHIFT - 32); - } else { - stream->specific_ctx_id_mask = - ((1U << GEN11_SW_CTX_ID_WIDTH) - 1) << (GEN11_SW_CTX_ID_SHIFT - 32); - /* - * Pick an unused context id - * 0 - BITS_PER_LONG are used by other contexts - * GEN12_MAX_CONTEXT_HW_ID (0x7ff) is used by idle context - */ - stream->specific_ctx_id = - (GEN12_MAX_CONTEXT_HW_ID - 1) << (GEN11_SW_CTX_ID_SHIFT - 32); - } + ret = gen12_get_render_context_id(stream); break; default: @@ -1321,7 +1427,7 @@ static int oa_get_render_ctx_id(struct i915_perf_stream *stream) stream->specific_ctx_id, stream->specific_ctx_id_mask); - return 0; + return ret; } /** -- cgit From 81d5f7d91492aa3a362937926cdc094a7dc1e4b7 Mon Sep 17 00:00:00 2001 From: Umesh Nerlige Ramappa Date: Wed, 26 Oct 2022 22:20:48 +0000 Subject: drm/i915/perf: Add 32-bit OAG and OAR formats for DG2 Add new OA formats for DG2. MR: https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/18893 v2: - Update commit title (Ashutosh) - Coding style fixes (Lionel) - 64 bit OA formats need UMD changes in GPUvis, drop for now and send in a separate series with UMD changes v3: - Update commit message to drop 64 bit related description Signed-off-by: Umesh Nerlige Ramappa Reviewed-by: Lionel Landwerlin #1 Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20221026222102.5526-3-umesh.nerlige.ramappa@intel.com --- drivers/gpu/drm/i915/i915_perf.c | 7 +++++++ include/uapi/drm/i915_drm.h | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index 255335868b6a..2b772a6b1cd6 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -320,6 +320,8 @@ static const struct i915_oa_format oa_formats[I915_OA_FORMAT_MAX] = { [I915_OA_FORMAT_A12] = { 0, 64 }, [I915_OA_FORMAT_A12_B8_C8] = { 2, 128 }, [I915_OA_FORMAT_A32u40_A4u32_B8_C8] = { 5, 256 }, + [I915_OAR_FORMAT_A32u40_A4u32_B8_C8] = { 5, 256 }, + [I915_OA_FORMAT_A24u40_A14u32_B8_C8] = { 5, 256 }, }; #define SAMPLE_OA_REPORT (1<<0) @@ -4515,6 +4517,11 @@ static void oa_init_supported_formats(struct i915_perf *perf) oa_format_add(perf, I915_OA_FORMAT_C4_B8); break; + case INTEL_DG2: + oa_format_add(perf, I915_OAR_FORMAT_A32u40_A4u32_B8_C8); + oa_format_add(perf, I915_OA_FORMAT_A24u40_A14u32_B8_C8); + break; + default: MISSING_CASE(platform); } diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index 08d69e36fb66..b946674c68cc 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -2666,6 +2666,10 @@ enum drm_i915_oa_format { I915_OA_FORMAT_A12_B8_C8, I915_OA_FORMAT_A32u40_A4u32_B8_C8, + /* DG2 */ + I915_OAR_FORMAT_A32u40_A4u32_B8_C8, + I915_OA_FORMAT_A24u40_A14u32_B8_C8, + I915_OA_FORMAT_MAX /* non-ABI */ }; -- cgit From 2d9da585216bd151779c45bb7dc736ea4e9e0249 Mon Sep 17 00:00:00 2001 From: Umesh Nerlige Ramappa Date: Wed, 26 Oct 2022 22:20:49 +0000 Subject: drm/i915/perf: Fix noa wait predication for DG2 Predication for batch buffer commands changed in XEHPSDV. MI_BATCH_BUFFER_START predicates based on MI_SET_PREDICATE_RESULT register. The MI_SET_PREDICATE_RESULT register can only be modified with MI_SET_PREDICATE command. When configured, the MI_SET_PREDICATE command sets MI_SET_PREDICATE_RESULT based on bit 0 of MI_PREDICATE_RESULT_2. Use this to configure predication in noa_wait. Signed-off-by: Umesh Nerlige Ramappa Reviewed-by: Ashutosh Dixit Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20221026222102.5526-4-umesh.nerlige.ramappa@intel.com --- drivers/gpu/drm/i915/gt/intel_engine_regs.h | 1 + drivers/gpu/drm/i915/i915_perf.c | 24 ++++++++++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_engine_regs.h b/drivers/gpu/drm/i915/gt/intel_engine_regs.h index fe1a0d5fd4b1..ee3efd06ee54 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_regs.h +++ b/drivers/gpu/drm/i915/gt/intel_engine_regs.h @@ -201,6 +201,7 @@ #define RING_CONTEXT_STATUS_PTR(base) _MMIO((base) + 0x3a0) #define RING_CTX_TIMESTAMP(base) _MMIO((base) + 0x3a8) /* gen8+ */ #define RING_PREDICATE_RESULT(base) _MMIO((base) + 0x3b8) +#define MI_PREDICATE_RESULT_2_ENGINE(base) _MMIO((base) + 0x3bc) #define RING_FORCE_TO_NONPRIV(base, i) _MMIO(((base) + 0x4D0) + (i) * 4) #define RING_FORCE_TO_NONPRIV_DENY REG_BIT(30) #define RING_FORCE_TO_NONPRIV_ADDRESS_MASK REG_GENMASK(25, 2) diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index 2b772a6b1cd6..e68666b44a72 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -286,6 +286,7 @@ static u32 i915_perf_stream_paranoid = true; #define OAREPORT_REASON_CTX_SWITCH (1<<3) #define OAREPORT_REASON_CLK_RATIO (1<<5) +#define HAS_MI_SET_PREDICATE(i915) (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50)) /* For sysctl proc_dointvec_minmax of i915_oa_max_sample_rate * @@ -1760,6 +1761,9 @@ static int alloc_noa_wait(struct i915_perf_stream *stream) DELTA_TARGET, N_CS_GPR }; + i915_reg_t mi_predicate_result = HAS_MI_SET_PREDICATE(i915) ? + MI_PREDICATE_RESULT_2_ENGINE(base) : + MI_PREDICATE_RESULT_1(RENDER_RING_BASE); bo = i915_gem_object_create_internal(i915, 4096); if (IS_ERR(bo)) { @@ -1797,7 +1801,7 @@ retry: stream, cs, true /* save */, CS_GPR(i), INTEL_GT_SCRATCH_FIELD_PERF_CS_GPR + 8 * i, 2); cs = save_restore_register( - stream, cs, true /* save */, MI_PREDICATE_RESULT_1(RENDER_RING_BASE), + stream, cs, true /* save */, mi_predicate_result, INTEL_GT_SCRATCH_FIELD_PERF_PREDICATE_RESULT_1, 1); /* First timestamp snapshot location. */ @@ -1851,7 +1855,10 @@ retry: */ *cs++ = MI_LOAD_REGISTER_REG | (3 - 2); *cs++ = i915_mmio_reg_offset(CS_GPR(JUMP_PREDICATE)); - *cs++ = i915_mmio_reg_offset(MI_PREDICATE_RESULT_1(RENDER_RING_BASE)); + *cs++ = i915_mmio_reg_offset(mi_predicate_result); + + if (HAS_MI_SET_PREDICATE(i915)) + *cs++ = MI_SET_PREDICATE | 1; /* Restart from the beginning if we had timestamps roll over. */ *cs++ = (GRAPHICS_VER(i915) < 8 ? @@ -1861,6 +1868,9 @@ retry: *cs++ = i915_ggtt_offset(vma) + (ts0 - batch) * 4; *cs++ = 0; + if (HAS_MI_SET_PREDICATE(i915)) + *cs++ = MI_SET_PREDICATE; + /* * Now add the diff between to previous timestamps and add it to : * (((1 * << 64) - 1) - delay_ns) @@ -1888,7 +1898,10 @@ retry: */ *cs++ = MI_LOAD_REGISTER_REG | (3 - 2); *cs++ = i915_mmio_reg_offset(CS_GPR(JUMP_PREDICATE)); - *cs++ = i915_mmio_reg_offset(MI_PREDICATE_RESULT_1(RENDER_RING_BASE)); + *cs++ = i915_mmio_reg_offset(mi_predicate_result); + + if (HAS_MI_SET_PREDICATE(i915)) + *cs++ = MI_SET_PREDICATE | 1; /* Predicate the jump. */ *cs++ = (GRAPHICS_VER(i915) < 8 ? @@ -1898,13 +1911,16 @@ retry: *cs++ = i915_ggtt_offset(vma) + (jump - batch) * 4; *cs++ = 0; + if (HAS_MI_SET_PREDICATE(i915)) + *cs++ = MI_SET_PREDICATE; + /* Restore registers. */ for (i = 0; i < N_CS_GPR; i++) cs = save_restore_register( stream, cs, false /* restore */, CS_GPR(i), INTEL_GT_SCRATCH_FIELD_PERF_CS_GPR + 8 * i, 2); cs = save_restore_register( - stream, cs, false /* restore */, MI_PREDICATE_RESULT_1(RENDER_RING_BASE), + stream, cs, false /* restore */, mi_predicate_result, INTEL_GT_SCRATCH_FIELD_PERF_PREDICATE_RESULT_1, 1); /* And return to the ring. */ -- cgit From a5c3a3cbf0292b1772436e7da0fdda7d818b177d Mon Sep 17 00:00:00 2001 From: Umesh Nerlige Ramappa Date: Wed, 26 Oct 2022 22:20:50 +0000 Subject: drm/i915/perf: Determine gen12 oa ctx offset at runtime Some SKUs of same gen12 platform may have different oactxctrl offsets. For gen12, determine oactxctrl offsets at runtime. v2: (Lionel) - Move MI definitions to intel_gpu_commands.h - Ensure __find_reg_in_lri does read past context image size v3: (Ashutosh) - Drop unnecessary use of double underscores - fix find_reg_in_lri - Return error if oa context offset is U32_MAX - Error out if oa_ctx_ctrl_offset does not find offset v4: (Ashutosh) - Warn on odd MI LRI_LEN - Remove unnecessary check for valid_oactxctrl_offset - Drop valid_oactxctrl_offset macro v5: Drop unrelated comment Signed-off-by: Umesh Nerlige Ramappa Reviewed-by: Ashutosh Dixit Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20221026222102.5526-5-umesh.nerlige.ramappa@intel.com --- drivers/gpu/drm/i915/gt/intel_gpu_commands.h | 4 + drivers/gpu/drm/i915/i915_perf.c | 146 ++++++++++++++++++++++----- drivers/gpu/drm/i915/i915_perf_oa_regs.h | 2 +- 3 files changed, 127 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gpu_commands.h b/drivers/gpu/drm/i915/gt/intel_gpu_commands.h index d4e9702d3c8e..f50ea92910d9 100644 --- a/drivers/gpu/drm/i915/gt/intel_gpu_commands.h +++ b/drivers/gpu/drm/i915/gt/intel_gpu_commands.h @@ -187,6 +187,10 @@ #define MI_BATCH_RESOURCE_STREAMER REG_BIT(10) #define MI_BATCH_PREDICATE REG_BIT(15) /* HSW+ on RCS only*/ +#define MI_OPCODE(x) (((x) >> 23) & 0x3f) +#define IS_MI_LRI_CMD(x) (MI_OPCODE(x) == MI_OPCODE(MI_INSTR(0x22, 0))) +#define MI_LRI_LEN(x) (((x) & 0xff) + 1) + /* * 3D instructions used by the kernel */ diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index e68666b44a72..b71b5cf21176 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -1356,6 +1356,74 @@ static int gen12_get_render_context_id(struct i915_perf_stream *stream) return 0; } +static bool oa_find_reg_in_lri(u32 *state, u32 reg, u32 *offset, u32 end) +{ + u32 idx = *offset; + u32 len = min(MI_LRI_LEN(state[idx]) + idx, end); + bool found = false; + + idx++; + for (; idx < len; idx += 2) { + if (state[idx] == reg) { + found = true; + break; + } + } + + *offset = idx; + return found; +} + +static u32 oa_context_image_offset(struct intel_context *ce, u32 reg) +{ + u32 offset, len = (ce->engine->context_size - PAGE_SIZE) / 4; + u32 *state = ce->lrc_reg_state; + + for (offset = 0; offset < len; ) { + if (IS_MI_LRI_CMD(state[offset])) { + /* + * We expect reg-value pairs in MI_LRI command, so + * MI_LRI_LEN() should be even, if not, issue a warning. + */ + drm_WARN_ON(&ce->engine->i915->drm, + MI_LRI_LEN(state[offset]) & 0x1); + + if (oa_find_reg_in_lri(state, reg, &offset, len)) + break; + } else { + offset++; + } + } + + return offset < len ? offset : U32_MAX; +} + +static int set_oa_ctx_ctrl_offset(struct intel_context *ce) +{ + i915_reg_t reg = GEN12_OACTXCONTROL(ce->engine->mmio_base); + struct i915_perf *perf = &ce->engine->i915->perf; + u32 offset = perf->ctx_oactxctrl_offset; + + /* Do this only once. Failure is stored as offset of U32_MAX */ + if (offset) + goto exit; + + offset = oa_context_image_offset(ce, i915_mmio_reg_offset(reg)); + perf->ctx_oactxctrl_offset = offset; + + drm_dbg(&ce->engine->i915->drm, + "%s oa ctx control at 0x%08x dword offset\n", + ce->engine->name, offset); + +exit: + return offset && offset != U32_MAX ? 0 : -ENODEV; +} + +static bool engine_supports_mi_query(struct intel_engine_cs *engine) +{ + return engine->class == RENDER_CLASS; +} + /** * oa_get_render_ctx_id - determine and hold ctx hw id * @stream: An i915-perf stream opened for OA metrics @@ -1375,6 +1443,21 @@ static int oa_get_render_ctx_id(struct i915_perf_stream *stream) if (IS_ERR(ce)) return PTR_ERR(ce); + if (engine_supports_mi_query(stream->engine)) { + /* + * We are enabling perf query here. If we don't find the context + * offset here, just return an error. + */ + ret = set_oa_ctx_ctrl_offset(ce); + if (ret) { + intel_context_unpin(ce); + drm_err(&stream->perf->i915->drm, + "Enabling perf query failed for %s\n", + stream->engine->name); + return ret; + } + } + switch (GRAPHICS_VER(ce->engine->i915)) { case 7: { /* @@ -2406,10 +2489,11 @@ static int gen12_configure_oar_context(struct i915_perf_stream *stream, int err; struct intel_context *ce = stream->pinned_ctx; u32 format = stream->oa_buffer.format; + u32 offset = stream->perf->ctx_oactxctrl_offset; struct flex regs_context[] = { { GEN8_OACTXCONTROL, - stream->perf->ctx_oactxctrl_offset + 1, + offset + 1, active ? GEN8_OA_COUNTER_RESUME : 0, }, }; @@ -2434,12 +2518,13 @@ static int gen12_configure_oar_context(struct i915_perf_stream *stream, }, }; - /* Modify the context image of pinned context with regs_context*/ + /* Modify the context image of pinned context with regs_context */ err = intel_context_lock_pinned(ce); if (err) return err; - err = gen8_modify_context(ce, regs_context, ARRAY_SIZE(regs_context)); + err = gen8_modify_context(ce, regs_context, + ARRAY_SIZE(regs_context)); intel_context_unlock_pinned(ce); if (err) return err; @@ -2564,6 +2649,7 @@ lrc_configure_all_contexts(struct i915_perf_stream *stream, const struct i915_oa_config *oa_config, struct i915_active *active) { + u32 ctx_oactxctrl = stream->perf->ctx_oactxctrl_offset; /* The MMIO offsets for Flex EU registers aren't contiguous */ const u32 ctx_flexeu0 = stream->perf->ctx_flexeu0_offset; #define ctx_flexeuN(N) (ctx_flexeu0 + 2 * (N) + 1) @@ -2574,7 +2660,7 @@ lrc_configure_all_contexts(struct i915_perf_stream *stream, }, { GEN8_OACTXCONTROL, - stream->perf->ctx_oactxctrl_offset + 1, + ctx_oactxctrl + 1, }, { EU_PERF_CNTL0, ctx_flexeuN(0) }, { EU_PERF_CNTL1, ctx_flexeuN(1) }, @@ -4543,6 +4629,37 @@ static void oa_init_supported_formats(struct i915_perf *perf) } } +static void i915_perf_init_info(struct drm_i915_private *i915) +{ + struct i915_perf *perf = &i915->perf; + + switch (GRAPHICS_VER(i915)) { + case 8: + perf->ctx_oactxctrl_offset = 0x120; + perf->ctx_flexeu0_offset = 0x2ce; + perf->gen8_valid_ctx_bit = BIT(25); + break; + case 9: + perf->ctx_oactxctrl_offset = 0x128; + perf->ctx_flexeu0_offset = 0x3de; + perf->gen8_valid_ctx_bit = BIT(16); + break; + case 11: + perf->ctx_oactxctrl_offset = 0x124; + perf->ctx_flexeu0_offset = 0x78e; + perf->gen8_valid_ctx_bit = BIT(16); + break; + case 12: + /* + * Calculate offset at runtime in oa_pin_context for gen12 and + * cache the value in perf->ctx_oactxctrl_offset. + */ + break; + default: + MISSING_CASE(GRAPHICS_VER(i915)); + } +} + /** * i915_perf_init - initialize i915-perf state on module bind * @i915: i915 device instance @@ -4581,6 +4698,7 @@ void i915_perf_init(struct drm_i915_private *i915) * execlist mode by default. */ perf->ops.read = gen8_oa_read; + i915_perf_init_info(i915); if (IS_GRAPHICS_VER(i915, 8, 9)) { perf->ops.is_valid_b_counter_reg = @@ -4600,18 +4718,6 @@ void i915_perf_init(struct drm_i915_private *i915) perf->ops.enable_metric_set = gen8_enable_metric_set; perf->ops.disable_metric_set = gen8_disable_metric_set; perf->ops.oa_hw_tail_read = gen8_oa_hw_tail_read; - - if (GRAPHICS_VER(i915) == 8) { - perf->ctx_oactxctrl_offset = 0x120; - perf->ctx_flexeu0_offset = 0x2ce; - - perf->gen8_valid_ctx_bit = BIT(25); - } else { - perf->ctx_oactxctrl_offset = 0x128; - perf->ctx_flexeu0_offset = 0x3de; - - perf->gen8_valid_ctx_bit = BIT(16); - } } else if (GRAPHICS_VER(i915) == 11) { perf->ops.is_valid_b_counter_reg = gen7_is_valid_b_counter_addr; @@ -4625,11 +4731,6 @@ void i915_perf_init(struct drm_i915_private *i915) perf->ops.enable_metric_set = gen8_enable_metric_set; perf->ops.disable_metric_set = gen11_disable_metric_set; perf->ops.oa_hw_tail_read = gen8_oa_hw_tail_read; - - perf->ctx_oactxctrl_offset = 0x124; - perf->ctx_flexeu0_offset = 0x78e; - - perf->gen8_valid_ctx_bit = BIT(16); } else if (GRAPHICS_VER(i915) == 12) { perf->ops.is_valid_b_counter_reg = gen12_is_valid_b_counter_addr; @@ -4643,9 +4744,6 @@ void i915_perf_init(struct drm_i915_private *i915) perf->ops.enable_metric_set = gen12_enable_metric_set; perf->ops.disable_metric_set = gen12_disable_metric_set; perf->ops.oa_hw_tail_read = gen12_oa_hw_tail_read; - - perf->ctx_flexeu0_offset = 0; - perf->ctx_oactxctrl_offset = 0x144; } } diff --git a/drivers/gpu/drm/i915/i915_perf_oa_regs.h b/drivers/gpu/drm/i915/i915_perf_oa_regs.h index f31c9f13a9fc..0ef3562ff4aa 100644 --- a/drivers/gpu/drm/i915/i915_perf_oa_regs.h +++ b/drivers/gpu/drm/i915/i915_perf_oa_regs.h @@ -97,7 +97,7 @@ #define GEN12_OAR_OACONTROL_COUNTER_FORMAT_SHIFT 1 #define GEN12_OAR_OACONTROL_COUNTER_ENABLE (1 << 0) -#define GEN12_OACTXCONTROL _MMIO(0x2360) +#define GEN12_OACTXCONTROL(base) _MMIO((base) + 0x360) #define GEN12_OAR_OASTATUS _MMIO(0x2968) /* Gen12 OAG unit */ -- cgit From cceb084905285dcf56912336c9f4f4e7ac334d9f Mon Sep 17 00:00:00 2001 From: Umesh Nerlige Ramappa Date: Wed, 26 Oct 2022 22:20:51 +0000 Subject: drm/i915/perf: Enable bytes per clock reporting in OA XEHPSDV and DG2 provide a way to configure bytes per clock vs commands per clock reporting. Enable bytes per clock setting on enabling OA. Bspec: 51762 Bspec: 52201 v2: - Fix commit msg (Ashutosh) - Fix checkpatch issues v3: - s/commands/bytes/ in code comment and commmit msg Signed-off-by: Umesh Nerlige Ramappa Reviewed-by: Ashutosh Dixit Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20221026222102.5526-6-umesh.nerlige.ramappa@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 3 +++ drivers/gpu/drm/i915/i915_pci.c | 1 + drivers/gpu/drm/i915/i915_perf.c | 20 ++++++++++++++++++++ drivers/gpu/drm/i915/i915_perf_oa_regs.h | 4 ++++ drivers/gpu/drm/i915/intel_device_info.h | 1 + 5 files changed, 29 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 28ee5ac166db..34f0bcc36671 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -901,6 +901,9 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915, #define HAS_RUNTIME_PM(dev_priv) (INTEL_INFO(dev_priv)->has_runtime_pm) #define HAS_64BIT_RELOC(dev_priv) (INTEL_INFO(dev_priv)->has_64bit_reloc) +#define HAS_OA_BPC_REPORTING(dev_priv) \ + (INTEL_INFO(dev_priv)->has_oa_bpc_reporting) + /* * Set this flag, when platform requires 64K GTT page sizes or larger for * device local memory access. diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c index 53c6b7cf7879..7b751bf4be21 100644 --- a/drivers/gpu/drm/i915/i915_pci.c +++ b/drivers/gpu/drm/i915/i915_pci.c @@ -1023,6 +1023,7 @@ static const struct intel_device_info adl_p_info = { .has_logical_ring_contexts = 1, \ .has_logical_ring_elsq = 1, \ .has_mslice_steering = 1, \ + .has_oa_bpc_reporting = 1, \ .has_rc6 = 1, \ .has_reset_engine = 1, \ .has_rps = 1, \ diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index b71b5cf21176..d11cc949c9be 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -2748,10 +2748,12 @@ static int gen12_enable_metric_set(struct i915_perf_stream *stream, struct i915_active *active) { + struct drm_i915_private *i915 = stream->perf->i915; struct intel_uncore *uncore = stream->uncore; struct i915_oa_config *oa_config = stream->oa_config; bool periodic = stream->periodic; u32 period_exponent = stream->period_exponent; + u32 sqcnt1; int ret; intel_uncore_write(uncore, GEN12_OAG_OA_DEBUG, @@ -2770,6 +2772,16 @@ gen12_enable_metric_set(struct i915_perf_stream *stream, (period_exponent << GEN12_OAG_OAGLBCTXCTRL_TIMER_PERIOD_SHIFT)) : 0); + /* + * Initialize Super Queue Internal Cnt Register + * Set PMON Enable in order to collect valid metrics. + * Enable byets per clock reporting in OA for XEHPSDV onward. + */ + sqcnt1 = GEN12_SQCNT1_PMON_ENABLE | + (HAS_OA_BPC_REPORTING(i915) ? GEN12_SQCNT1_OABPC : 0); + + intel_uncore_rmw(uncore, GEN12_SQCNT1, 0, sqcnt1); + /* * Update all contexts prior writing the mux configurations as we need * to make sure all slices/subslices are ON before writing to NOA @@ -2819,6 +2831,8 @@ static void gen11_disable_metric_set(struct i915_perf_stream *stream) static void gen12_disable_metric_set(struct i915_perf_stream *stream) { struct intel_uncore *uncore = stream->uncore; + struct drm_i915_private *i915 = stream->perf->i915; + u32 sqcnt1; /* Reset all contexts' slices/subslices configurations. */ gen12_configure_all_contexts(stream, NULL, NULL); @@ -2829,6 +2843,12 @@ static void gen12_disable_metric_set(struct i915_perf_stream *stream) /* Make sure we disable noa to save power. */ intel_uncore_rmw(uncore, RPM_CONFIG1, GEN10_GT_NOA_ENABLE, 0); + + sqcnt1 = GEN12_SQCNT1_PMON_ENABLE | + (HAS_OA_BPC_REPORTING(i915) ? GEN12_SQCNT1_OABPC : 0); + + /* Reset PMON Enable to save power. */ + intel_uncore_rmw(uncore, GEN12_SQCNT1, sqcnt1, 0); } static void gen7_oa_enable(struct i915_perf_stream *stream) diff --git a/drivers/gpu/drm/i915/i915_perf_oa_regs.h b/drivers/gpu/drm/i915/i915_perf_oa_regs.h index 0ef3562ff4aa..381d94101610 100644 --- a/drivers/gpu/drm/i915/i915_perf_oa_regs.h +++ b/drivers/gpu/drm/i915/i915_perf_oa_regs.h @@ -134,4 +134,8 @@ #define GDT_CHICKEN_BITS _MMIO(0x9840) #define GT_NOA_ENABLE 0x00000080 +#define GEN12_SQCNT1 _MMIO(0x8718) +#define GEN12_SQCNT1_PMON_ENABLE REG_BIT(30) +#define GEN12_SQCNT1_OABPC REG_BIT(29) + #endif /* __INTEL_PERF_OA_REGS__ */ diff --git a/drivers/gpu/drm/i915/intel_device_info.h b/drivers/gpu/drm/i915/intel_device_info.h index da833267a782..d11546d87fe7 100644 --- a/drivers/gpu/drm/i915/intel_device_info.h +++ b/drivers/gpu/drm/i915/intel_device_info.h @@ -163,6 +163,7 @@ enum intel_ppgtt_type { func(has_logical_ring_elsq); \ func(has_media_ratio_mode); \ func(has_mslice_steering); \ + func(has_oa_bpc_reporting); \ func(has_one_eu_per_fuse_bit); \ func(has_pxp); \ func(has_rc6); \ -- cgit From a5a6d92f77ffde188ce3aa4ccec21fac5b00c6e8 Mon Sep 17 00:00:00 2001 From: Umesh Nerlige Ramappa Date: Wed, 26 Oct 2022 22:20:52 +0000 Subject: drm/i915/perf: Simply use stream->ctx Earlier code used exclusive_stream to check for user passed context. Simplify this by accessing stream->ctx. Signed-off-by: Umesh Nerlige Ramappa Reviewed-by: Lionel Landwerlin Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20221026222102.5526-7-umesh.nerlige.ramappa@intel.com --- drivers/gpu/drm/i915/i915_perf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index d11cc949c9be..75d320b2c1f8 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -776,7 +776,7 @@ static int gen8_append_oa_reports(struct i915_perf_stream *stream, * switches since it's not-uncommon for periodic samples to * identify a switch before any 'context switch' report. */ - if (!stream->perf->exclusive_stream->ctx || + if (!stream->ctx || stream->specific_ctx_id == ctx_id || stream->oa_buffer.last_ctx_id == stream->specific_ctx_id || reason & OAREPORT_REASON_CTX_SWITCH) { @@ -785,7 +785,7 @@ static int gen8_append_oa_reports(struct i915_perf_stream *stream, * While filtering for a single context we avoid * leaking the IDs of other contexts. */ - if (stream->perf->exclusive_stream->ctx && + if (stream->ctx && stream->specific_ctx_id != ctx_id) { report32[2] = INVALID_CTX_ID; } -- cgit From 9677a9f3b1ad3537bc945e7c7e54778632ee2d0f Mon Sep 17 00:00:00 2001 From: Umesh Nerlige Ramappa Date: Wed, 26 Oct 2022 22:20:53 +0000 Subject: drm/i915/perf: Move gt-specific data from i915->perf to gt->perf Make perf part of gt as the OAG buffer is specific to a gt. The refactor eventually simplifies programming the right OA buffer and the right HW registers when supporting multiple gts. Signed-off-by: Umesh Nerlige Ramappa Reviewed-by: Lionel Landwerlin Reviewed-by: Ashutosh Dixit Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20221026222102.5526-8-umesh.nerlige.ramappa@intel.com --- drivers/gpu/drm/i915/gt/intel_gt_types.h | 3 ++ drivers/gpu/drm/i915/gt/intel_sseu.c | 4 +- drivers/gpu/drm/i915/i915_perf.c | 75 ++++++++++++++++++------------ drivers/gpu/drm/i915/i915_perf_types.h | 39 ++++++++-------- drivers/gpu/drm/i915/selftests/i915_perf.c | 16 +++++-- 5 files changed, 80 insertions(+), 57 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_types.h b/drivers/gpu/drm/i915/gt/intel_gt_types.h index 64aa2ba624fc..6f686a4244f0 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_types.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_types.h @@ -20,6 +20,7 @@ #include "intel_gsc.h" #include "i915_vma.h" +#include "i915_perf_types.h" #include "intel_engine_types.h" #include "intel_gt_buffer_pool_types.h" #include "intel_hwconfig.h" @@ -289,6 +290,8 @@ struct intel_gt { /* sysfs defaults per gt */ struct gt_defaults defaults; struct kobject *sysfs_defaults; + + struct i915_perf_gt perf; }; struct intel_gt_definition { diff --git a/drivers/gpu/drm/i915/gt/intel_sseu.c b/drivers/gpu/drm/i915/gt/intel_sseu.c index 66f21c735d54..6c6198a257ac 100644 --- a/drivers/gpu/drm/i915/gt/intel_sseu.c +++ b/drivers/gpu/drm/i915/gt/intel_sseu.c @@ -677,8 +677,8 @@ u32 intel_sseu_make_rpcs(struct intel_gt *gt, * If i915/perf is active, we want a stable powergating configuration * on the system. Use the configuration pinned by i915/perf. */ - if (i915->perf.exclusive_stream) - req_sseu = &i915->perf.sseu; + if (gt->perf.exclusive_stream) + req_sseu = >->perf.sseu; slices = hweight8(req_sseu->slice_mask); subslices = hweight8(req_sseu->subslice_mask); diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index 75d320b2c1f8..83c5dc043261 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -1565,8 +1565,9 @@ free_noa_wait(struct i915_perf_stream *stream) static void i915_oa_stream_destroy(struct i915_perf_stream *stream) { struct i915_perf *perf = stream->perf; + struct intel_gt *gt = stream->engine->gt; - if (WARN_ON(stream != perf->exclusive_stream)) + if (WARN_ON(stream != gt->perf.exclusive_stream)) return; /* @@ -1575,7 +1576,7 @@ static void i915_oa_stream_destroy(struct i915_perf_stream *stream) * * See i915_oa_init_reg_state() and lrc_configure_all_contexts() */ - WRITE_ONCE(perf->exclusive_stream, NULL); + WRITE_ONCE(gt->perf.exclusive_stream, NULL); perf->ops.disable_metric_set(stream); free_oa_buffer(stream); @@ -2566,10 +2567,11 @@ oa_configure_all_contexts(struct i915_perf_stream *stream, { struct drm_i915_private *i915 = stream->perf->i915; struct intel_engine_cs *engine; + struct intel_gt *gt = stream->engine->gt; struct i915_gem_context *ctx, *cn; int err; - lockdep_assert_held(&stream->perf->lock); + lockdep_assert_held(>->perf.lock); /* * The OA register config is setup through the context image. This image @@ -3090,6 +3092,7 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream, { struct drm_i915_private *i915 = stream->perf->i915; struct i915_perf *perf = stream->perf; + struct intel_gt *gt; int format_size; int ret; @@ -3098,6 +3101,7 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream, "OA engine not specified\n"); return -EINVAL; } + gt = props->engine->gt; /* * If the sysfs metrics/ directory wasn't registered for some @@ -3128,7 +3132,7 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream, * counter reports and marshal to the appropriate client * we currently only allow exclusive access */ - if (perf->exclusive_stream) { + if (gt->perf.exclusive_stream) { drm_dbg(&stream->perf->i915->drm, "OA unit already in use\n"); return -EBUSY; @@ -3208,8 +3212,8 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream, stream->ops = &i915_oa_stream_ops; - perf->sseu = props->sseu; - WRITE_ONCE(perf->exclusive_stream, stream); + stream->engine->gt->perf.sseu = props->sseu; + WRITE_ONCE(gt->perf.exclusive_stream, stream); ret = i915_perf_stream_enable_sync(stream); if (ret) { @@ -3231,7 +3235,7 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream, return 0; err_enable: - WRITE_ONCE(perf->exclusive_stream, NULL); + WRITE_ONCE(gt->perf.exclusive_stream, NULL); perf->ops.disable_metric_set(stream); free_oa_buffer(stream); @@ -3261,7 +3265,7 @@ void i915_oa_init_reg_state(const struct intel_context *ce, return; /* perf.exclusive_stream serialised by lrc_configure_all_contexts() */ - stream = READ_ONCE(engine->i915->perf.exclusive_stream); + stream = READ_ONCE(engine->gt->perf.exclusive_stream); if (stream && GRAPHICS_VER(stream->perf->i915) < 12) gen8_update_reg_state_unlocked(ce, stream); } @@ -3290,7 +3294,7 @@ static ssize_t i915_perf_read(struct file *file, loff_t *ppos) { struct i915_perf_stream *stream = file->private_data; - struct i915_perf *perf = stream->perf; + struct intel_gt *gt = stream->engine->gt; size_t offset = 0; int ret; @@ -3314,14 +3318,14 @@ static ssize_t i915_perf_read(struct file *file, if (ret) return ret; - mutex_lock(&perf->lock); + mutex_lock(>->perf.lock); ret = stream->ops->read(stream, buf, count, &offset); - mutex_unlock(&perf->lock); + mutex_unlock(>->perf.lock); } while (!offset && !ret); } else { - mutex_lock(&perf->lock); + mutex_lock(>->perf.lock); ret = stream->ops->read(stream, buf, count, &offset); - mutex_unlock(&perf->lock); + mutex_unlock(>->perf.lock); } /* We allow the poll checking to sometimes report false positive EPOLLIN @@ -3368,7 +3372,7 @@ static enum hrtimer_restart oa_poll_check_timer_cb(struct hrtimer *hrtimer) * &i915_perf_stream_ops->poll_wait to call poll_wait() with a wait queue that * will be woken for new stream data. * - * Note: The &perf->lock mutex has been taken to serialize + * Note: The >->perf.lock mutex has been taken to serialize * with any non-file-operation driver hooks. * * Returns: any poll events that are ready without sleeping @@ -3409,12 +3413,12 @@ static __poll_t i915_perf_poll_locked(struct i915_perf_stream *stream, static __poll_t i915_perf_poll(struct file *file, poll_table *wait) { struct i915_perf_stream *stream = file->private_data; - struct i915_perf *perf = stream->perf; + struct intel_gt *gt = stream->engine->gt; __poll_t ret; - mutex_lock(&perf->lock); + mutex_lock(>->perf.lock); ret = i915_perf_poll_locked(stream, file, wait); - mutex_unlock(&perf->lock); + mutex_unlock(>->perf.lock); return ret; } @@ -3513,7 +3517,7 @@ static long i915_perf_config_locked(struct i915_perf_stream *stream, * @cmd: the ioctl request * @arg: the ioctl data * - * Note: The &perf->lock mutex has been taken to serialize + * Note: The >->perf.lock mutex has been taken to serialize * with any non-file-operation driver hooks. * * Returns: zero on success or a negative error code. Returns -EINVAL for @@ -3553,12 +3557,12 @@ static long i915_perf_ioctl(struct file *file, unsigned long arg) { struct i915_perf_stream *stream = file->private_data; - struct i915_perf *perf = stream->perf; + struct intel_gt *gt = stream->engine->gt; long ret; - mutex_lock(&perf->lock); + mutex_lock(>->perf.lock); ret = i915_perf_ioctl_locked(stream, cmd, arg); - mutex_unlock(&perf->lock); + mutex_unlock(>->perf.lock); return ret; } @@ -3570,7 +3574,7 @@ static long i915_perf_ioctl(struct file *file, * Frees all resources associated with the given i915 perf @stream, disabling * any associated data capture in the process. * - * Note: The &perf->lock mutex has been taken to serialize + * Note: The >->perf.lock mutex has been taken to serialize * with any non-file-operation driver hooks. */ static void i915_perf_destroy_locked(struct i915_perf_stream *stream) @@ -3602,10 +3606,11 @@ static int i915_perf_release(struct inode *inode, struct file *file) { struct i915_perf_stream *stream = file->private_data; struct i915_perf *perf = stream->perf; + struct intel_gt *gt = stream->engine->gt; - mutex_lock(&perf->lock); + mutex_lock(>->perf.lock); i915_perf_destroy_locked(stream); - mutex_unlock(&perf->lock); + mutex_unlock(>->perf.lock); /* Release the reference the perf stream kept on the driver. */ drm_dev_put(&perf->i915->drm); @@ -3638,7 +3643,7 @@ static const struct file_operations fops = { * See i915_perf_ioctl_open() for interface details. * * Implements further stream config validation and stream initialization on - * behalf of i915_perf_open_ioctl() with the &perf->lock mutex + * behalf of i915_perf_open_ioctl() with the >->perf.lock mutex * taken to serialize with any non-file-operation driver hooks. * * Note: at this point the @props have only been validated in isolation and @@ -4022,7 +4027,7 @@ static int read_properties_unlocked(struct i915_perf *perf, * mutex to avoid an awkward lockdep with mmap_lock. * * Most of the implementation details are handled by - * i915_perf_open_ioctl_locked() after taking the &perf->lock + * i915_perf_open_ioctl_locked() after taking the >->perf.lock * mutex for serializing with any non-file-operation driver hooks. * * Return: A newly opened i915 Perf stream file descriptor or negative @@ -4033,6 +4038,7 @@ int i915_perf_open_ioctl(struct drm_device *dev, void *data, { struct i915_perf *perf = &to_i915(dev)->perf; struct drm_i915_perf_open_param *param = data; + struct intel_gt *gt; struct perf_open_properties props; u32 known_open_flags; int ret; @@ -4059,9 +4065,11 @@ int i915_perf_open_ioctl(struct drm_device *dev, void *data, if (ret) return ret; - mutex_lock(&perf->lock); + gt = props.engine->gt; + + mutex_lock(>->perf.lock); ret = i915_perf_open_ioctl_locked(perf, param, &props, file); - mutex_unlock(&perf->lock); + mutex_unlock(>->perf.lock); return ret; } @@ -4077,6 +4085,7 @@ int i915_perf_open_ioctl(struct drm_device *dev, void *data, void i915_perf_register(struct drm_i915_private *i915) { struct i915_perf *perf = &i915->perf; + struct intel_gt *gt = to_gt(i915); if (!perf->i915) return; @@ -4085,13 +4094,13 @@ void i915_perf_register(struct drm_i915_private *i915) * i915_perf_open_ioctl(); considering that we register after * being exposed to userspace. */ - mutex_lock(&perf->lock); + mutex_lock(>->perf.lock); perf->metrics_kobj = kobject_create_and_add("metrics", &i915->drm.primary->kdev->kobj); - mutex_unlock(&perf->lock); + mutex_unlock(>->perf.lock); } /** @@ -4768,7 +4777,11 @@ void i915_perf_init(struct drm_i915_private *i915) } if (perf->ops.enable_metric_set) { - mutex_init(&perf->lock); + struct intel_gt *gt; + int i; + + for_each_gt(gt, i915, i) + mutex_init(>->perf.lock); /* Choose a representative limit */ oa_sample_rate_hard_limit = to_gt(i915)->clock_frequency / 2; diff --git a/drivers/gpu/drm/i915/i915_perf_types.h b/drivers/gpu/drm/i915/i915_perf_types.h index 05cb9a335a97..e888bfab478f 100644 --- a/drivers/gpu/drm/i915/i915_perf_types.h +++ b/drivers/gpu/drm/i915/i915_perf_types.h @@ -380,6 +380,26 @@ struct i915_oa_ops { u32 (*oa_hw_tail_read)(struct i915_perf_stream *stream); }; +struct i915_perf_gt { + /* + * Lock associated with anything below within this structure. + */ + struct mutex lock; + + /** + * @sseu: sseu configuration selected to run while perf is active, + * applies to all contexts. + */ + struct intel_sseu sseu; + + /* + * @exclusive_stream: The stream currently using the OA unit. This is + * sometimes accessed outside a syscall associated to its file + * descriptor. + */ + struct i915_perf_stream *exclusive_stream; +}; + struct i915_perf { struct drm_i915_private *i915; @@ -397,25 +417,6 @@ struct i915_perf { */ struct idr metrics_idr; - /* - * Lock associated with anything below within this structure - * except exclusive_stream. - */ - struct mutex lock; - - /* - * The stream currently using the OA unit. If accessed - * outside a syscall associated to its file - * descriptor. - */ - struct i915_perf_stream *exclusive_stream; - - /** - * @sseu: sseu configuration selected to run while perf is active, - * applies to all contexts. - */ - struct intel_sseu sseu; - /** * For rate limiting any notifications of spurious * invalid OA reports diff --git a/drivers/gpu/drm/i915/selftests/i915_perf.c b/drivers/gpu/drm/i915/selftests/i915_perf.c index 429c6d73b159..24dde5531423 100644 --- a/drivers/gpu/drm/i915/selftests/i915_perf.c +++ b/drivers/gpu/drm/i915/selftests/i915_perf.c @@ -102,6 +102,12 @@ test_stream(struct i915_perf *perf) I915_OA_FORMAT_A32u40_A4u32_B8_C8 : I915_OA_FORMAT_C4_B8, }; struct i915_perf_stream *stream; + struct intel_gt *gt; + + if (!props.engine) + return NULL; + + gt = props.engine->gt; if (!oa_config) return NULL; @@ -116,12 +122,12 @@ test_stream(struct i915_perf *perf) stream->perf = perf; - mutex_lock(&perf->lock); + mutex_lock(>->perf.lock); if (i915_oa_stream_init(stream, ¶m, &props)) { kfree(stream); stream = NULL; } - mutex_unlock(&perf->lock); + mutex_unlock(>->perf.lock); i915_oa_config_put(oa_config); @@ -130,11 +136,11 @@ test_stream(struct i915_perf *perf) static void stream_destroy(struct i915_perf_stream *stream) { - struct i915_perf *perf = stream->perf; + struct intel_gt *gt = stream->engine->gt; - mutex_lock(&perf->lock); + mutex_lock(>->perf.lock); i915_perf_destroy_locked(stream); - mutex_unlock(&perf->lock); + mutex_unlock(>->perf.lock); } static int live_sanitycheck(void *arg) -- cgit From 2db609c014958202e067678758c2a5291a28bae5 Mon Sep 17 00:00:00 2001 From: Umesh Nerlige Ramappa Date: Wed, 26 Oct 2022 22:20:54 +0000 Subject: drm/i915/perf: Replace gt->perf.lock with stream->lock for file ops With multi-gt, user can access multiple OA buffers concurrently. Use stream->lock instead of gt->perf.lock to serialize file operations. Signed-off-by: Umesh Nerlige Ramappa Reviewed-by: Ashutosh Dixit Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20221026222102.5526-9-umesh.nerlige.ramappa@intel.com --- drivers/gpu/drm/i915/i915_perf.c | 31 ++++++++++++++----------------- drivers/gpu/drm/i915/i915_perf_types.h | 5 +++++ 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index 83c5dc043261..9a00398ae25f 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -3231,6 +3231,7 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream, stream->poll_check_timer.function = oa_poll_check_timer_cb; init_waitqueue_head(&stream->poll_wq); spin_lock_init(&stream->oa_buffer.ptr_lock); + mutex_init(&stream->lock); return 0; @@ -3294,7 +3295,6 @@ static ssize_t i915_perf_read(struct file *file, loff_t *ppos) { struct i915_perf_stream *stream = file->private_data; - struct intel_gt *gt = stream->engine->gt; size_t offset = 0; int ret; @@ -3318,14 +3318,14 @@ static ssize_t i915_perf_read(struct file *file, if (ret) return ret; - mutex_lock(>->perf.lock); + mutex_lock(&stream->lock); ret = stream->ops->read(stream, buf, count, &offset); - mutex_unlock(>->perf.lock); + mutex_unlock(&stream->lock); } while (!offset && !ret); } else { - mutex_lock(>->perf.lock); + mutex_lock(&stream->lock); ret = stream->ops->read(stream, buf, count, &offset); - mutex_unlock(>->perf.lock); + mutex_unlock(&stream->lock); } /* We allow the poll checking to sometimes report false positive EPOLLIN @@ -3372,9 +3372,6 @@ static enum hrtimer_restart oa_poll_check_timer_cb(struct hrtimer *hrtimer) * &i915_perf_stream_ops->poll_wait to call poll_wait() with a wait queue that * will be woken for new stream data. * - * Note: The >->perf.lock mutex has been taken to serialize - * with any non-file-operation driver hooks. - * * Returns: any poll events that are ready without sleeping */ static __poll_t i915_perf_poll_locked(struct i915_perf_stream *stream, @@ -3413,12 +3410,11 @@ static __poll_t i915_perf_poll_locked(struct i915_perf_stream *stream, static __poll_t i915_perf_poll(struct file *file, poll_table *wait) { struct i915_perf_stream *stream = file->private_data; - struct intel_gt *gt = stream->engine->gt; __poll_t ret; - mutex_lock(>->perf.lock); + mutex_lock(&stream->lock); ret = i915_perf_poll_locked(stream, file, wait); - mutex_unlock(>->perf.lock); + mutex_unlock(&stream->lock); return ret; } @@ -3517,9 +3513,6 @@ static long i915_perf_config_locked(struct i915_perf_stream *stream, * @cmd: the ioctl request * @arg: the ioctl data * - * Note: The >->perf.lock mutex has been taken to serialize - * with any non-file-operation driver hooks. - * * Returns: zero on success or a negative error code. Returns -EINVAL for * an unknown ioctl request. */ @@ -3557,12 +3550,11 @@ static long i915_perf_ioctl(struct file *file, unsigned long arg) { struct i915_perf_stream *stream = file->private_data; - struct intel_gt *gt = stream->engine->gt; long ret; - mutex_lock(>->perf.lock); + mutex_lock(&stream->lock); ret = i915_perf_ioctl_locked(stream, cmd, arg); - mutex_unlock(>->perf.lock); + mutex_unlock(&stream->lock); return ret; } @@ -3608,6 +3600,11 @@ static int i915_perf_release(struct inode *inode, struct file *file) struct i915_perf *perf = stream->perf; struct intel_gt *gt = stream->engine->gt; + /* + * Within this call, we know that the fd is being closed and we have no + * other user of stream->lock. Use the perf lock to destroy the stream + * here. + */ mutex_lock(>->perf.lock); i915_perf_destroy_locked(stream); mutex_unlock(>->perf.lock); diff --git a/drivers/gpu/drm/i915/i915_perf_types.h b/drivers/gpu/drm/i915/i915_perf_types.h index e888bfab478f..dc9bfd8086cf 100644 --- a/drivers/gpu/drm/i915/i915_perf_types.h +++ b/drivers/gpu/drm/i915/i915_perf_types.h @@ -146,6 +146,11 @@ struct i915_perf_stream { */ struct intel_engine_cs *engine; + /* + * Lock associated with operations on stream + */ + struct mutex lock; + /** * @sample_flags: Flags representing the `DRM_I915_PERF_PROP_SAMPLE_*` * properties given when opening a stream, representing the contents -- cgit From cc85345dc804f9fbe39ca2727e63058595b01e0f Mon Sep 17 00:00:00 2001 From: Umesh Nerlige Ramappa Date: Wed, 26 Oct 2022 22:20:55 +0000 Subject: drm/i915/perf: Use gt-specific ggtt for OA and noa-wait buffers User passes uabi engine class and instance to the perf OA interface. Use gt corresponding to the engine to pin the buffers to the right ggtt. Signed-off-by: Umesh Nerlige Ramappa Reviewed-by: Lionel Landwerlin Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20221026222102.5526-10-umesh.nerlige.ramappa@intel.com --- drivers/gpu/drm/i915/i915_perf.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index 9a00398ae25f..2c8727253f0d 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -1754,6 +1754,7 @@ static void gen12_init_oa_buffer(struct i915_perf_stream *stream) static int alloc_oa_buffer(struct i915_perf_stream *stream) { struct drm_i915_private *i915 = stream->perf->i915; + struct intel_gt *gt = stream->engine->gt; struct drm_i915_gem_object *bo; struct i915_vma *vma; int ret; @@ -1773,11 +1774,22 @@ static int alloc_oa_buffer(struct i915_perf_stream *stream) i915_gem_object_set_cache_coherency(bo, I915_CACHE_LLC); /* PreHSW required 512K alignment, HSW requires 16M */ - vma = i915_gem_object_ggtt_pin(bo, NULL, 0, SZ_16M, 0); + vma = i915_vma_instance(bo, >->ggtt->vm, NULL); if (IS_ERR(vma)) { ret = PTR_ERR(vma); goto err_unref; } + + /* + * PreHSW required 512K alignment. + * HSW and onwards, align to requested size of OA buffer. + */ + ret = i915_vma_pin(vma, 0, SZ_16M, PIN_GLOBAL | PIN_HIGH); + if (ret) { + drm_err(>->i915->drm, "Failed to pin OA buffer %d\n", ret); + goto err_unref; + } + stream->oa_buffer.vma = vma; stream->oa_buffer.vaddr = @@ -1827,6 +1839,7 @@ static u32 *save_restore_register(struct i915_perf_stream *stream, u32 *cs, static int alloc_noa_wait(struct i915_perf_stream *stream) { struct drm_i915_private *i915 = stream->perf->i915; + struct intel_gt *gt = stream->engine->gt; struct drm_i915_gem_object *bo; struct i915_vma *vma; const u64 delay_ticks = 0xffffffffffffffff - @@ -1867,12 +1880,16 @@ retry: * multiple OA config BOs will have a jump to this address and it * needs to be fixed during the lifetime of the i915/perf stream. */ - vma = i915_gem_object_ggtt_pin_ww(bo, &ww, NULL, 0, 0, PIN_HIGH); + vma = i915_vma_instance(bo, >->ggtt->vm, NULL); if (IS_ERR(vma)) { ret = PTR_ERR(vma); goto out_ww; } + ret = i915_vma_pin_ww(vma, &ww, 0, 0, PIN_GLOBAL | PIN_HIGH); + if (ret) + goto out_ww; + batch = cs = i915_gem_object_pin_map(bo, I915_MAP_WB); if (IS_ERR(batch)) { ret = PTR_ERR(batch); -- cgit From 90981da6da8ce333c49d2748f925fc4ef566785f Mon Sep 17 00:00:00 2001 From: Umesh Nerlige Ramappa Date: Wed, 26 Oct 2022 22:20:56 +0000 Subject: drm/i915/perf: Store a pointer to oa_format in oa_buffer DG2 introduces OA reports with 64 bit report header fields. Perf OA would need more information about the OA format in order to process such reports. Store all OA format info in oa_buffer instead of just the size and format-id. v2: Drop format_size variable (Ashutosh) Signed-off-by: Umesh Nerlige Ramappa Reviewed-by: Lionel Landwerlin Reviewed-by: Ashutosh Dixit Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20221026222102.5526-11-umesh.nerlige.ramappa@intel.com --- drivers/gpu/drm/i915/i915_perf.c | 30 ++++++++++++------------------ drivers/gpu/drm/i915/i915_perf_types.h | 3 +-- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index 2c8727253f0d..585079ae5f03 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -465,7 +465,7 @@ static u32 gen7_oa_hw_tail_read(struct i915_perf_stream *stream) static bool oa_buffer_check_unlocked(struct i915_perf_stream *stream) { u32 gtt_offset = i915_ggtt_offset(stream->oa_buffer.vma); - int report_size = stream->oa_buffer.format_size; + int report_size = stream->oa_buffer.format->size; unsigned long flags; bool pollin; u32 hw_tail; @@ -602,7 +602,7 @@ static int append_oa_sample(struct i915_perf_stream *stream, size_t *offset, const u8 *report) { - int report_size = stream->oa_buffer.format_size; + int report_size = stream->oa_buffer.format->size; struct drm_i915_perf_record_header header; header.type = DRM_I915_PERF_RECORD_SAMPLE; @@ -652,7 +652,7 @@ static int gen8_append_oa_reports(struct i915_perf_stream *stream, size_t *offset) { struct intel_uncore *uncore = stream->uncore; - int report_size = stream->oa_buffer.format_size; + int report_size = stream->oa_buffer.format->size; u8 *oa_buf_base = stream->oa_buffer.vaddr; u32 gtt_offset = i915_ggtt_offset(stream->oa_buffer.vma); u32 mask = (OA_BUFFER_SIZE - 1); @@ -945,7 +945,7 @@ static int gen7_append_oa_reports(struct i915_perf_stream *stream, size_t *offset) { struct intel_uncore *uncore = stream->uncore; - int report_size = stream->oa_buffer.format_size; + int report_size = stream->oa_buffer.format->size; u8 *oa_buf_base = stream->oa_buffer.vaddr; u32 gtt_offset = i915_ggtt_offset(stream->oa_buffer.vma); u32 mask = (OA_BUFFER_SIZE - 1); @@ -2506,7 +2506,7 @@ static int gen12_configure_oar_context(struct i915_perf_stream *stream, { int err; struct intel_context *ce = stream->pinned_ctx; - u32 format = stream->oa_buffer.format; + u32 format = stream->oa_buffer.format->format; u32 offset = stream->perf->ctx_oactxctrl_offset; struct flex regs_context[] = { { @@ -2877,7 +2877,7 @@ static void gen7_oa_enable(struct i915_perf_stream *stream) u32 ctx_id = stream->specific_ctx_id; bool periodic = stream->periodic; u32 period_exponent = stream->period_exponent; - u32 report_format = stream->oa_buffer.format; + u32 report_format = stream->oa_buffer.format->format; /* * Reset buf pointers so we don't forward reports from before now. @@ -2903,7 +2903,7 @@ static void gen7_oa_enable(struct i915_perf_stream *stream) static void gen8_oa_enable(struct i915_perf_stream *stream) { struct intel_uncore *uncore = stream->uncore; - u32 report_format = stream->oa_buffer.format; + u32 report_format = stream->oa_buffer.format->format; /* * Reset buf pointers so we don't forward reports from before now. @@ -2929,7 +2929,7 @@ static void gen8_oa_enable(struct i915_perf_stream *stream) static void gen12_oa_enable(struct i915_perf_stream *stream) { struct intel_uncore *uncore = stream->uncore; - u32 report_format = stream->oa_buffer.format; + u32 report_format = stream->oa_buffer.format->format; /* * If we don't want OA reports from the OA buffer, then we don't even @@ -3110,7 +3110,6 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream, struct drm_i915_private *i915 = stream->perf->i915; struct i915_perf *perf = stream->perf; struct intel_gt *gt; - int format_size; int ret; if (!props->engine) { @@ -3166,20 +3165,15 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream, stream->sample_size = sizeof(struct drm_i915_perf_record_header); - format_size = perf->oa_formats[props->oa_format].size; + stream->oa_buffer.format = &perf->oa_formats[props->oa_format]; + if (drm_WARN_ON(&i915->drm, stream->oa_buffer.format->size == 0)) + return -EINVAL; stream->sample_flags = props->sample_flags; - stream->sample_size += format_size; - - stream->oa_buffer.format_size = format_size; - if (drm_WARN_ON(&i915->drm, stream->oa_buffer.format_size == 0)) - return -EINVAL; + stream->sample_size += stream->oa_buffer.format->size; stream->hold_preemption = props->hold_preemption; - stream->oa_buffer.format = - perf->oa_formats[props->oa_format].format; - stream->periodic = props->oa_periodic; if (stream->periodic) stream->period_exponent = props->oa_period_exponent; diff --git a/drivers/gpu/drm/i915/i915_perf_types.h b/drivers/gpu/drm/i915/i915_perf_types.h index dc9bfd8086cf..e0c96b44eda8 100644 --- a/drivers/gpu/drm/i915/i915_perf_types.h +++ b/drivers/gpu/drm/i915/i915_perf_types.h @@ -250,11 +250,10 @@ struct i915_perf_stream { * @oa_buffer: State of the OA buffer. */ struct { + const struct i915_oa_format *format; struct i915_vma *vma; u8 *vaddr; u32 last_ctx_id; - int format; - int format_size; int size_exponent; /** -- cgit From ed6b25aa6fbf8855446efc7125e6b5d912b36ed3 Mon Sep 17 00:00:00 2001 From: Umesh Nerlige Ramappa Date: Wed, 26 Oct 2022 22:20:57 +0000 Subject: drm/i915/perf: Add Wa_1508761755:dg2 Disable Clock gating in EU when gathering the events so that EU events are not lost. v2: Fix checkpatch issues v3: User MCR helpers to write to MC reg v4: Indent correctly (checkpatch) Signed-off-by: Umesh Nerlige Ramappa Reviewed-by: Ashutosh Dixit Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20221026222102.5526-12-umesh.nerlige.ramappa@intel.com --- drivers/gpu/drm/i915/gt/intel_gt_regs.h | 1 + drivers/gpu/drm/i915/i915_perf.c | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_regs.h b/drivers/gpu/drm/i915/gt/intel_gt_regs.h index a9c409eb131c..1b901970cfa4 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_regs.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_regs.h @@ -1162,6 +1162,7 @@ #define GEN12_DISABLE_EARLY_READ REG_BIT(14) #define GEN12_ENABLE_LARGE_GRF_MODE REG_BIT(12) #define GEN12_PUSH_CONST_DEREF_HOLD_DIS REG_BIT(8) +#define GEN12_DISABLE_DOP_GATING REG_BIT(0) #define RT_CTRL MCR_REG(0xe530) #define DIS_NULL_QUERY REG_BIT(10) diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index 585079ae5f03..e14d16ac47de 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -204,6 +204,7 @@ #include "gt/intel_gpu_commands.h" #include "gt/intel_gt.h" #include "gt/intel_gt_clock_utils.h" +#include "gt/intel_gt_mcr.h" #include "gt/intel_gt_regs.h" #include "gt/intel_lrc.h" #include "gt/intel_lrc_reg.h" @@ -2775,6 +2776,18 @@ gen12_enable_metric_set(struct i915_perf_stream *stream, u32 sqcnt1; int ret; + /* + * Wa_1508761755:xehpsdv, dg2 + * EU NOA signals behave incorrectly if EU clock gating is enabled. + * Disable thread stall DOP gating and EU DOP gating. + */ + if (IS_XEHPSDV(i915) || IS_DG2(i915)) { + intel_gt_mcr_multicast_write(uncore->gt, GEN8_ROW_CHICKEN, + _MASKED_BIT_ENABLE(STALL_DOP_GATING_DISABLE)); + intel_uncore_write(uncore, GEN7_ROW_CHICKEN2, + _MASKED_BIT_ENABLE(GEN12_DISABLE_DOP_GATING)); + } + intel_uncore_write(uncore, GEN12_OAG_OA_DEBUG, /* Disable clk ratio reports, like previous Gens. */ _MASKED_BIT_ENABLE(GEN12_OAG_OA_DEBUG_DISABLE_CLK_RATIO_REPORTS | @@ -2853,6 +2866,17 @@ static void gen12_disable_metric_set(struct i915_perf_stream *stream) struct drm_i915_private *i915 = stream->perf->i915; u32 sqcnt1; + /* + * Wa_1508761755:xehpsdv, dg2 + * Enable thread stall DOP gating and EU DOP gating. + */ + if (IS_XEHPSDV(i915) || IS_DG2(i915)) { + intel_gt_mcr_multicast_write(uncore->gt, GEN8_ROW_CHICKEN, + _MASKED_BIT_DISABLE(STALL_DOP_GATING_DISABLE)); + intel_uncore_write(uncore, GEN7_ROW_CHICKEN2, + _MASKED_BIT_DISABLE(GEN12_DISABLE_DOP_GATING)); + } + /* Reset all contexts' slices/subslices configurations. */ gen12_configure_all_contexts(stream, NULL, NULL); -- cgit From bc7ed4d30815bc434c1e49dc6784164b352d167c Mon Sep 17 00:00:00 2001 From: Umesh Nerlige Ramappa Date: Wed, 26 Oct 2022 22:20:58 +0000 Subject: drm/i915/perf: Apply Wa_18013179988 OA reports in the OA buffer contain an OA timestamp field that helps user calculate delta between 2 OA reports. The calculation relies on the CS timestamp frequency to convert the timestamp value to nanoseconds. The CS timestamp frequency is a function of the CTC_SHIFT value in RPM_CONFIG0. In DG2, OA unit assumes that the CTC_SHIFT is 3, instead of using the actual value from RPM_CONFIG0. At the user level, this results in an error in calculating delta between 2 OA reports since the OA timestamp is not shifted in the same manner as CS timestamp. Also the periodicity of the reports is different from what the user configured because of mismatch in the CS and OA frequencies. The issue also affects MI_REPORT_PERF_COUNT command. To resolve this, return actual OA timestamp frequency to the user in i915_getparam_ioctl, so that user can calculate the right OA exponent as well as interpret the reports correctly. MR: https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/18893 v2: - Use REG_FIELD_GET (Ashutosh) - Update commit msg Signed-off-by: Umesh Nerlige Ramappa Reviewed-by: Ashutosh Dixit Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20221026222102.5526-13-umesh.nerlige.ramappa@intel.com --- drivers/gpu/drm/i915/i915_getparam.c | 3 +++ drivers/gpu/drm/i915/i915_perf.c | 30 ++++++++++++++++++++++++++++-- drivers/gpu/drm/i915/i915_perf.h | 2 ++ include/uapi/drm/i915_drm.h | 6 ++++++ 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_getparam.c b/drivers/gpu/drm/i915/i915_getparam.c index 342c8ca6414e..3047e80e1163 100644 --- a/drivers/gpu/drm/i915/i915_getparam.c +++ b/drivers/gpu/drm/i915/i915_getparam.c @@ -175,6 +175,9 @@ int i915_getparam_ioctl(struct drm_device *dev, void *data, case I915_PARAM_PERF_REVISION: value = i915_perf_ioctl_version(); break; + case I915_PARAM_OA_TIMESTAMP_FREQUENCY: + value = i915_perf_oa_timestamp_frequency(i915); + break; default: DRM_DEBUG("Unknown parameter %d\n", param->param); return -EINVAL; diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index e14d16ac47de..b73d91b792df 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -3109,6 +3109,30 @@ get_sseu_config(struct intel_sseu *out_sseu, return i915_gem_user_to_context_sseu(engine->gt, drm_sseu, out_sseu); } +/* + * OA timestamp frequency = CS timestamp frequency in most platforms. On some + * platforms OA unit ignores the CTC_SHIFT and the 2 timestamps differ. In such + * cases, return the adjusted CS timestamp frequency to the user. + */ +u32 i915_perf_oa_timestamp_frequency(struct drm_i915_private *i915) +{ + /* Wa_18013179988:dg2 */ + if (IS_DG2(i915)) { + intel_wakeref_t wakeref; + u32 reg, shift; + + with_intel_runtime_pm(to_gt(i915)->uncore->rpm, wakeref) + reg = intel_uncore_read(to_gt(i915)->uncore, RPM_CONFIG0); + + shift = REG_FIELD_GET(GEN10_RPM_CONFIG0_CTC_SHIFT_PARAMETER_MASK, + reg); + + return to_gt(i915)->clock_frequency << (3 - shift); + } + + return to_gt(i915)->clock_frequency; +} + /** * i915_oa_stream_init - validate combined props for OA stream and init * @stream: An i915 perf stream @@ -3830,8 +3854,10 @@ err: static u64 oa_exponent_to_ns(struct i915_perf *perf, int exponent) { - return intel_gt_clock_interval_to_ns(to_gt(perf->i915), - 2ULL << exponent); + u64 nom = (2ULL << exponent) * NSEC_PER_SEC; + u32 den = i915_perf_oa_timestamp_frequency(perf->i915); + + return div_u64(nom + den - 1, den); } static __always_inline bool diff --git a/drivers/gpu/drm/i915/i915_perf.h b/drivers/gpu/drm/i915/i915_perf.h index 1d1329e5af3a..f96e09a4af04 100644 --- a/drivers/gpu/drm/i915/i915_perf.h +++ b/drivers/gpu/drm/i915/i915_perf.h @@ -57,4 +57,6 @@ static inline void i915_oa_config_put(struct i915_oa_config *oa_config) kref_put(&oa_config->ref, i915_oa_config_release); } +u32 i915_perf_oa_timestamp_frequency(struct drm_i915_private *i915); + #endif /* __I915_PERF_H__ */ diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index b946674c68cc..8df261c5ab9b 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -765,6 +765,12 @@ typedef struct drm_i915_irq_wait { /* Query if the kernel supports the I915_USERPTR_PROBE flag. */ #define I915_PARAM_HAS_USERPTR_PROBE 56 +/* + * Frequency of the timestamps in OA reports. This used to be the same as the CS + * timestamp frequency, but differs on some platforms. + */ +#define I915_PARAM_OA_TIMESTAMP_FREQUENCY 57 + /* Must be kept compact -- no holes and well documented */ /** -- cgit From fa569804341803032d260de3570bc6bc1698b790 Mon Sep 17 00:00:00 2001 From: Umesh Nerlige Ramappa Date: Wed, 26 Oct 2022 22:20:59 +0000 Subject: drm/i915/perf: Save/restore EU flex counters across reset If a drm client is killed, then hw contexts used by the client are reset immediately. This reset clears the EU flex counter configuration. If an OA use case is running in parallel, it would start seeing zeroed eu counter values following the reset even if the drm client is restarted. Save/restore the EU flex counter config so that the EU counters can be monitored continuously across resets. v2: - Save/restore eu flex config only for gen12, as for pre-gen12, these are saved and restored in the context image. Signed-off-by: Umesh Nerlige Ramappa Reviewed-by: Ashutosh Dixit Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20221026222102.5526-14-umesh.nerlige.ramappa@intel.com --- drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c index 34ef4f36e660..a419d60166c8 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c @@ -392,6 +392,16 @@ static int guc_mmio_regset_init(struct temp_regset *regset, else ret |= GUC_MMIO_REG_ADD(gt, regset, GEN9_LNCFCMOCS(i), false); + if (GRAPHICS_VER(engine->i915) >= 12) { + ret |= GUC_MMIO_REG_ADD(gt, regset, EU_PERF_CNTL0, false); + ret |= GUC_MMIO_REG_ADD(gt, regset, EU_PERF_CNTL1, false); + ret |= GUC_MMIO_REG_ADD(gt, regset, EU_PERF_CNTL2, false); + ret |= GUC_MMIO_REG_ADD(gt, regset, EU_PERF_CNTL3, false); + ret |= GUC_MMIO_REG_ADD(gt, regset, EU_PERF_CNTL4, false); + ret |= GUC_MMIO_REG_ADD(gt, regset, EU_PERF_CNTL5, false); + ret |= GUC_MMIO_REG_ADD(gt, regset, EU_PERF_CNTL6, false); + } + return ret ? -1 : 0; } -- cgit From 01e7427467857861d1aaa7cd05598dfcb631c5b5 Mon Sep 17 00:00:00 2001 From: Vinay Belgaumkar Date: Wed, 26 Oct 2022 22:21:00 +0000 Subject: drm/i915/guc: Support OA when Wa_16011777198 is enabled On DG2, a w/a resets RCS/CCS before it goes into RC6. This breaks OA since OA does not expect engine resets during its use. Fix it by disabling RC6. v2: (Ashutosh) - Bring back slpc_unset_param helper - Update commit msg - Use with_intel_runtime_pm helper for set/unset v3: (Ashutosh) - Just use intel_uc_uses_guc_rc Signed-off-by: Vinay Belgaumkar Signed-off-by: Umesh Nerlige Ramappa Reviewed-by: Ashutosh Dixit Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20221026222102.5526-15-umesh.nerlige.ramappa@intel.com --- .../gpu/drm/i915/gt/uc/abi/guc_actions_slpc_abi.h | 9 +++ drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c | 66 ++++++++++++++++++++++ drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.h | 2 + drivers/gpu/drm/i915/i915_perf.c | 27 +++++++++ 4 files changed, 104 insertions(+) diff --git a/drivers/gpu/drm/i915/gt/uc/abi/guc_actions_slpc_abi.h b/drivers/gpu/drm/i915/gt/uc/abi/guc_actions_slpc_abi.h index 4c840a2639dc..811add10c30d 100644 --- a/drivers/gpu/drm/i915/gt/uc/abi/guc_actions_slpc_abi.h +++ b/drivers/gpu/drm/i915/gt/uc/abi/guc_actions_slpc_abi.h @@ -128,6 +128,15 @@ enum slpc_media_ratio_mode { SLPC_MEDIA_RATIO_MODE_FIXED_ONE_TO_TWO = 2, }; +enum slpc_gucrc_mode { + SLPC_GUCRC_MODE_HW = 0, + SLPC_GUCRC_MODE_GUCRC_NO_RC6 = 1, + SLPC_GUCRC_MODE_GUCRC_STATIC_TIMEOUT = 2, + SLPC_GUCRC_MODE_GUCRC_DYNAMIC_HYSTERESIS = 3, + + SLPC_GUCRC_MODE_MAX, +}; + enum slpc_event_id { SLPC_EVENT_RESET = 0, SLPC_EVENT_SHUTDOWN = 1, diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c index c7e568af1e9c..63464933cbce 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c @@ -137,6 +137,17 @@ static int guc_action_slpc_set_param(struct intel_guc *guc, u8 id, u32 value) return ret > 0 ? -EPROTO : ret; } +static int guc_action_slpc_unset_param(struct intel_guc *guc, u8 id) +{ + u32 request[] = { + GUC_ACTION_HOST2GUC_PC_SLPC_REQUEST, + SLPC_EVENT(SLPC_EVENT_PARAMETER_UNSET, 1), + id, + }; + + return intel_guc_send(guc, request, ARRAY_SIZE(request)); +} + static bool slpc_is_running(struct intel_guc_slpc *slpc) { return slpc_get_state(slpc) == SLPC_GLOBAL_STATE_RUNNING; @@ -190,6 +201,15 @@ static int slpc_set_param(struct intel_guc_slpc *slpc, u8 id, u32 value) return ret; } +static int slpc_unset_param(struct intel_guc_slpc *slpc, u8 id) +{ + struct intel_guc *guc = slpc_to_guc(slpc); + + GEM_BUG_ON(id >= SLPC_MAX_PARAM); + + return guc_action_slpc_unset_param(guc, id); +} + static int slpc_force_min_freq(struct intel_guc_slpc *slpc, u32 freq) { struct drm_i915_private *i915 = slpc_to_i915(slpc); @@ -644,6 +664,52 @@ static void slpc_get_rp_values(struct intel_guc_slpc *slpc) slpc->boost_freq = slpc->rp0_freq; } +/** + * intel_guc_slpc_override_gucrc_mode() - override GUCRC mode + * @slpc: pointer to intel_guc_slpc. + * @mode: new value of the mode. + * + * This function will override the GUCRC mode. + * + * Return: 0 on success, non-zero error code on failure. + */ +int intel_guc_slpc_override_gucrc_mode(struct intel_guc_slpc *slpc, u32 mode) +{ + int ret; + struct drm_i915_private *i915 = slpc_to_i915(slpc); + intel_wakeref_t wakeref; + + if (mode >= SLPC_GUCRC_MODE_MAX) + return -EINVAL; + + with_intel_runtime_pm(&i915->runtime_pm, wakeref) { + ret = slpc_set_param(slpc, SLPC_PARAM_PWRGATE_RC_MODE, mode); + if (ret) + drm_err(&i915->drm, + "Override gucrc mode %d failed %d\n", + mode, ret); + } + + return ret; +} + +int intel_guc_slpc_unset_gucrc_mode(struct intel_guc_slpc *slpc) +{ + struct drm_i915_private *i915 = slpc_to_i915(slpc); + intel_wakeref_t wakeref; + int ret = 0; + + with_intel_runtime_pm(&i915->runtime_pm, wakeref) { + ret = slpc_unset_param(slpc, SLPC_PARAM_PWRGATE_RC_MODE); + if (ret) + drm_err(&i915->drm, + "Unsetting gucrc mode failed %d\n", + ret); + } + + return ret; +} + /* * intel_guc_slpc_enable() - Start SLPC * @slpc: pointer to intel_guc_slpc. diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.h index 11975a31c9d0..17ed515f6a85 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.h @@ -44,5 +44,7 @@ int intel_guc_slpc_set_media_ratio_mode(struct intel_guc_slpc *slpc, u32 val); void intel_guc_pm_intrmsk_enable(struct intel_gt *gt); void intel_guc_slpc_boost(struct intel_guc_slpc *slpc); void intel_guc_slpc_dec_waiters(struct intel_guc_slpc *slpc); +int intel_guc_slpc_unset_gucrc_mode(struct intel_guc_slpc *slpc); +int intel_guc_slpc_override_gucrc_mode(struct intel_guc_slpc *slpc, u32 mode); #endif diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index b73d91b792df..b2766485888f 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -209,6 +209,7 @@ #include "gt/intel_lrc.h" #include "gt/intel_lrc_reg.h" #include "gt/intel_ring.h" +#include "gt/uc/intel_guc_slpc.h" #include "i915_drv.h" #include "i915_file_private.h" @@ -1582,6 +1583,15 @@ static void i915_oa_stream_destroy(struct i915_perf_stream *stream) free_oa_buffer(stream); + /* + * Wa_16011777198:dg2: Unset the override of GUCRC mode to enable rc6. + */ + if (intel_uc_uses_guc_rc(>->uc) && + (IS_DG2_GRAPHICS_STEP(gt->i915, G10, STEP_A0, STEP_C0) || + IS_DG2_GRAPHICS_STEP(gt->i915, G11, STEP_A0, STEP_B0))) + drm_WARN_ON(>->i915->drm, + intel_guc_slpc_unset_gucrc_mode(>->uc.guc.slpc)); + intel_uncore_forcewake_put(stream->uncore, FORCEWAKE_ALL); intel_engine_pm_put(stream->engine); @@ -3265,6 +3275,23 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream, intel_engine_pm_get(stream->engine); intel_uncore_forcewake_get(stream->uncore, FORCEWAKE_ALL); + /* + * Wa_16011777198:dg2: GuC resets render as part of the Wa. This causes + * OA to lose the configuration state. Prevent this by overriding GUCRC + * mode. + */ + if (intel_uc_uses_guc_rc(>->uc) && + (IS_DG2_GRAPHICS_STEP(gt->i915, G10, STEP_A0, STEP_C0) || + IS_DG2_GRAPHICS_STEP(gt->i915, G11, STEP_A0, STEP_B0))) { + ret = intel_guc_slpc_override_gucrc_mode(>->uc.guc.slpc, + SLPC_GUCRC_MODE_GUCRC_NO_RC6); + if (ret) { + drm_dbg(&stream->perf->i915->drm, + "Unable to override gucrc mode\n"); + goto err_config; + } + } + ret = alloc_oa_buffer(stream); if (ret) goto err_oa_buf_alloc; -- cgit From 0fa9349dda030fa847b36f880a5eea25c3202b66 Mon Sep 17 00:00:00 2001 From: Lionel Landwerlin Date: Wed, 26 Oct 2022 22:21:01 +0000 Subject: drm/i915/perf: complete programming whitelisting for XEHPSDV We have an additional register to select which slices contribute to OAG/OAG counter increments. Signed-off-by: Lionel Landwerlin Signed-off-by: Matt Roper Reviewed-by: Ashutosh Dixit Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20221026222102.5526-16-umesh.nerlige.ramappa@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/i915_pci.c | 1 + drivers/gpu/drm/i915/i915_perf.c | 13 +++++++++++++ drivers/gpu/drm/i915/intel_device_info.h | 1 + 4 files changed, 17 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 34f0bcc36671..b1c4e924d883 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -903,6 +903,8 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915, #define HAS_OA_BPC_REPORTING(dev_priv) \ (INTEL_INFO(dev_priv)->has_oa_bpc_reporting) +#define HAS_OA_SLICE_CONTRIB_LIMITS(dev_priv) \ + (INTEL_INFO(dev_priv)->has_oa_slice_contrib_limits) /* * Set this flag, when platform requires 64K GTT page sizes or larger for diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c index 7b751bf4be21..6b22fb506aa9 100644 --- a/drivers/gpu/drm/i915/i915_pci.c +++ b/drivers/gpu/drm/i915/i915_pci.c @@ -1024,6 +1024,7 @@ static const struct intel_device_info adl_p_info = { .has_logical_ring_elsq = 1, \ .has_mslice_steering = 1, \ .has_oa_bpc_reporting = 1, \ + .has_oa_slice_contrib_limits = 1, \ .has_rc6 = 1, \ .has_reset_engine = 1, \ .has_rps = 1, \ diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index b2766485888f..2db74b5a54cd 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -4261,6 +4261,11 @@ static const struct i915_range gen12_oa_b_counters[] = { {} }; +static const struct i915_range xehp_oa_b_counters[] = { + { .start = 0xdc48, .end = 0xdc48 }, /* OAA_ENABLE_REG */ + { .start = 0xdd00, .end = 0xdd48 }, /* OAG_LCE0_0 - OAA_LENABLE_REG */ +}; + static const struct i915_range gen7_oa_mux_regs[] = { { .start = 0x91b8, .end = 0x91cc }, /* OA_PERFCNT[1-2], OA_PERFMATRIX */ { .start = 0x9800, .end = 0x9888 }, /* MICRO_BP0_0 - NOA_WRITE */ @@ -4335,6 +4340,12 @@ static bool gen12_is_valid_b_counter_addr(struct i915_perf *perf, u32 addr) return reg_in_range_table(addr, gen12_oa_b_counters); } +static bool xehp_is_valid_b_counter_addr(struct i915_perf *perf, u32 addr) +{ + return reg_in_range_table(addr, xehp_oa_b_counters) || + reg_in_range_table(addr, gen12_oa_b_counters); +} + static bool gen12_is_valid_mux_addr(struct i915_perf *perf, u32 addr) { return reg_in_range_table(addr, gen12_oa_mux_regs); @@ -4847,6 +4858,8 @@ void i915_perf_init(struct drm_i915_private *i915) perf->ops.oa_hw_tail_read = gen8_oa_hw_tail_read; } else if (GRAPHICS_VER(i915) == 12) { perf->ops.is_valid_b_counter_reg = + HAS_OA_SLICE_CONTRIB_LIMITS(i915) ? + xehp_is_valid_b_counter_addr : gen12_is_valid_b_counter_addr; perf->ops.is_valid_mux_reg = gen12_is_valid_mux_addr; diff --git a/drivers/gpu/drm/i915/intel_device_info.h b/drivers/gpu/drm/i915/intel_device_info.h index d11546d87fe7..4ee6074955ef 100644 --- a/drivers/gpu/drm/i915/intel_device_info.h +++ b/drivers/gpu/drm/i915/intel_device_info.h @@ -164,6 +164,7 @@ enum intel_ppgtt_type { func(has_media_ratio_mode); \ func(has_mslice_steering); \ func(has_oa_bpc_reporting); \ + func(has_oa_slice_contrib_limits); \ func(has_one_eu_per_fuse_bit); \ func(has_pxp); \ func(has_rc6); \ -- cgit From 07b444f57f12177e5df639f55dc1d747f4a635c8 Mon Sep 17 00:00:00 2001 From: Umesh Nerlige Ramappa Date: Wed, 26 Oct 2022 22:21:02 +0000 Subject: drm/i915/perf: Enable OA for DG2 OA was disabled for DG2 as support was missing. Enable it back now. Signed-off-by: Umesh Nerlige Ramappa Reviewed-by: Ashutosh Dixit Signed-off-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20221026222102.5526-17-umesh.nerlige.ramappa@intel.com --- drivers/gpu/drm/i915/i915_perf.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index 2db74b5a54cd..0dd597a7a11f 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -4798,12 +4798,6 @@ void i915_perf_init(struct drm_i915_private *i915) { struct i915_perf *perf = &i915->perf; - /* XXX const struct i915_perf_ops! */ - - /* i915_perf is not enabled for DG2 yet */ - if (IS_DG2(i915)) - return; - perf->oa_formats = oa_formats; if (IS_HASWELL(i915)) { perf->ops.is_valid_b_counter_reg = gen7_is_valid_b_counter_addr; -- cgit From bc63897bc33b81897c7f8f5965c8f9326457d082 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 27 Oct 2022 14:52:41 +0200 Subject: firmware: raspberrypi: Introduce rpi_firmware_find_node() A significant number of RaspberryPi drivers using the firmware don't have a phandle to it, so end up scanning the device tree to find a node with the firmware compatible. That code is duplicated everywhere, so let's introduce a helper instead. Acked-by: Florian Fainelli Link: https://lore.kernel.org/r/20220815-rpi-fix-4k-60-v5-1-fe9e7ac8b111@cerno.tech Signed-off-by: Maxime Ripard --- drivers/firmware/raspberrypi.c | 18 ++++++++++++------ include/soc/bcm2835/raspberrypi-firmware.h | 7 +++++++ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c index 4b8978b254f9..932a8bef22fb 100644 --- a/drivers/firmware/raspberrypi.c +++ b/drivers/firmware/raspberrypi.c @@ -311,6 +311,18 @@ static int rpi_firmware_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id rpi_firmware_of_match[] = { + { .compatible = "raspberrypi,bcm2835-firmware", }, + {}, +}; +MODULE_DEVICE_TABLE(of, rpi_firmware_of_match); + +struct device_node *rpi_firmware_find_node(void) +{ + return of_find_matching_node(NULL, rpi_firmware_of_match); +} +EXPORT_SYMBOL_GPL(rpi_firmware_find_node); + /** * rpi_firmware_get - Get pointer to rpi_firmware structure. * @firmware_node: Pointer to the firmware Device Tree node. @@ -366,12 +378,6 @@ struct rpi_firmware *devm_rpi_firmware_get(struct device *dev, } EXPORT_SYMBOL_GPL(devm_rpi_firmware_get); -static const struct of_device_id rpi_firmware_of_match[] = { - { .compatible = "raspberrypi,bcm2835-firmware", }, - {}, -}; -MODULE_DEVICE_TABLE(of, rpi_firmware_of_match); - static struct platform_driver rpi_firmware_driver = { .driver = { .name = "raspberrypi-firmware", diff --git a/include/soc/bcm2835/raspberrypi-firmware.h b/include/soc/bcm2835/raspberrypi-firmware.h index 811ea668c4a1..63426082bcb9 100644 --- a/include/soc/bcm2835/raspberrypi-firmware.h +++ b/include/soc/bcm2835/raspberrypi-firmware.h @@ -142,6 +142,7 @@ int rpi_firmware_property(struct rpi_firmware *fw, int rpi_firmware_property_list(struct rpi_firmware *fw, void *data, size_t tag_size); void rpi_firmware_put(struct rpi_firmware *fw); +struct device_node *rpi_firmware_find_node(void); struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node); struct rpi_firmware *devm_rpi_firmware_get(struct device *dev, struct device_node *firmware_node); @@ -159,6 +160,12 @@ static inline int rpi_firmware_property_list(struct rpi_firmware *fw, } static inline void rpi_firmware_put(struct rpi_firmware *fw) { } + +static inline struct device_node *rpi_firmware_find_node(void) +{ + return NULL; +} + static inline struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node) { return NULL; -- cgit From d0cde9b3b0cae06f5998f6d3936e90a80d05b2ec Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 27 Oct 2022 14:52:42 +0200 Subject: firmware: raspberrypi: Move the clock IDs to the firmware header We'll need the clock IDs in more drivers than just the clock driver from now on, so let's move them in the firmware header. Reviewed-by: Florian Fainelli Acked-by: Stephen Boyd Link: https://lore.kernel.org/r/20220815-rpi-fix-4k-60-v5-2-fe9e7ac8b111@cerno.tech Signed-off-by: Maxime Ripard --- drivers/clk/bcm/clk-raspberrypi.c | 19 ------------------- include/soc/bcm2835/raspberrypi-firmware.h | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/clk/bcm/clk-raspberrypi.c b/drivers/clk/bcm/clk-raspberrypi.c index 679f4649a7ef..ce2f93479736 100644 --- a/drivers/clk/bcm/clk-raspberrypi.c +++ b/drivers/clk/bcm/clk-raspberrypi.c @@ -18,25 +18,6 @@ #include -enum rpi_firmware_clk_id { - RPI_FIRMWARE_EMMC_CLK_ID = 1, - RPI_FIRMWARE_UART_CLK_ID, - RPI_FIRMWARE_ARM_CLK_ID, - RPI_FIRMWARE_CORE_CLK_ID, - RPI_FIRMWARE_V3D_CLK_ID, - RPI_FIRMWARE_H264_CLK_ID, - RPI_FIRMWARE_ISP_CLK_ID, - RPI_FIRMWARE_SDRAM_CLK_ID, - RPI_FIRMWARE_PIXEL_CLK_ID, - RPI_FIRMWARE_PWM_CLK_ID, - RPI_FIRMWARE_HEVC_CLK_ID, - RPI_FIRMWARE_EMMC2_CLK_ID, - RPI_FIRMWARE_M2MC_CLK_ID, - RPI_FIRMWARE_PIXEL_BVB_CLK_ID, - RPI_FIRMWARE_VEC_CLK_ID, - RPI_FIRMWARE_NUM_CLK_ID, -}; - static char *rpi_firmware_clk_names[] = { [RPI_FIRMWARE_EMMC_CLK_ID] = "emmc", [RPI_FIRMWARE_UART_CLK_ID] = "uart", diff --git a/include/soc/bcm2835/raspberrypi-firmware.h b/include/soc/bcm2835/raspberrypi-firmware.h index 63426082bcb9..9b1db12d013f 100644 --- a/include/soc/bcm2835/raspberrypi-firmware.h +++ b/include/soc/bcm2835/raspberrypi-firmware.h @@ -136,6 +136,25 @@ enum rpi_firmware_property_tag { RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001, }; +enum rpi_firmware_clk_id { + RPI_FIRMWARE_EMMC_CLK_ID = 1, + RPI_FIRMWARE_UART_CLK_ID, + RPI_FIRMWARE_ARM_CLK_ID, + RPI_FIRMWARE_CORE_CLK_ID, + RPI_FIRMWARE_V3D_CLK_ID, + RPI_FIRMWARE_H264_CLK_ID, + RPI_FIRMWARE_ISP_CLK_ID, + RPI_FIRMWARE_SDRAM_CLK_ID, + RPI_FIRMWARE_PIXEL_CLK_ID, + RPI_FIRMWARE_PWM_CLK_ID, + RPI_FIRMWARE_HEVC_CLK_ID, + RPI_FIRMWARE_EMMC2_CLK_ID, + RPI_FIRMWARE_M2MC_CLK_ID, + RPI_FIRMWARE_PIXEL_BVB_CLK_ID, + RPI_FIRMWARE_VEC_CLK_ID, + RPI_FIRMWARE_NUM_CLK_ID, +}; + #if IS_ENABLED(CONFIG_RASPBERRYPI_FIRMWARE) int rpi_firmware_property(struct rpi_firmware *fw, u32 tag, void *data, size_t len); -- cgit From 40c31955e4e9ff268d21c0a8009e35f4cfaa167c Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 27 Oct 2022 14:52:43 +0200 Subject: firmware: raspberrypi: Provide a helper to query a clock max rate The firmware allows to query for its clocks the operating range of a given clock. We'll need this for some drivers (KMS, in particular) to infer the state of some configuration options, so let's create a function to do so. Acked-by: Stephen Boyd Reviewed-by: Florian Fainelli Acked-by: Florian Fainelli Link: https://lore.kernel.org/r/20220815-rpi-fix-4k-60-v5-3-fe9e7ac8b111@cerno.tech Signed-off-by: Maxime Ripard --- drivers/firmware/raspberrypi.c | 20 ++++++++++++++++++++ include/soc/bcm2835/raspberrypi-firmware.h | 26 ++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c index 932a8bef22fb..b15aa6fce0e9 100644 --- a/drivers/firmware/raspberrypi.c +++ b/drivers/firmware/raspberrypi.c @@ -228,6 +228,26 @@ static void rpi_register_clk_driver(struct device *dev) -1, NULL, 0); } +unsigned int rpi_firmware_clk_get_max_rate(struct rpi_firmware *fw, unsigned int id) +{ + struct rpi_firmware_clk_rate_request msg = + RPI_FIRMWARE_CLK_RATE_REQUEST(id); + int ret; + + ret = rpi_firmware_property(fw, RPI_FIRMWARE_GET_MAX_CLOCK_RATE, + &msg, sizeof(msg)); + if (ret) + /* + * If our firmware doesn't support that operation, or fails, we + * assume the maximum clock rate is absolute maximum we can + * store over our type. + */ + return UINT_MAX; + + return le32_to_cpu(msg.rate); +} +EXPORT_SYMBOL_GPL(rpi_firmware_clk_get_max_rate); + static void rpi_firmware_delete(struct kref *kref) { struct rpi_firmware *fw = container_of(kref, struct rpi_firmware, diff --git a/include/soc/bcm2835/raspberrypi-firmware.h b/include/soc/bcm2835/raspberrypi-firmware.h index 9b1db12d013f..ab955591cb72 100644 --- a/include/soc/bcm2835/raspberrypi-firmware.h +++ b/include/soc/bcm2835/raspberrypi-firmware.h @@ -155,12 +155,32 @@ enum rpi_firmware_clk_id { RPI_FIRMWARE_NUM_CLK_ID, }; +/** + * struct rpi_firmware_clk_rate_request - Firmware Request for a rate + * @id: ID of the clock being queried + * @rate: Rate in Hertz. Set by the firmware. + * + * Used by @RPI_FIRMWARE_GET_CLOCK_RATE, @RPI_FIRMWARE_GET_CLOCK_MEASURED, + * @RPI_FIRMWARE_GET_MAX_CLOCK_RATE and @RPI_FIRMWARE_GET_MIN_CLOCK_RATE. + */ +struct rpi_firmware_clk_rate_request { + __le32 id; + __le32 rate; +} __packed; + +#define RPI_FIRMWARE_CLK_RATE_REQUEST(_id) \ + { \ + .id = _id, \ + } + #if IS_ENABLED(CONFIG_RASPBERRYPI_FIRMWARE) int rpi_firmware_property(struct rpi_firmware *fw, u32 tag, void *data, size_t len); int rpi_firmware_property_list(struct rpi_firmware *fw, void *data, size_t tag_size); void rpi_firmware_put(struct rpi_firmware *fw); +unsigned int rpi_firmware_clk_get_max_rate(struct rpi_firmware *fw, + unsigned int id); struct device_node *rpi_firmware_find_node(void); struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node); struct rpi_firmware *devm_rpi_firmware_get(struct device *dev, @@ -180,6 +200,12 @@ static inline int rpi_firmware_property_list(struct rpi_firmware *fw, static inline void rpi_firmware_put(struct rpi_firmware *fw) { } +static inline unsigned int rpi_firmware_clk_get_max_rate(struct rpi_firmware *fw, + unsigned int id) +{ + return UINT_MAX; +} + static inline struct device_node *rpi_firmware_find_node(void) { return NULL; -- cgit From dd51d3a33c10925b20d4b9b665a6f4a65f24ca67 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 27 Oct 2022 14:52:44 +0200 Subject: drm/vc4: hdmi: Fix hdmi_enable_4kp60 detection In order to support higher HDMI frequencies, users have to set the hdmi_enable_4kp60 parameter in their config.txt file. We were detecting this so far by calling clk_round_rate() on the core clock with the frequency we're supposed to run at when one of those modes is enabled. Whether or not the parameter was enabled could then be inferred by the returned rate since the maximum clock rate reported by the firmware was one of the side effect of setting that parameter. However, the recent clock rework we did changed what clk_round_rate() was returning to always return the minimum allowed, and thus this test wasn't reliable anymore. Let's use the new clk_get_max_rate() function to reliably determine the maximum rate allowed on that clock and fix the 4k@60Hz output. Fixes: e9d6cea2af1c ("clk: bcm: rpi: Run some clocks at the minimum rate allowed") Reviewed-by: Dave Stevenson Link: https://lore.kernel.org/r/20220815-rpi-fix-4k-60-v5-4-fe9e7ac8b111@cerno.tech Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 99908137dbe7..88ae3a0cfcfe 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -3429,7 +3430,7 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) if (variant->max_pixel_clock == 600000000) { struct vc4_dev *vc4 = to_vc4_dev(drm); - long max_rate = clk_round_rate(vc4->hvs->core_clk, 550000000); + unsigned int max_rate = rpi_firmware_clk_get_max_rate(vc4->hvs->core_clk); if (max_rate < 550000000) vc4_hdmi->disable_4kp60 = true; -- cgit From 2a001ca00ad55fd9e0fc96d84f57b894a4c34388 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 27 Oct 2022 14:52:45 +0200 Subject: drm/vc4: hdmi: Rework hdmi_enable_4kp60 detection code In order to support higher HDMI frequencies, users have to set the hdmi_enable_4kp60 parameter in their config.txt file. This will have the side-effect of raising the maximum of the core clock, tied to the HVS, and managed by the HVS driver. However, we are querying this in the HDMI driver by poking into the HVS structure to get our struct clk handle. Let's make this part of the HVS bind implementation to have all the core clock related setup in the same place. Reviewed-by: Dave Stevenson Link: https://lore.kernel.org/r/20220815-rpi-fix-4k-60-v5-5-fe9e7ac8b111@cerno.tech Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_drv.h | 10 ++++++++++ drivers/gpu/drm/vc4/vc4_hdmi.c | 15 ++++----------- drivers/gpu/drm/vc4/vc4_hdmi.h | 8 -------- drivers/gpu/drm/vc4/vc4_hvs.c | 23 +++++++++++++++++++++++ 4 files changed, 37 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index 418a8242691f..8da2b80fdbd3 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -326,6 +326,8 @@ struct vc4_hvs { struct clk *core_clk; + unsigned long max_core_rate; + /* Memory manager for CRTCs to allocate space in the display * list. Units are dwords. */ @@ -337,6 +339,14 @@ struct vc4_hvs { struct drm_mm_node mitchell_netravali_filter; struct debugfs_regset32 regset; + + /* + * Even if HDMI0 on the RPi4 can output modes requiring a pixel + * rate higher than 297MHz, it needs some adjustments in the + * config.txt file to be able to do so and thus won't always be + * available. + */ + bool vc5_hdmi_enable_hdmi_20; }; struct vc4_plane { diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 88ae3a0cfcfe..3114735df5ae 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -46,7 +46,6 @@ #include #include #include -#include #include #include #include @@ -460,6 +459,7 @@ static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector, static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) { struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector); + struct vc4_dev *vc4 = to_vc4_dev(connector->dev); int ret = 0; struct edid *edid; @@ -483,7 +483,7 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) ret = drm_add_edid_modes(connector, edid); kfree(edid); - if (vc4_hdmi->disable_4kp60) { + if (!vc4->hvs->vc5_hdmi_enable_hdmi_20) { struct drm_device *drm = connector->dev; const struct drm_display_mode *mode; @@ -1757,11 +1757,12 @@ vc4_hdmi_encoder_clock_valid(const struct vc4_hdmi *vc4_hdmi, { const struct drm_connector *connector = &vc4_hdmi->connector; const struct drm_display_info *info = &connector->display_info; + struct vc4_dev *vc4 = to_vc4_dev(connector->dev); if (clock > vc4_hdmi->variant->max_pixel_clock) return MODE_CLOCK_HIGH; - if (vc4_hdmi->disable_4kp60 && clock > HDMI_14_MAX_TMDS_CLK) + if (!vc4->hvs->vc5_hdmi_enable_hdmi_20 && clock > HDMI_14_MAX_TMDS_CLK) return MODE_CLOCK_HIGH; if (info->max_tmds_clock && clock > (info->max_tmds_clock * 1000)) @@ -3428,14 +3429,6 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) vc4_hdmi->disable_wifi_frequencies = of_property_read_bool(dev->of_node, "wifi-2.4ghz-coexistence"); - if (variant->max_pixel_clock == 600000000) { - struct vc4_dev *vc4 = to_vc4_dev(drm); - unsigned int max_rate = rpi_firmware_clk_get_max_rate(vc4->hvs->core_clk); - - if (max_rate < 550000000) - vc4_hdmi->disable_4kp60 = true; - } - ret = devm_pm_runtime_enable(dev); if (ret) return ret; diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h index db823efb2563..e3619836ca17 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h @@ -156,14 +156,6 @@ struct vc4_hdmi { */ bool disable_wifi_frequencies; - /* - * Even if HDMI0 on the RPi4 can output modes requiring a pixel - * rate higher than 297MHz, it needs some adjustments in the - * config.txt file to be able to do so and thus won't always be - * available. - */ - bool disable_4kp60; - struct cec_adapter *cec_adap; struct cec_msg cec_rx_msg; bool cec_tx_ok; diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c index 4ac9f5a2d5f9..fc4b7310bf63 100644 --- a/drivers/gpu/drm/vc4/vc4_hvs.c +++ b/drivers/gpu/drm/vc4/vc4_hvs.c @@ -28,6 +28,8 @@ #include #include +#include + #include "vc4_drv.h" #include "vc4_regs.h" @@ -791,12 +793,33 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) hvs->regset.nregs = ARRAY_SIZE(hvs_regs); if (vc4->is_vc5) { + struct rpi_firmware *firmware; + struct device_node *node; + unsigned int max_rate; + + node = rpi_firmware_find_node(); + if (!node) + return -EINVAL; + + firmware = rpi_firmware_get(node); + of_node_put(node); + if (!firmware) + return -EPROBE_DEFER; + hvs->core_clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(hvs->core_clk)) { dev_err(&pdev->dev, "Couldn't get core clock\n"); return PTR_ERR(hvs->core_clk); } + max_rate = rpi_firmware_clk_get_max_rate(firmware, + RPI_FIRMWARE_CORE_CLK_ID); + rpi_firmware_put(firmware); + if (max_rate >= 550000000) + hvs->vc5_hdmi_enable_hdmi_20 = true; + + hvs->max_core_rate = max_rate; + ret = clk_prepare_enable(hvs->core_clk); if (ret) { dev_err(&pdev->dev, "Couldn't enable the core clock\n"); -- cgit From f09e172da85854d71284638d8ca25f0b3a980cb6 Mon Sep 17 00:00:00 2001 From: Dom Cobley Date: Thu, 27 Oct 2022 14:52:46 +0200 Subject: drm/vc4: hdmi: Add more checks for 4k resolutions At least the 4096x2160@60Hz mode requires some overclocking that isn't available by default, even if hdmi_enable_4kp60 is enabled. Let's add some logic to detect whether we can satisfy the core clock requirements for that mode, and prevent it from being used otherwise. Signed-off-by: Dom Cobley Reviewed-by: Dave Stevenson Link: https://lore.kernel.org/r/20220815-rpi-fix-4k-60-v5-6-fe9e7ac8b111@cerno.tech Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_drv.h | 6 ++++++ drivers/gpu/drm/vc4/vc4_hdmi.c | 11 +++++++++-- drivers/gpu/drm/vc4/vc4_hvs.c | 3 +++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index 8da2b80fdbd3..515228682e8e 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -347,6 +347,12 @@ struct vc4_hvs { * available. */ bool vc5_hdmi_enable_hdmi_20; + + /* + * 4096x2160@60 requires a core overclock to work, so register + * whether that is sufficient. + */ + bool vc5_hdmi_enable_4096by2160; }; struct vc4_plane { diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 3114735df5ae..4a73fafca51b 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -1753,6 +1753,7 @@ vc4_hdmi_sink_supports_format_bpc(const struct vc4_hdmi *vc4_hdmi, static enum drm_mode_status vc4_hdmi_encoder_clock_valid(const struct vc4_hdmi *vc4_hdmi, + const struct drm_display_mode *mode, unsigned long long clock) { const struct drm_connector *connector = &vc4_hdmi->connector; @@ -1765,6 +1766,12 @@ vc4_hdmi_encoder_clock_valid(const struct vc4_hdmi *vc4_hdmi, if (!vc4->hvs->vc5_hdmi_enable_hdmi_20 && clock > HDMI_14_MAX_TMDS_CLK) return MODE_CLOCK_HIGH; + /* 4096x2160@60 is not reliable without overclocking core */ + if (!vc4->hvs->vc5_hdmi_enable_4096by2160 && + mode->hdisplay > 3840 && mode->vdisplay >= 2160 && + drm_mode_vrefresh(mode) >= 50) + return MODE_CLOCK_HIGH; + if (info->max_tmds_clock && clock > (info->max_tmds_clock * 1000)) return MODE_CLOCK_HIGH; @@ -1799,7 +1806,7 @@ vc4_hdmi_encoder_compute_clock(const struct vc4_hdmi *vc4_hdmi, unsigned long long clock; clock = vc4_hdmi_encoder_compute_mode_clock(mode, bpc, fmt); - if (vc4_hdmi_encoder_clock_valid(vc4_hdmi, clock) != MODE_OK) + if (vc4_hdmi_encoder_clock_valid(vc4_hdmi, mode, clock) != MODE_OK) return -EINVAL; vc4_state->tmds_char_rate = clock; @@ -1962,7 +1969,7 @@ vc4_hdmi_encoder_mode_valid(struct drm_encoder *encoder, (mode->hsync_end % 2) || (mode->htotal % 2))) return MODE_H_ILLEGAL; - return vc4_hdmi_encoder_clock_valid(vc4_hdmi, mode->clock * 1000); + return vc4_hdmi_encoder_clock_valid(vc4_hdmi, mode, mode->clock * 1000); } static const struct drm_encoder_helper_funcs vc4_hdmi_encoder_helper_funcs = { diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c index fc4b7310bf63..c4453a5ae163 100644 --- a/drivers/gpu/drm/vc4/vc4_hvs.c +++ b/drivers/gpu/drm/vc4/vc4_hvs.c @@ -818,6 +818,9 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) if (max_rate >= 550000000) hvs->vc5_hdmi_enable_hdmi_20 = true; + if (max_rate >= 600000000) + hvs->vc5_hdmi_enable_4096by2160 = true; + hvs->max_core_rate = max_rate; ret = clk_prepare_enable(hvs->core_clk); -- cgit From fc04142894d1d970e21c6ab3ab663aa51c5a8b7b Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 27 Oct 2022 14:52:47 +0200 Subject: drm/vc4: Make sure we don't end up with a core clock too high Following the clock rate range improvements to the clock framework, trying to set a disjoint range on a clock will now result in an error. Thus, we can't set a minimum rate higher than the maximum reported by the firmware, or clk_set_min_rate() will fail. Thus we need to clamp the rate we are about to ask for to the maximum rate possible on that clock. Reviewed-by: Dave Stevenson Link: https://lore.kernel.org/r/20220815-rpi-fix-4k-60-v5-7-fe9e7ac8b111@cerno.tech Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_kms.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c index 4419e810103d..5c97642ed66a 100644 --- a/drivers/gpu/drm/vc4/vc4_kms.c +++ b/drivers/gpu/drm/vc4/vc4_kms.c @@ -396,8 +396,8 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state) if (vc4->is_vc5) { unsigned long state_rate = max(old_hvs_state->core_clock_rate, new_hvs_state->core_clock_rate); - unsigned long core_rate = max_t(unsigned long, - 500000000, state_rate); + unsigned long core_rate = clamp_t(unsigned long, state_rate, + 500000000, hvs->max_core_rate); drm_dbg(dev, "Raising the core clock at %lu Hz\n", core_rate); @@ -431,14 +431,17 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state) drm_atomic_helper_cleanup_planes(dev, state); if (vc4->is_vc5) { - drm_dbg(dev, "Running the core clock at %lu Hz\n", - new_hvs_state->core_clock_rate); + unsigned long core_rate = min_t(unsigned long, + hvs->max_core_rate, + new_hvs_state->core_clock_rate); + + drm_dbg(dev, "Running the core clock at %lu Hz\n", core_rate); /* * Request a clock rate based on the current HVS * requirements. */ - WARN_ON(clk_set_min_rate(hvs->core_clk, new_hvs_state->core_clock_rate)); + WARN_ON(clk_set_min_rate(hvs->core_clk, core_rate)); drm_dbg(dev, "Core clock actual rate: %lu Hz\n", clk_get_rate(hvs->core_clk)); -- cgit From cc1e66394daaa7e9f005e2487a84e34a39f9308b Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 26 Oct 2022 13:11:27 +0300 Subject: drm/i915/sdvo: Filter out invalid outputs more sensibly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We try to filter out the corresponding xxx1 output if the xxx0 output is not present. But the way that is being done is pretty awkward. Make it less so. Cc: stable@vger.kernel.org Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221026101134.20865-2-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_sdvo.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c index 8852564b5fbf..c38b75fbabd3 100644 --- a/drivers/gpu/drm/i915/display/intel_sdvo.c +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c @@ -2934,16 +2934,33 @@ err: return false; } +static u16 intel_sdvo_filter_output_flags(u16 flags) +{ + flags &= SDVO_OUTPUT_MASK; + + /* SDVO requires XXX1 function may not exist unless it has XXX0 function.*/ + if (!(flags & SDVO_OUTPUT_TMDS0)) + flags &= ~SDVO_OUTPUT_TMDS1; + + if (!(flags & SDVO_OUTPUT_RGB0)) + flags &= ~SDVO_OUTPUT_RGB1; + + if (!(flags & SDVO_OUTPUT_LVDS0)) + flags &= ~SDVO_OUTPUT_LVDS1; + + return flags; +} + static bool intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, u16 flags) { - /* SDVO requires XXX1 function may not exist unless it has XXX0 function.*/ + flags = intel_sdvo_filter_output_flags(flags); if (flags & SDVO_OUTPUT_TMDS0) if (!intel_sdvo_dvi_init(intel_sdvo, 0)) return false; - if ((flags & SDVO_TMDS_MASK) == SDVO_TMDS_MASK) + if (flags & SDVO_OUTPUT_TMDS1) if (!intel_sdvo_dvi_init(intel_sdvo, 1)) return false; @@ -2964,7 +2981,7 @@ intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, u16 flags) if (!intel_sdvo_analog_init(intel_sdvo, 0)) return false; - if ((flags & SDVO_RGB_MASK) == SDVO_RGB_MASK) + if (flags & SDVO_OUTPUT_RGB1) if (!intel_sdvo_analog_init(intel_sdvo, 1)) return false; @@ -2972,11 +2989,11 @@ intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, u16 flags) if (!intel_sdvo_lvds_init(intel_sdvo, 0)) return false; - if ((flags & SDVO_LVDS_MASK) == SDVO_LVDS_MASK) + if (flags & SDVO_OUTPUT_LVDS1) if (!intel_sdvo_lvds_init(intel_sdvo, 1)) return false; - if ((flags & SDVO_OUTPUT_MASK) == 0) { + if (flags == 0) { unsigned char bytes[2]; intel_sdvo->controlled_output = 0; -- cgit From 64b7b557dc8a96d9cfed6aedbf81de2df80c025d Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 26 Oct 2022 13:11:28 +0300 Subject: drm/i915/sdvo: Setup DDC fully before output init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Call intel_sdvo_select_ddc_bus() before initializing any of the outputs. And before that is functional (assuming no VBT) we have to set up the controlled_outputs thing. Otherwise DDC won't be functional during the output init but LVDS really needs it for the fixed mode setup. Note that the whole multi output support still looks very bogus, and more work will be needed to make it correct. But for now this should at least fix the LVDS EDID fixed mode setup. Cc: stable@vger.kernel.org Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/7301 Fixes: aa2b88074a56 ("drm/i915/sdvo: Fix multi function encoder stuff") Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221026101134.20865-3-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_sdvo.c | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c index c38b75fbabd3..e62f41354789 100644 --- a/drivers/gpu/drm/i915/display/intel_sdvo.c +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c @@ -2755,13 +2755,10 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) if (!intel_sdvo_connector) return false; - if (device == 0) { - intel_sdvo->controlled_output |= SDVO_OUTPUT_TMDS0; + if (device == 0) intel_sdvo_connector->output_flag = SDVO_OUTPUT_TMDS0; - } else if (device == 1) { - intel_sdvo->controlled_output |= SDVO_OUTPUT_TMDS1; + else if (device == 1) intel_sdvo_connector->output_flag = SDVO_OUTPUT_TMDS1; - } intel_connector = &intel_sdvo_connector->base; connector = &intel_connector->base; @@ -2816,7 +2813,6 @@ intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, int type) encoder->encoder_type = DRM_MODE_ENCODER_TVDAC; connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO; - intel_sdvo->controlled_output |= type; intel_sdvo_connector->output_flag = type; if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0) { @@ -2857,13 +2853,10 @@ intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device) encoder->encoder_type = DRM_MODE_ENCODER_DAC; connector->connector_type = DRM_MODE_CONNECTOR_VGA; - if (device == 0) { - intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB0; + if (device == 0) intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB0; - } else if (device == 1) { - intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB1; + else if (device == 1) intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB1; - } if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0) { kfree(intel_sdvo_connector); @@ -2893,13 +2886,10 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device) encoder->encoder_type = DRM_MODE_ENCODER_LVDS; connector->connector_type = DRM_MODE_CONNECTOR_LVDS; - if (device == 0) { - intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS0; + if (device == 0) intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS0; - } else if (device == 1) { - intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS1; + else if (device == 1) intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1; - } if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0) { kfree(intel_sdvo_connector); @@ -2954,8 +2944,14 @@ static u16 intel_sdvo_filter_output_flags(u16 flags) static bool intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, u16 flags) { + struct drm_i915_private *i915 = to_i915(intel_sdvo->base.base.dev); + flags = intel_sdvo_filter_output_flags(flags); + intel_sdvo->controlled_output = flags; + + intel_sdvo_select_ddc_bus(i915, intel_sdvo); + if (flags & SDVO_OUTPUT_TMDS0) if (!intel_sdvo_dvi_init(intel_sdvo, 0)) return false; @@ -2996,7 +2992,6 @@ intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, u16 flags) if (flags == 0) { unsigned char bytes[2]; - intel_sdvo->controlled_output = 0; memcpy(bytes, &intel_sdvo->caps.output_flags, 2); DRM_DEBUG_KMS("%s: Unknown SDVO output type (0x%02x%02x)\n", SDVO_NAME(intel_sdvo), @@ -3408,8 +3403,6 @@ bool intel_sdvo_init(struct drm_i915_private *dev_priv, */ intel_sdvo->base.cloneable = 0; - intel_sdvo_select_ddc_bus(dev_priv, intel_sdvo); - /* Set the input timing to the screen. Assume always input 0. */ if (!intel_sdvo_set_target_input(intel_sdvo)) goto err_output; -- cgit From a3cd4f447281c56377de2ee109327400eb00668d Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 26 Oct 2022 13:11:29 +0300 Subject: drm/i915/sdvo: Grab mode_config.mutex during LVDS init to avoid WARNs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drm_mode_probed_add() is unhappy about being called w/o mode_config.mutex. Grab it during LVDS fixed mode setup to silence the WARNs. Cc: stable@vger.kernel.org Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/7301 Fixes: aa2b88074a56 ("drm/i915/sdvo: Fix multi function encoder stuff") Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221026101134.20865-4-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_sdvo.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c index e62f41354789..9b447708d8e8 100644 --- a/drivers/gpu/drm/i915/display/intel_sdvo.c +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c @@ -2908,8 +2908,12 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device) intel_panel_add_vbt_sdvo_fixed_mode(intel_connector); if (!intel_panel_preferred_fixed_mode(intel_connector)) { + mutex_lock(&i915->drm.mode_config.mutex); + intel_ddc_get_modes(connector, &intel_sdvo->ddc); intel_panel_add_edid_fixed_modes(intel_connector, false); + + mutex_unlock(&i915->drm.mode_config.mutex); } intel_panel_init(intel_connector); -- cgit From aa7d827b0c9781d7dc73dc1f793734716b75395b Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 26 Oct 2022 13:11:30 +0300 Subject: drm/i915/sdvo: Simplify output setup debugs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Get rid of this funny byte based dumping of invalid output flags and just dump it as a single hex numbers. Also do that early since all the rest is going to get skipped anyway of the thing is zero. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221026101134.20865-5-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_sdvo.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c index 9b447708d8e8..116854ad29c5 100644 --- a/drivers/gpu/drm/i915/display/intel_sdvo.c +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c @@ -199,7 +199,7 @@ to_intel_sdvo_connector(struct drm_connector *connector) container_of((conn_state), struct intel_sdvo_connector_state, base.base) static bool -intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, u16 flags); +intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo); static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo, struct intel_sdvo_connector *intel_sdvo_connector, @@ -2946,11 +2946,18 @@ static u16 intel_sdvo_filter_output_flags(u16 flags) } static bool -intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, u16 flags) +intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo) { struct drm_i915_private *i915 = to_i915(intel_sdvo->base.base.dev); + u16 flags; - flags = intel_sdvo_filter_output_flags(flags); + flags = intel_sdvo_filter_output_flags(intel_sdvo->caps.output_flags); + + if (flags == 0) { + DRM_DEBUG_KMS("%s: Unknown SDVO output type (0x%04x)\n", + SDVO_NAME(intel_sdvo), intel_sdvo->caps.output_flags); + return false; + } intel_sdvo->controlled_output = flags; @@ -2993,15 +3000,6 @@ intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, u16 flags) if (!intel_sdvo_lvds_init(intel_sdvo, 1)) return false; - if (flags == 0) { - unsigned char bytes[2]; - - memcpy(bytes, &intel_sdvo->caps.output_flags, 2); - DRM_DEBUG_KMS("%s: Unknown SDVO output type (0x%02x%02x)\n", - SDVO_NAME(intel_sdvo), - bytes[0], bytes[1]); - return false; - } intel_sdvo->base.pipe_mask = ~0; return true; @@ -3377,8 +3375,7 @@ bool intel_sdvo_init(struct drm_i915_private *dev_priv, intel_sdvo->colorimetry_cap = intel_sdvo_get_colorimetry_cap(intel_sdvo); - if (intel_sdvo_output_setup(intel_sdvo, - intel_sdvo->caps.output_flags) != true) { + if (!intel_sdvo_output_setup(intel_sdvo)) { drm_dbg_kms(&dev_priv->drm, "SDVO output failed to setup on %s\n", SDVO_NAME(intel_sdvo)); -- cgit From 5e52622efb916f3185045283a0203e9b00f8175b Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 26 Oct 2022 13:11:31 +0300 Subject: drm/i915/sdvo: Don't add DDC modes for LVDS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stop enumerating the DDC modes for SDVO LVDS outputs (outside the initial fixed mode setup). intel_panel_mode_valid() will just reject most of them anyway, and any left over are entirely pointless as they'll match the fixed mode hdisp+vdisp+vrefresh so no user visible effect from using them instead of the fixed mode. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221026101134.20865-6-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_sdvo.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c index 116854ad29c5..5742ba22a50c 100644 --- a/drivers/gpu/drm/i915/display/intel_sdvo.c +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c @@ -2299,17 +2299,12 @@ static int intel_sdvo_get_tv_modes(struct drm_connector *connector) static int intel_sdvo_get_lvds_modes(struct drm_connector *connector) { - struct intel_sdvo *intel_sdvo = intel_attached_sdvo(to_intel_connector(connector)); struct drm_i915_private *dev_priv = to_i915(connector->dev); - int num_modes = 0; drm_dbg_kms(&dev_priv->drm, "[CONNECTOR:%d:%s]\n", connector->base.id, connector->name); - num_modes += intel_panel_get_modes(to_intel_connector(connector)); - num_modes += intel_ddc_get_modes(connector, &intel_sdvo->ddc); - - return num_modes; + return intel_panel_get_modes(to_intel_connector(connector)); } static int intel_sdvo_get_modes(struct drm_connector *connector) -- cgit From 739f8dbccf530277e3781a6a352018e972208522 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 26 Oct 2022 13:11:32 +0300 Subject: drm/i915/sdvo: Get rid of the output type<->device index stuff MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Get rid of this silly output type<->device index back and forth and just pass the output type directly to the corresponding output init function. This was already being done for TV outputs anyway. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221026101134.20865-7-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_sdvo.c | 47 +++++++++++++------------------ 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c index 5742ba22a50c..94c297474adb 100644 --- a/drivers/gpu/drm/i915/display/intel_sdvo.c +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c @@ -2631,7 +2631,7 @@ intel_sdvo_unselect_i2c_bus(struct intel_sdvo *sdvo) } static bool -intel_sdvo_is_hdmi_connector(struct intel_sdvo *intel_sdvo, int device) +intel_sdvo_is_hdmi_connector(struct intel_sdvo *intel_sdvo) { return intel_sdvo_check_supp_encode(intel_sdvo); } @@ -2736,7 +2736,7 @@ static struct intel_sdvo_connector *intel_sdvo_connector_alloc(void) } static bool -intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) +intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, u16 type) { struct drm_encoder *encoder = &intel_sdvo->base.base; struct drm_connector *connector; @@ -2744,16 +2744,13 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) struct intel_connector *intel_connector; struct intel_sdvo_connector *intel_sdvo_connector; - DRM_DEBUG_KMS("initialising DVI device %d\n", device); + DRM_DEBUG_KMS("initialising DVI type 0x%x\n", type); intel_sdvo_connector = intel_sdvo_connector_alloc(); if (!intel_sdvo_connector) return false; - if (device == 0) - intel_sdvo_connector->output_flag = SDVO_OUTPUT_TMDS0; - else if (device == 1) - intel_sdvo_connector->output_flag = SDVO_OUTPUT_TMDS1; + intel_sdvo_connector->output_flag = type; intel_connector = &intel_sdvo_connector->base; connector = &intel_connector->base; @@ -2773,7 +2770,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) encoder->encoder_type = DRM_MODE_ENCODER_TMDS; connector->connector_type = DRM_MODE_CONNECTOR_DVID; - if (intel_sdvo_is_hdmi_connector(intel_sdvo, device)) { + if (intel_sdvo_is_hdmi_connector(intel_sdvo)) { connector->connector_type = DRM_MODE_CONNECTOR_HDMIA; intel_sdvo_connector->is_hdmi = true; } @@ -2790,14 +2787,14 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) } static bool -intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, int type) +intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, u16 type) { struct drm_encoder *encoder = &intel_sdvo->base.base; struct drm_connector *connector; struct intel_connector *intel_connector; struct intel_sdvo_connector *intel_sdvo_connector; - DRM_DEBUG_KMS("initialising TV type %d\n", type); + DRM_DEBUG_KMS("initialising TV type 0x%x\n", type); intel_sdvo_connector = intel_sdvo_connector_alloc(); if (!intel_sdvo_connector) @@ -2829,14 +2826,14 @@ err: } static bool -intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device) +intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, u16 type) { struct drm_encoder *encoder = &intel_sdvo->base.base; struct drm_connector *connector; struct intel_connector *intel_connector; struct intel_sdvo_connector *intel_sdvo_connector; - DRM_DEBUG_KMS("initialising analog device %d\n", device); + DRM_DEBUG_KMS("initialising analog type 0x%x\n", type); intel_sdvo_connector = intel_sdvo_connector_alloc(); if (!intel_sdvo_connector) @@ -2848,10 +2845,7 @@ intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device) encoder->encoder_type = DRM_MODE_ENCODER_DAC; connector->connector_type = DRM_MODE_CONNECTOR_VGA; - if (device == 0) - intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB0; - else if (device == 1) - intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB1; + intel_sdvo_connector->output_flag = type; if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0) { kfree(intel_sdvo_connector); @@ -2862,7 +2856,7 @@ intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device) } static bool -intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device) +intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, u16 type) { struct drm_encoder *encoder = &intel_sdvo->base.base; struct drm_i915_private *i915 = to_i915(encoder->dev); @@ -2870,7 +2864,7 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device) struct intel_connector *intel_connector; struct intel_sdvo_connector *intel_sdvo_connector; - DRM_DEBUG_KMS("initialising LVDS device %d\n", device); + DRM_DEBUG_KMS("initialising LVDS type 0x%x\n", type); intel_sdvo_connector = intel_sdvo_connector_alloc(); if (!intel_sdvo_connector) @@ -2881,10 +2875,7 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device) encoder->encoder_type = DRM_MODE_ENCODER_LVDS; connector->connector_type = DRM_MODE_CONNECTOR_LVDS; - if (device == 0) - intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS0; - else if (device == 1) - intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1; + intel_sdvo_connector->output_flag = type; if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0) { kfree(intel_sdvo_connector); @@ -2959,11 +2950,11 @@ intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo) intel_sdvo_select_ddc_bus(i915, intel_sdvo); if (flags & SDVO_OUTPUT_TMDS0) - if (!intel_sdvo_dvi_init(intel_sdvo, 0)) + if (!intel_sdvo_dvi_init(intel_sdvo, SDVO_OUTPUT_TMDS0)) return false; if (flags & SDVO_OUTPUT_TMDS1) - if (!intel_sdvo_dvi_init(intel_sdvo, 1)) + if (!intel_sdvo_dvi_init(intel_sdvo, SDVO_OUTPUT_TMDS1)) return false; /* TV has no XXX1 function block */ @@ -2980,19 +2971,19 @@ intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo) return false; if (flags & SDVO_OUTPUT_RGB0) - if (!intel_sdvo_analog_init(intel_sdvo, 0)) + if (!intel_sdvo_analog_init(intel_sdvo, SDVO_OUTPUT_RGB0)) return false; if (flags & SDVO_OUTPUT_RGB1) - if (!intel_sdvo_analog_init(intel_sdvo, 1)) + if (!intel_sdvo_analog_init(intel_sdvo, SDVO_OUTPUT_RGB1)) return false; if (flags & SDVO_OUTPUT_LVDS0) - if (!intel_sdvo_lvds_init(intel_sdvo, 0)) + if (!intel_sdvo_lvds_init(intel_sdvo, SDVO_OUTPUT_LVDS0)) return false; if (flags & SDVO_OUTPUT_LVDS1) - if (!intel_sdvo_lvds_init(intel_sdvo, 1)) + if (!intel_sdvo_lvds_init(intel_sdvo, SDVO_OUTPUT_LVDS1)) return false; intel_sdvo->base.pipe_mask = ~0; -- cgit From 79708d142e65c59656aa231aa98e00334ced89a5 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 26 Oct 2022 13:11:33 +0300 Subject: drm/i915/sdvo: Reduce copy-pasta in output setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid having to call the output init function for each output type separately. We can just call the right one based on the "class" of the output. Technically we could just walk the bits of the bitmask but that could change the order in which we initialize the outputs. To avoid any behavioural changes keep to the same explicit probe order as before. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221026101134.20865-8-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_sdvo.c | 66 +++++++++++++++---------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c index 94c297474adb..1e06c6fb2c62 100644 --- a/drivers/gpu/drm/i915/display/intel_sdvo.c +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c @@ -2931,11 +2931,38 @@ static u16 intel_sdvo_filter_output_flags(u16 flags) return flags; } +static bool intel_sdvo_output_init(struct intel_sdvo *sdvo, u16 type) +{ + if (type & SDVO_TMDS_MASK) + return intel_sdvo_dvi_init(sdvo, type); + else if (type & SDVO_TV_MASK) + return intel_sdvo_tv_init(sdvo, type); + else if (type & SDVO_RGB_MASK) + return intel_sdvo_analog_init(sdvo, type); + else if (type & SDVO_LVDS_MASK) + return intel_sdvo_lvds_init(sdvo, type); + else + return false; +} + static bool intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo) { + static const u16 probe_order[] = { + SDVO_OUTPUT_TMDS0, + SDVO_OUTPUT_TMDS1, + /* TV has no XXX1 function block */ + SDVO_OUTPUT_SVID0, + SDVO_OUTPUT_CVBS0, + SDVO_OUTPUT_YPRPB0, + SDVO_OUTPUT_RGB0, + SDVO_OUTPUT_RGB1, + SDVO_OUTPUT_LVDS0, + SDVO_OUTPUT_LVDS1, + }; struct drm_i915_private *i915 = to_i915(intel_sdvo->base.base.dev); u16 flags; + int i; flags = intel_sdvo_filter_output_flags(intel_sdvo->caps.output_flags); @@ -2949,42 +2976,15 @@ intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo) intel_sdvo_select_ddc_bus(i915, intel_sdvo); - if (flags & SDVO_OUTPUT_TMDS0) - if (!intel_sdvo_dvi_init(intel_sdvo, SDVO_OUTPUT_TMDS0)) - return false; + for (i = 0; i < ARRAY_SIZE(probe_order); i++) { + u16 type = flags & probe_order[i]; - if (flags & SDVO_OUTPUT_TMDS1) - if (!intel_sdvo_dvi_init(intel_sdvo, SDVO_OUTPUT_TMDS1)) - return false; + if (!type) + continue; - /* TV has no XXX1 function block */ - if (flags & SDVO_OUTPUT_SVID0) - if (!intel_sdvo_tv_init(intel_sdvo, SDVO_OUTPUT_SVID0)) - return false; - - if (flags & SDVO_OUTPUT_CVBS0) - if (!intel_sdvo_tv_init(intel_sdvo, SDVO_OUTPUT_CVBS0)) - return false; - - if (flags & SDVO_OUTPUT_YPRPB0) - if (!intel_sdvo_tv_init(intel_sdvo, SDVO_OUTPUT_YPRPB0)) - return false; - - if (flags & SDVO_OUTPUT_RGB0) - if (!intel_sdvo_analog_init(intel_sdvo, SDVO_OUTPUT_RGB0)) - return false; - - if (flags & SDVO_OUTPUT_RGB1) - if (!intel_sdvo_analog_init(intel_sdvo, SDVO_OUTPUT_RGB1)) - return false; - - if (flags & SDVO_OUTPUT_LVDS0) - if (!intel_sdvo_lvds_init(intel_sdvo, SDVO_OUTPUT_LVDS0)) - return false; - - if (flags & SDVO_OUTPUT_LVDS1) - if (!intel_sdvo_lvds_init(intel_sdvo, SDVO_OUTPUT_LVDS1)) + if (!intel_sdvo_output_init(intel_sdvo, type)) return false; + } intel_sdvo->base.pipe_mask = ~0; -- cgit From a6ebd538364b1e9e6048faaafbc0188172ed50c3 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 26 Oct 2022 13:11:34 +0300 Subject: drm/i915/sdvo: Fix debug print MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Correctly indicate which outputs we support in the debug print. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221026101134.20865-9-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_sdvo.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c index 1e06c6fb2c62..48b7b1aa37b2 100644 --- a/drivers/gpu/drm/i915/display/intel_sdvo.c +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c @@ -3412,9 +3412,12 @@ bool intel_sdvo_init(struct drm_i915_private *dev_priv, (intel_sdvo->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N', /* check currently supported outputs */ intel_sdvo->caps.output_flags & - (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_RGB0) ? 'Y' : 'N', + (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_RGB0 | + SDVO_OUTPUT_LVDS0 | SDVO_OUTPUT_SVID0 | + SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_YPRPB0) ? 'Y' : 'N', intel_sdvo->caps.output_flags & - (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N'); + (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1 | + SDVO_OUTPUT_LVDS1) ? 'Y' : 'N'); return true; err_output: -- cgit From 2a865248399a13bb2b2bcc50297069a7521de258 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Wed, 26 Oct 2022 14:52:46 +0200 Subject: drm: bridge: adv7511: use dev_err_probe in probe function adv7511 probe may need to be attempted multiple times before no -EPROBE_DEFER is returned. Currently, every such probe results in an error message: [ 4.534229] adv7511 1-003d: failed to find dsi host [ 4.580288] adv7511 1-003d: failed to find dsi host This is misleading, as there is no error and probe deferral is normal behavior. Fix this by using dev_err_probe that will suppress -EPROBE_DEFER errors. While at it, we touch all dev_err in the probe path. This makes the code more concise and included the error code everywhere to aid user in debugging. Reviewed-by: Laurent Pinchart Signed-off-by: Ahmad Fatoum Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20221026125246.3188260-1-a.fatoum@pengutronix.de --- drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 6 ++---- drivers/gpu/drm/bridge/adv7511/adv7533.c | 20 ++++++++------------ 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index 78b72739e5c3..e7a6e456ed0d 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -1219,10 +1219,8 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id) return ret; ret = adv7511_init_regulators(adv7511); - if (ret) { - dev_err(dev, "failed to init regulators\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "failed to init regulators\n"); /* * The power down GPIO is optional. If present, toggle it from active to diff --git a/drivers/gpu/drm/bridge/adv7511/adv7533.c b/drivers/gpu/drm/bridge/adv7511/adv7533.c index 258c79d4dab0..fdfeadcefe80 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7533.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7533.c @@ -149,16 +149,14 @@ int adv7533_attach_dsi(struct adv7511 *adv) }; host = of_find_mipi_dsi_host_by_node(adv->host_node); - if (!host) { - dev_err(dev, "failed to find dsi host\n"); - return -EPROBE_DEFER; - } + if (!host) + return dev_err_probe(dev, -EPROBE_DEFER, + "failed to find dsi host\n"); dsi = devm_mipi_dsi_device_register_full(dev, host, &info); - if (IS_ERR(dsi)) { - dev_err(dev, "failed to create dsi device\n"); - return PTR_ERR(dsi); - } + if (IS_ERR(dsi)) + return dev_err_probe(dev, PTR_ERR(dsi), + "failed to create dsi device\n"); adv->dsi = dsi; @@ -168,10 +166,8 @@ int adv7533_attach_dsi(struct adv7511 *adv) MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_VIDEO_HSE; ret = devm_mipi_dsi_attach(dev, dsi); - if (ret < 0) { - dev_err(dev, "failed to attach dsi to host\n"); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "failed to attach dsi to host\n"); return 0; } -- cgit From 876e9047a91839ee5be0ba099036d19883e52ca2 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Fri, 28 Oct 2022 15:40:22 -0700 Subject: drm/i915/mtl: Add missing steering table terminators The termination entries were missing for a couple of the recently-added MTL steering tables. Fixes: f32898c94a10 ("drm/i915/xelpg: Add multicast steering") Fixes: a7ec65fc7e83 ("drm/i915/xelpmp: Add multicast steering for media GT") Signed-off-by: Matt Roper Reviewed-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20221028224022.964997-1-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/gt/intel_gt_mcr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_mcr.c b/drivers/gpu/drm/i915/gt/intel_gt_mcr.c index 46cf2f3d1e8e..830edffe88cc 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_mcr.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_mcr.c @@ -128,11 +128,13 @@ static const struct intel_mmio_range xelpg_dss_steering_table[] = { { 0x00D800, 0x00D87F }, /* SLICE */ { 0x00DC00, 0x00DCFF }, /* SLICE */ { 0x00DE80, 0x00E8FF }, /* DSS (0xE000-0xE0FF reserved) */ + {}, }; static const struct intel_mmio_range xelpmp_oaddrm_steering_table[] = { { 0x393200, 0x39323F }, { 0x393400, 0x3934FF }, + {}, }; void intel_gt_mcr_init(struct intel_gt *gt) -- cgit From 4016379301a33e8bd0c2ef5c02f5d7f6a4afece4 Mon Sep 17 00:00:00 2001 From: Johan Jonker Date: Wed, 19 Oct 2022 23:35:03 +0200 Subject: drm: rockchip: remove rockchip_drm_framebuffer_init() function The function rockchip_drm_framebuffer_init() was in use in the rockchip_drm_fbdev.c file, but that is now replaced by a generic fbdev setup. Reduce the image size by removing the rockchip_drm_framebuffer_init() and sub function rockchip_fb_alloc() and cleanup the rockchip_drm_fb.h header file. Signed-off-by: Johan Jonker Reviewed-by: John Keeping Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/ebe91504-c5df-99e4-635f-832218584051@gmail.com --- drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 43 ------------------------------ drivers/gpu/drm/rockchip/rockchip_drm_fb.h | 6 ----- 2 files changed, 49 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c index 092bf863110b..409eaa1bf092 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c @@ -25,35 +25,6 @@ static const struct drm_framebuffer_funcs rockchip_drm_fb_funcs = { .dirty = drm_atomic_helper_dirtyfb, }; -static struct drm_framebuffer * -rockchip_fb_alloc(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cmd, - struct drm_gem_object **obj, unsigned int num_planes) -{ - struct drm_framebuffer *fb; - int ret; - int i; - - fb = kzalloc(sizeof(*fb), GFP_KERNEL); - if (!fb) - return ERR_PTR(-ENOMEM); - - drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd); - - for (i = 0; i < num_planes; i++) - fb->obj[i] = obj[i]; - - ret = drm_framebuffer_init(dev, fb, &rockchip_drm_fb_funcs); - if (ret) { - DRM_DEV_ERROR(dev->dev, - "Failed to initialize framebuffer: %d\n", - ret); - kfree(fb); - return ERR_PTR(ret); - } - - return fb; -} - static const struct drm_mode_config_helper_funcs rockchip_mode_config_helpers = { .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, }; @@ -106,20 +77,6 @@ static const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = { .atomic_commit = drm_atomic_helper_commit, }; -struct drm_framebuffer * -rockchip_drm_framebuffer_init(struct drm_device *dev, - const struct drm_mode_fb_cmd2 *mode_cmd, - struct drm_gem_object *obj) -{ - struct drm_framebuffer *fb; - - fb = rockchip_fb_alloc(dev, mode_cmd, &obj, 1); - if (IS_ERR(fb)) - return ERR_CAST(fb); - - return fb; -} - void rockchip_drm_mode_config_init(struct drm_device *dev) { dev->mode_config.min_width = 0; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.h b/drivers/gpu/drm/rockchip/rockchip_drm_fb.h index 1a696521096d..bae4e079dfb1 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.h @@ -7,11 +7,5 @@ #ifndef _ROCKCHIP_DRM_FB_H #define _ROCKCHIP_DRM_FB_H -struct drm_framebuffer * -rockchip_drm_framebuffer_init(struct drm_device *dev, - const struct drm_mode_fb_cmd2 *mode_cmd, - struct drm_gem_object *obj); -void rockchip_drm_framebuffer_fini(struct drm_framebuffer *fb); - void rockchip_drm_mode_config_init(struct drm_device *dev); #endif /* _ROCKCHIP_DRM_FB_H */ -- cgit From de4a4c8f64021b02aaa8ab21a82fe1f11a17b975 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 26 Sep 2022 10:16:43 +0200 Subject: drm/rockchip: vop2: Register Esmart0-win0 as primary plane Esmart0-win0 could serve as primary plane, so mark it as such. On RK3568 this window will never be used as primary plane, because the three windows at the beginning of the rk3568_vop_win_data[] array will be used. On RK3566 however, two of the windows at the beginning of the rk3568_vop_win_data[] array cannot not be used due to hardware limitations, so without this patch we end up with CRTCs without primary planes when multiple VPs are active. Signed-off-by: Sascha Hauer Tested-by: Chris Morgan Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20220926081643.304759-1-s.hauer@pengutronix.de --- drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c index 9bf0637bf8e2..9d30aa73b542 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -188,7 +188,7 @@ static const struct vop2_win_data rk3568_vop_win_data[] = { .base = 0x1800, .layer_sel_id = 2, .supported_rotations = DRM_MODE_REFLECT_Y, - .type = DRM_PLANE_TYPE_OVERLAY, + .type = DRM_PLANE_TYPE_PRIMARY, .max_upscale_factor = 8, .max_downscale_factor = 8, .dly = { 20, 47, 41 }, -- cgit From 3daf391fee830f2343cc6b1ba131b1b5115dea1f Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Mon, 17 Oct 2022 16:43:30 +0800 Subject: drm/rockchip: dsi: Remove the unused function dsi_update_bits() The function dsi_update_bits() is defined in the dw-mipi-dsi-rockchip.c file, but not called elsewhere, so delete this unused function. drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c:367:20: warning: unused function 'dsi_update_bits'. https://bugzilla.openanolis.cn/show_bug.cgi?id=2414 Reported-by: Abaci Robot Signed-off-by: Jiapeng Chong Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20221017084330.94117-1-jiapeng.chong@linux.alibaba.com --- drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c index bf6948125b84..313231d886d2 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c @@ -364,12 +364,6 @@ static inline u32 dsi_read(struct dw_mipi_dsi_rockchip *dsi, u32 reg) return readl(dsi->base + reg); } -static inline void dsi_update_bits(struct dw_mipi_dsi_rockchip *dsi, u32 reg, - u32 mask, u32 val) -{ - dsi_write(dsi, reg, (dsi_read(dsi, reg) & ~mask) | val); -} - static void dw_mipi_dsi_phy_write(struct dw_mipi_dsi_rockchip *dsi, u8 test_code, u8 test_data) -- cgit From e3558747ebe15306e6d0b75bd6d211436be4a7d5 Mon Sep 17 00:00:00 2001 From: Yuan Can Date: Wed, 15 Jun 2022 06:26:44 +0000 Subject: drm/rockchip: use pm_runtime_resume_and_get() instead of pm_runtime_get_sync() Replace pm_runtime_get_sync() with pm_runtime_resume_and_get() to avoid device usage counter leak. Signed-off-by: Yuan Can Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20220615062644.96837-1-yuancan@huawei.com --- drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c | 2 +- drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 4 ++-- drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c index 313231d886d2..92b599b089f9 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c @@ -1207,7 +1207,7 @@ static int dw_mipi_dsi_dphy_power_on(struct phy *phy) return i; } - ret = pm_runtime_get_sync(dsi->dev); + ret = pm_runtime_resume_and_get(dsi->dev); if (ret < 0) { DRM_DEV_ERROR(dsi->dev, "failed to enable device: %d\n", ret); return ret; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index c356de5dd220..fa1f4ee6d195 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -602,7 +602,7 @@ static int vop_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) struct vop *vop = to_vop(crtc); int ret, i; - ret = pm_runtime_get_sync(vop->dev); + ret = pm_runtime_resume_and_get(vop->dev); if (ret < 0) { DRM_DEV_ERROR(vop->dev, "failed to get pm runtime: %d\n", ret); return ret; @@ -1983,7 +1983,7 @@ static int vop_initial(struct vop *vop) return PTR_ERR(vop->dclk); } - ret = pm_runtime_get_sync(vop->dev); + ret = pm_runtime_resume_and_get(vop->dev); if (ret < 0) { DRM_DEV_ERROR(vop->dev, "failed to get pm runtime: %d\n", ret); return ret; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index aac20be5ac08..ad87db2fcaf6 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -822,7 +822,7 @@ static void vop2_enable(struct vop2 *vop2) { int ret; - ret = pm_runtime_get_sync(vop2->dev); + ret = pm_runtime_resume_and_get(vop2->dev); if (ret < 0) { drm_err(vop2->drm, "failed to get pm runtime: %d\n", ret); return; -- cgit From 4dba27f1a14592ac4cf71c3bc1cc1fd05dea8015 Mon Sep 17 00:00:00 2001 From: Zhang Qilong Date: Thu, 22 Sep 2022 21:21:07 +0800 Subject: drm/rockchip: lvds: fix PM usage counter unbalance in poweron pm_runtime_get_sync will increment pm usage counter even it failed. Forgetting to putting operation will result in reference leak here. We fix it by replacing it with the newest pm_runtime_resume_and_get to keep usage counter balanced. Fixes: 34cc0aa25456 ("drm/rockchip: Add support for Rockchip Soc LVDS") Fixes: cca1705c3d89 ("drm/rockchip: lvds: Add PX30 support") Signed-off-by: Zhang Qilong Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20220922132107.105419-3-zhangqilong3@huawei.com --- drivers/gpu/drm/rockchip/rockchip_lvds.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c index 5a284332ec49..68f6ebb33460 100644 --- a/drivers/gpu/drm/rockchip/rockchip_lvds.c +++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c @@ -152,7 +152,7 @@ static int rk3288_lvds_poweron(struct rockchip_lvds *lvds) DRM_DEV_ERROR(lvds->dev, "failed to enable lvds pclk %d\n", ret); return ret; } - ret = pm_runtime_get_sync(lvds->dev); + ret = pm_runtime_resume_and_get(lvds->dev); if (ret < 0) { DRM_DEV_ERROR(lvds->dev, "failed to get pm runtime: %d\n", ret); clk_disable(lvds->pclk); @@ -336,16 +336,20 @@ static int px30_lvds_poweron(struct rockchip_lvds *lvds) { int ret; - ret = pm_runtime_get_sync(lvds->dev); + ret = pm_runtime_resume_and_get(lvds->dev); if (ret < 0) { DRM_DEV_ERROR(lvds->dev, "failed to get pm runtime: %d\n", ret); return ret; } /* Enable LVDS mode */ - return regmap_update_bits(lvds->grf, PX30_LVDS_GRF_PD_VO_CON1, + ret = regmap_update_bits(lvds->grf, PX30_LVDS_GRF_PD_VO_CON1, PX30_LVDS_MODE_EN(1) | PX30_LVDS_P2S_EN(1), PX30_LVDS_MODE_EN(1) | PX30_LVDS_P2S_EN(1)); + if (ret) + pm_runtime_put(lvds->dev); + + return ret; } static void px30_lvds_poweroff(struct rockchip_lvds *lvds) -- cgit From e66c8dcf997ed54b62f754351e7129e1cc4e3cf9 Mon Sep 17 00:00:00 2001 From: Anshuman Gupta Date: Thu, 27 Oct 2022 14:52:41 +0530 Subject: drm/i915: Encapsulate lmem rpm stuff in intel_runtime_pm Runtime pm is not really per GT, therefore it make sense to move lmem_userfault_list, lmem_userfault_lock and userfault_wakeref from intel_gt to intel_runtime_pm structure, which is embedded to i915. No functional change. v2: - Fixes the code comment nit. [Matt Auld] Signed-off-by: Anshuman Gupta Reviewed-by: Matthew Auld Acked-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20221027092242.1476080-2-anshuman.gupta@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_mman.c | 6 +++--- drivers/gpu/drm/i915/gem/i915_gem_pm.c | 2 +- drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 8 ++++---- drivers/gpu/drm/i915/gt/intel_gt.c | 3 --- drivers/gpu/drm/i915/gt/intel_gt_types.h | 17 ----------------- drivers/gpu/drm/i915/i915_gem.c | 4 +--- drivers/gpu/drm/i915/intel_runtime_pm.c | 5 +++++ drivers/gpu/drm/i915/intel_runtime_pm.h | 22 ++++++++++++++++++++++ 8 files changed, 36 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_mman.c b/drivers/gpu/drm/i915/gem/i915_gem_mman.c index 73d9eda1d6b7..fd29a9053582 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_mman.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_mman.c @@ -413,7 +413,7 @@ retry: vma->mmo = mmo; if (CONFIG_DRM_I915_USERFAULT_AUTOSUSPEND) - intel_wakeref_auto(&to_gt(i915)->userfault_wakeref, + intel_wakeref_auto(&i915->runtime_pm.userfault_wakeref, msecs_to_jiffies_timeout(CONFIG_DRM_I915_USERFAULT_AUTOSUSPEND)); if (write) { @@ -589,9 +589,9 @@ void i915_gem_object_release_mmap_offset(struct drm_i915_gem_object *obj) spin_unlock(&obj->mmo.lock); if (obj->userfault_count) { - mutex_lock(&to_gt(to_i915(obj->base.dev))->lmem_userfault_lock); + mutex_lock(&to_i915(obj->base.dev)->runtime_pm.lmem_userfault_lock); list_del(&obj->userfault_link); - mutex_unlock(&to_gt(to_i915(obj->base.dev))->lmem_userfault_lock); + mutex_unlock(&to_i915(obj->base.dev)->runtime_pm.lmem_userfault_lock); obj->userfault_count = 0; } } diff --git a/drivers/gpu/drm/i915/gem/i915_gem_pm.c b/drivers/gpu/drm/i915/gem/i915_gem_pm.c index e5bfb6be9f7a..0d812f4d787d 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_pm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_pm.c @@ -27,7 +27,7 @@ void i915_gem_suspend(struct drm_i915_private *i915) GEM_TRACE("%s\n", dev_name(i915->drm.dev)); - intel_wakeref_auto(&to_gt(i915)->userfault_wakeref, 0); + intel_wakeref_auto(&i915->runtime_pm.userfault_wakeref, 0); flush_workqueue(i915->wq); /* diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c index e4ecfd3e8ee3..e10e20b38645 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c @@ -1101,13 +1101,13 @@ static vm_fault_t vm_fault_ttm(struct vm_fault *vmf) /* ttm_bo_vm_reserve() already has dma_resv_lock */ if (ret == VM_FAULT_NOPAGE && wakeref && !obj->userfault_count) { obj->userfault_count = 1; - mutex_lock(&to_gt(to_i915(obj->base.dev))->lmem_userfault_lock); - list_add(&obj->userfault_link, &to_gt(to_i915(obj->base.dev))->lmem_userfault_list); - mutex_unlock(&to_gt(to_i915(obj->base.dev))->lmem_userfault_lock); + mutex_lock(&to_i915(obj->base.dev)->runtime_pm.lmem_userfault_lock); + list_add(&obj->userfault_link, &to_i915(obj->base.dev)->runtime_pm.lmem_userfault_list); + mutex_unlock(&to_i915(obj->base.dev)->runtime_pm.lmem_userfault_lock); } if (wakeref & CONFIG_DRM_I915_USERFAULT_AUTOSUSPEND) - intel_wakeref_auto(&to_gt(to_i915(obj->base.dev))->userfault_wakeref, + intel_wakeref_auto(&to_i915(obj->base.dev)->runtime_pm.userfault_wakeref, msecs_to_jiffies_timeout(CONFIG_DRM_I915_USERFAULT_AUTOSUSPEND)); i915_ttm_adjust_lru(obj); diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c b/drivers/gpu/drm/i915/gt/intel_gt.c index 2e796ffad911..8e914c4066ed 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt.c +++ b/drivers/gpu/drm/i915/gt/intel_gt.c @@ -40,8 +40,6 @@ void intel_gt_common_init_early(struct intel_gt *gt) { spin_lock_init(gt->irq_lock); - INIT_LIST_HEAD(>->lmem_userfault_list); - mutex_init(>->lmem_userfault_lock); INIT_LIST_HEAD(>->closed_vma); spin_lock_init(>->closed_lock); @@ -859,7 +857,6 @@ static int intel_gt_tile_setup(struct intel_gt *gt, phys_addr_t phys_addr) } intel_uncore_init_early(gt->uncore, gt); - intel_wakeref_auto_init(>->userfault_wakeref, gt->uncore->rpm); ret = intel_uncore_setup_mmio(gt->uncore, phys_addr); if (ret) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_types.h b/drivers/gpu/drm/i915/gt/intel_gt_types.h index 6f686a4244f0..a0cc73b401ef 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_types.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_types.h @@ -145,20 +145,6 @@ struct intel_gt { struct intel_wakeref wakeref; atomic_t user_wakeref; - /** - * Protects access to lmem usefault list. - * It is required, if we are outside of the runtime suspend path, - * access to @lmem_userfault_list requires always first grabbing the - * runtime pm, to ensure we can't race against runtime suspend. - * Once we have that we also need to grab @lmem_userfault_lock, - * at which point we have exclusive access. - * The runtime suspend path is special since it doesn't really hold any locks, - * but instead has exclusive access by virtue of all other accesses requiring - * holding the runtime pm wakeref. - */ - struct mutex lmem_userfault_lock; - struct list_head lmem_userfault_list; - struct list_head closed_vma; spinlock_t closed_lock; /* guards the list of closed_vma */ @@ -174,9 +160,6 @@ struct intel_gt { */ intel_wakeref_t awake; - /* Manual runtime pm autosuspend delay for user GGTT/lmem mmaps */ - struct intel_wakeref_auto userfault_wakeref; - u32 clock_frequency; u32 clock_period_ns; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 55d605c0c55d..299f94a9fb87 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -843,7 +843,7 @@ void i915_gem_runtime_suspend(struct drm_i915_private *i915) __i915_gem_object_release_mmap_gtt(obj); list_for_each_entry_safe(obj, on, - &to_gt(i915)->lmem_userfault_list, userfault_link) + &i915->runtime_pm.lmem_userfault_list, userfault_link) i915_gem_object_runtime_pm_release_mmap_offset(obj); /* @@ -1227,8 +1227,6 @@ void i915_gem_driver_remove(struct drm_i915_private *dev_priv) struct intel_gt *gt; unsigned int i; - intel_wakeref_auto_fini(&to_gt(dev_priv)->userfault_wakeref); - i915_gem_suspend_late(dev_priv); for_each_gt(gt, dev_priv, i) intel_gt_driver_remove(gt); diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 6ed5786bcd29..6e7f5b38eb32 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -626,6 +626,8 @@ void intel_runtime_pm_driver_release(struct intel_runtime_pm *rpm) runtime_pm); int count = atomic_read(&rpm->wakeref_count); + intel_wakeref_auto_fini(&rpm->userfault_wakeref); + drm_WARN(&i915->drm, count, "i915 raw-wakerefs=%d wakelocks=%d on cleanup\n", intel_rpm_raw_wakeref_count(count), @@ -645,4 +647,7 @@ void intel_runtime_pm_init_early(struct intel_runtime_pm *rpm) rpm->available = HAS_RUNTIME_PM(i915); init_intel_runtime_pm_wakeref(rpm); + INIT_LIST_HEAD(&rpm->lmem_userfault_list); + mutex_init(&rpm->lmem_userfault_lock); + intel_wakeref_auto_init(&rpm->userfault_wakeref, rpm); } diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.h b/drivers/gpu/drm/i915/intel_runtime_pm.h index d9160e3ff4af..9f50f109aa11 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.h +++ b/drivers/gpu/drm/i915/intel_runtime_pm.h @@ -53,6 +53,28 @@ struct intel_runtime_pm { bool irqs_enabled; bool no_wakeref_tracking; + /* + * Protects access to lmem usefault list. + * It is required, if we are outside of the runtime suspend path, + * access to @lmem_userfault_list requires always first grabbing the + * runtime pm, to ensure we can't race against runtime suspend. + * Once we have that we also need to grab @lmem_userfault_lock, + * at which point we have exclusive access. + * The runtime suspend path is special since it doesn't really hold any locks, + * but instead has exclusive access by virtue of all other accesses requiring + * holding the runtime pm wakeref. + */ + struct mutex lmem_userfault_lock; + + /* + * Keep list of userfaulted gem obj, which require to release their + * mmap mappings at runtime suspend path. + */ + struct list_head lmem_userfault_list; + + /* Manual runtime pm autosuspend delay for user GGTT/lmem mmaps */ + struct intel_wakeref_auto userfault_wakeref; + #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM) /* * To aide detection of wakeref leaks and general misuse, we -- cgit From 1cacd6894d5f4084f1581435e92d8a18d6721b25 Mon Sep 17 00:00:00 2001 From: Anshuman Gupta Date: Thu, 27 Oct 2022 14:52:42 +0530 Subject: drm/i915/dgfx: Grab wakeref at i915_ttm_unmap_virtual We had already grabbed the rpm wakeref at obj destruction path, but it also required to grab the wakeref when object moves. When i915_gem_object_release_mmap_offset() gets called by i915_ttm_move_notify(), it will release the mmap offset without grabbing the wakeref. We want to avoid that therefore, grab the wakeref at i915_ttm_unmap_virtual() accordingly. While doing that also changed the lmem_userfault_lock from mutex to spinlock, as spinlock widely used for list. Also changed if (obj->userfault_count) to GEM_BUG_ON(!obj->userfault_count). v2: - Removed lmem_userfault_{list,lock} from intel_gt. [Matt Auld] Fixes: ad74457a6b5a ("drm/i915/dgfx: Release mmap on rpm suspend") Suggested-by: Matthew Auld Signed-off-by: Anshuman Gupta Reviewed-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20221027092242.1476080-3-anshuman.gupta@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_mman.c | 19 ++++++---------- drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 38 ++++++++++++++++++++++---------- drivers/gpu/drm/i915/intel_runtime_pm.c | 2 +- drivers/gpu/drm/i915/intel_runtime_pm.h | 2 +- 4 files changed, 35 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_mman.c b/drivers/gpu/drm/i915/gem/i915_gem_mman.c index fd29a9053582..e63329bc8065 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_mman.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_mman.c @@ -557,11 +557,13 @@ void i915_gem_object_runtime_pm_release_mmap_offset(struct drm_i915_gem_object * drm_vma_node_unmap(&bo->base.vma_node, bdev->dev_mapping); - if (obj->userfault_count) { - /* rpm wakeref provide exclusive access */ - list_del(&obj->userfault_link); - obj->userfault_count = 0; - } + /* + * We have exclusive access here via runtime suspend. All other callers + * must first grab the rpm wakeref. + */ + GEM_BUG_ON(!obj->userfault_count); + list_del(&obj->userfault_link); + obj->userfault_count = 0; } void i915_gem_object_release_mmap_offset(struct drm_i915_gem_object *obj) @@ -587,13 +589,6 @@ void i915_gem_object_release_mmap_offset(struct drm_i915_gem_object *obj) spin_lock(&obj->mmo.lock); } spin_unlock(&obj->mmo.lock); - - if (obj->userfault_count) { - mutex_lock(&to_i915(obj->base.dev)->runtime_pm.lmem_userfault_lock); - list_del(&obj->userfault_link); - mutex_unlock(&to_i915(obj->base.dev)->runtime_pm.lmem_userfault_lock); - obj->userfault_count = 0; - } } static struct i915_mmap_offset * diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c index e10e20b38645..9219a60a7f88 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c @@ -509,18 +509,9 @@ static int i915_ttm_shrink(struct drm_i915_gem_object *obj, unsigned int flags) static void i915_ttm_delete_mem_notify(struct ttm_buffer_object *bo) { struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo); - intel_wakeref_t wakeref = 0; if (bo->resource && !i915_ttm_is_ghost_object(bo)) { - /* ttm_bo_release() already has dma_resv_lock */ - if (i915_ttm_cpu_maps_iomem(bo->resource)) - wakeref = intel_runtime_pm_get(&to_i915(obj->base.dev)->runtime_pm); - __i915_gem_object_pages_fini(obj); - - if (wakeref) - intel_runtime_pm_put(&to_i915(obj->base.dev)->runtime_pm, wakeref); - i915_ttm_free_cached_io_rsgt(obj); } } @@ -1098,12 +1089,15 @@ static vm_fault_t vm_fault_ttm(struct vm_fault *vmf) if (ret == VM_FAULT_RETRY && !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT)) goto out_rpm; - /* ttm_bo_vm_reserve() already has dma_resv_lock */ + /* + * ttm_bo_vm_reserve() already has dma_resv_lock. + * userfault_count is protected by dma_resv lock and rpm wakeref. + */ if (ret == VM_FAULT_NOPAGE && wakeref && !obj->userfault_count) { obj->userfault_count = 1; - mutex_lock(&to_i915(obj->base.dev)->runtime_pm.lmem_userfault_lock); + spin_lock(&to_i915(obj->base.dev)->runtime_pm.lmem_userfault_lock); list_add(&obj->userfault_link, &to_i915(obj->base.dev)->runtime_pm.lmem_userfault_list); - mutex_unlock(&to_i915(obj->base.dev)->runtime_pm.lmem_userfault_lock); + spin_unlock(&to_i915(obj->base.dev)->runtime_pm.lmem_userfault_lock); } if (wakeref & CONFIG_DRM_I915_USERFAULT_AUTOSUSPEND) @@ -1169,7 +1163,27 @@ static u64 i915_ttm_mmap_offset(struct drm_i915_gem_object *obj) static void i915_ttm_unmap_virtual(struct drm_i915_gem_object *obj) { + struct ttm_buffer_object *bo = i915_gem_to_ttm(obj); + intel_wakeref_t wakeref = 0; + + assert_object_held_shared(obj); + + if (i915_ttm_cpu_maps_iomem(bo->resource)) { + wakeref = intel_runtime_pm_get(&to_i915(obj->base.dev)->runtime_pm); + + /* userfault_count is protected by obj lock and rpm wakeref. */ + if (obj->userfault_count) { + spin_lock(&to_i915(obj->base.dev)->runtime_pm.lmem_userfault_lock); + list_del(&obj->userfault_link); + spin_unlock(&to_i915(obj->base.dev)->runtime_pm.lmem_userfault_lock); + obj->userfault_count = 0; + } + } + ttm_bo_unmap_virtual(i915_gem_to_ttm(obj)); + + if (wakeref) + intel_runtime_pm_put(&to_i915(obj->base.dev)->runtime_pm, wakeref); } static const struct drm_i915_gem_object_ops i915_gem_ttm_obj_ops = { diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 6e7f5b38eb32..8b668ee35bd9 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -648,6 +648,6 @@ void intel_runtime_pm_init_early(struct intel_runtime_pm *rpm) init_intel_runtime_pm_wakeref(rpm); INIT_LIST_HEAD(&rpm->lmem_userfault_list); - mutex_init(&rpm->lmem_userfault_lock); + spin_lock_init(&rpm->lmem_userfault_lock); intel_wakeref_auto_init(&rpm->userfault_wakeref, rpm); } diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.h b/drivers/gpu/drm/i915/intel_runtime_pm.h index 9f50f109aa11..98b8b28baaa1 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.h +++ b/drivers/gpu/drm/i915/intel_runtime_pm.h @@ -64,7 +64,7 @@ struct intel_runtime_pm { * but instead has exclusive access by virtue of all other accesses requiring * holding the runtime pm wakeref. */ - struct mutex lmem_userfault_lock; + spinlock_t lmem_userfault_lock; /* * Keep list of userfaulted gem obj, which require to release their -- cgit From 28d52f99bbca7227008cf580c9194c9b3516968e Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Fri, 28 Oct 2022 16:50:26 +0100 Subject: drm/i915/dmabuf: fix sg_table handling in map_dma_buf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need to iterate over the original entries here for the sg_table, pulling out the struct page for each one, to be remapped. However currently this incorrectly iterates over the final dma mapped entries, which is likely just one gigantic sg entry if the iommu is enabled, leading to us only mapping the first struct page (and any physically contiguous pages following it), even if there is potentially lots more data to follow. Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/7306 Fixes: 1286ff739773 ("i915: add dmabuf/prime buffer sharing support.") Signed-off-by: Matthew Auld Cc: Lionel Landwerlin Cc: Tvrtko Ursulin Cc: Ville Syrjälä Cc: Michael J. Ruhl Cc: # v3.5+ Reviewed-by: Michael J. Ruhl Link: https://patchwork.freedesktop.org/patch/msgid/20221028155029.494736-1-matthew.auld@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c index f5062d0c6333..824971a1ceec 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c @@ -40,13 +40,13 @@ static struct sg_table *i915_gem_map_dma_buf(struct dma_buf_attachment *attachme goto err; } - ret = sg_alloc_table(st, obj->mm.pages->nents, GFP_KERNEL); + ret = sg_alloc_table(st, obj->mm.pages->orig_nents, GFP_KERNEL); if (ret) goto err_free; src = obj->mm.pages->sgl; dst = st->sgl; - for (i = 0; i < obj->mm.pages->nents; i++) { + for (i = 0; i < obj->mm.pages->orig_nents; i++) { sg_set_page(dst, sg_page(src), src->length, 0); dst = sg_next(dst); src = sg_next(src); -- cgit From 6427ab570c30cdfbbf00d2ae334d2ec47ce80c73 Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Fri, 28 Oct 2022 16:50:27 +0100 Subject: drm/i915/selftests: exercise GPU access from the importer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using PAGE_SIZE here potentially hides issues so bump that to something larger. This should also make it possible for iommu to coalesce entries for us. With that in place verify we can write from the GPU using the importers sg_table, followed by checking that our writes match when read from the CPU side. v2: Switch over to igt_gpu_fill_dw(), which looks to be more widely supported than the migrate stuff (at least OOTB). References: https://gitlab.freedesktop.org/drm/intel/-/issues/7306 Signed-off-by: Matthew Auld Cc: Lionel Landwerlin Cc: Tvrtko Ursulin Cc: Ville Syrjälä Cc: Michael J. Ruhl Reviewed-by: Michael J. Ruhl Link: https://patchwork.freedesktop.org/patch/msgid/20221028155029.494736-2-matthew.auld@intel.com --- .../gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c | 79 +++++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c index 51ed824b020c..aaa3d6174bf6 100644 --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c @@ -6,8 +6,12 @@ #include "i915_drv.h" #include "i915_selftest.h" +#include "gem/i915_gem_context.h" +#include "mock_context.h" #include "mock_dmabuf.h" +#include "igt_gem_utils.h" +#include "selftests/mock_drm.h" #include "selftests/mock_gem_device.h" static int igt_dmabuf_export(void *arg) @@ -140,6 +144,75 @@ out_ret: return err; } +static int verify_access(struct drm_i915_private *i915, + struct drm_i915_gem_object *native_obj, + struct drm_i915_gem_object *import_obj) +{ + struct i915_gem_engines_iter it; + struct i915_gem_context *ctx; + struct intel_context *ce; + struct i915_vma *vma; + struct file *file; + u32 *vaddr; + int err = 0, i; + + file = mock_file(i915); + if (IS_ERR(file)) + return PTR_ERR(file); + + ctx = live_context(i915, file); + if (IS_ERR(ctx)) { + err = PTR_ERR(ctx); + goto out_file; + } + + for_each_gem_engine(ce, i915_gem_context_lock_engines(ctx), it) { + if (intel_engine_can_store_dword(ce->engine)) + break; + } + i915_gem_context_unlock_engines(ctx); + if (!ce) + goto out_file; + + vma = i915_vma_instance(import_obj, ce->vm, NULL); + if (IS_ERR(vma)) { + err = PTR_ERR(vma); + goto out_file; + } + + err = i915_vma_pin(vma, 0, 0, PIN_USER); + if (err) + goto out_file; + + err = igt_gpu_fill_dw(ce, vma, 0, + vma->size >> PAGE_SHIFT, 0xdeadbeaf); + i915_vma_unpin(vma); + if (err) + goto out_file; + + err = i915_gem_object_wait(import_obj, 0, MAX_SCHEDULE_TIMEOUT); + if (err) + goto out_file; + + vaddr = i915_gem_object_pin_map_unlocked(native_obj, I915_MAP_WB); + if (IS_ERR(vaddr)) { + err = PTR_ERR(vaddr); + goto out_file; + } + + for (i = 0; i < native_obj->base.size / sizeof(u32); i += PAGE_SIZE / sizeof(u32)) { + if (vaddr[i] != 0xdeadbeaf) { + pr_err("Data mismatch [%d]=%u\n", i, vaddr[i]); + err = -EINVAL; + goto out_file; + } + } + +out_file: + fput(file); + return err; +} + static int igt_dmabuf_import_same_driver(struct drm_i915_private *i915, struct intel_memory_region **regions, unsigned int num_regions) @@ -154,7 +227,7 @@ static int igt_dmabuf_import_same_driver(struct drm_i915_private *i915, force_different_devices = true; - obj = __i915_gem_object_create_user(i915, PAGE_SIZE, + obj = __i915_gem_object_create_user(i915, SZ_8M, regions, num_regions); if (IS_ERR(obj)) { pr_err("__i915_gem_object_create_user failed with err=%ld\n", @@ -206,6 +279,10 @@ static int igt_dmabuf_import_same_driver(struct drm_i915_private *i915, i915_gem_object_unlock(import_obj); + err = verify_access(i915, obj, import_obj); + if (err) + goto out_import; + /* Now try a fake an importer */ import_attach = dma_buf_attach(dmabuf, obj->base.dev->dev); if (IS_ERR(import_attach)) { -- cgit From 81aa3f8e26e0fd8bffcaaaaf7e7a79ccc0a46111 Mon Sep 17 00:00:00 2001 From: "Michael J. Ruhl" Date: Fri, 28 Oct 2022 16:50:28 +0100 Subject: drm/i915/dmabuf: dmabuf cleanup Some minor cleanup of some variables for consistency. Normalize struct sg_table to sgt. Normalize struct dma_buf_attachment to attach. checkpatch issues sizeof(), !NULL updates. Cc: Tvrtko Ursulin Signed-off-by: Michael J. Ruhl Reviewed-by: Matthew Auld Signed-off-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20221028155029.494736-3-matthew.auld@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c | 47 ++++++++++++++++-------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c index 824971a1ceec..5359745d1185 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c @@ -25,43 +25,46 @@ static struct drm_i915_gem_object *dma_buf_to_obj(struct dma_buf *buf) return to_intel_bo(buf->priv); } -static struct sg_table *i915_gem_map_dma_buf(struct dma_buf_attachment *attachment, +static struct sg_table *i915_gem_map_dma_buf(struct dma_buf_attachment *attach, enum dma_data_direction dir) { - struct drm_i915_gem_object *obj = dma_buf_to_obj(attachment->dmabuf); - struct sg_table *st; + struct drm_i915_gem_object *obj = dma_buf_to_obj(attach->dmabuf); + struct sg_table *sgt; struct scatterlist *src, *dst; int ret, i; - /* Copy sg so that we make an independent mapping */ - st = kmalloc(sizeof(struct sg_table), GFP_KERNEL); - if (st == NULL) { + /* + * Make a copy of the object's sgt, so that we can make an independent + * mapping + */ + sgt = kmalloc(sizeof(*sgt), GFP_KERNEL); + if (!sgt) { ret = -ENOMEM; goto err; } - ret = sg_alloc_table(st, obj->mm.pages->orig_nents, GFP_KERNEL); + ret = sg_alloc_table(sgt, obj->mm.pages->orig_nents, GFP_KERNEL); if (ret) goto err_free; src = obj->mm.pages->sgl; - dst = st->sgl; + dst = sgt->sgl; for (i = 0; i < obj->mm.pages->orig_nents; i++) { sg_set_page(dst, sg_page(src), src->length, 0); dst = sg_next(dst); src = sg_next(src); } - ret = dma_map_sgtable(attachment->dev, st, dir, DMA_ATTR_SKIP_CPU_SYNC); + ret = dma_map_sgtable(attach->dev, sgt, dir, DMA_ATTR_SKIP_CPU_SYNC); if (ret) goto err_free_sg; - return st; + return sgt; err_free_sg: - sg_free_table(st); + sg_free_table(sgt); err_free: - kfree(st); + kfree(sgt); err: return ERR_PTR(ret); } @@ -236,15 +239,15 @@ struct dma_buf *i915_gem_prime_export(struct drm_gem_object *gem_obj, int flags) static int i915_gem_object_get_pages_dmabuf(struct drm_i915_gem_object *obj) { struct drm_i915_private *i915 = to_i915(obj->base.dev); - struct sg_table *pages; + struct sg_table *sgt; unsigned int sg_page_sizes; assert_object_held(obj); - pages = dma_buf_map_attachment(obj->base.import_attach, - DMA_BIDIRECTIONAL); - if (IS_ERR(pages)) - return PTR_ERR(pages); + sgt = dma_buf_map_attachment(obj->base.import_attach, + DMA_BIDIRECTIONAL); + if (IS_ERR(sgt)) + return PTR_ERR(sgt); /* * DG1 is special here since it still snoops transactions even with @@ -261,16 +264,16 @@ static int i915_gem_object_get_pages_dmabuf(struct drm_i915_gem_object *obj) (!HAS_LLC(i915) && !IS_DG1(i915))) wbinvd_on_all_cpus(); - sg_page_sizes = i915_sg_dma_sizes(pages->sgl); - __i915_gem_object_set_pages(obj, pages, sg_page_sizes); + sg_page_sizes = i915_sg_dma_sizes(sgt->sgl); + __i915_gem_object_set_pages(obj, sgt, sg_page_sizes); return 0; } static void i915_gem_object_put_pages_dmabuf(struct drm_i915_gem_object *obj, - struct sg_table *pages) + struct sg_table *sgt) { - dma_buf_unmap_attachment(obj->base.import_attach, pages, + dma_buf_unmap_attachment(obj->base.import_attach, sgt, DMA_BIDIRECTIONAL); } @@ -313,7 +316,7 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev, get_dma_buf(dma_buf); obj = i915_gem_object_alloc(); - if (obj == NULL) { + if (!obj) { ret = -ENOMEM; goto fail_detach; } -- cgit From 3096ae43cc815835cbaa846ae54e18cb92307730 Mon Sep 17 00:00:00 2001 From: "Michael J. Ruhl" Date: Fri, 28 Oct 2022 16:50:29 +0100 Subject: drm/i915/dmabuf: Use scatterlist for_each_sg API Update open coded for loop to use the standard scatterlist for_each_sg API. Cc: Tvrtko Ursulin Signed-off-by: Michael J. Ruhl Reviewed-by: Matthew Auld Signed-off-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20221028155029.494736-4-matthew.auld@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c index 5359745d1185..98b2d2950df6 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c @@ -47,12 +47,10 @@ static struct sg_table *i915_gem_map_dma_buf(struct dma_buf_attachment *attach, if (ret) goto err_free; - src = obj->mm.pages->sgl; dst = sgt->sgl; - for (i = 0; i < obj->mm.pages->orig_nents; i++) { + for_each_sg(obj->mm.pages->sgl, src, obj->mm.pages->orig_nents, i) { sg_set_page(dst, sg_page(src), src->length, 0); dst = sg_next(dst); - src = sg_next(src); } ret = dma_map_sgtable(attach->dev, sgt, dir, DMA_ATTR_SKIP_CPU_SYNC); -- cgit From 4cf949c7fafe21e085a4ee386bb2dade9067316e Mon Sep 17 00:00:00 2001 From: Zack Rusin Date: Tue, 25 Oct 2022 23:19:35 -0400 Subject: drm/vmwgfx: Validate the box size for the snooped cursor Invalid userspace dma surface copies could potentially overflow the memcpy from the surface to the snooped image leading to crashes. To fix it the dimensions of the copybox have to be validated against the expected size of the snooped cursor. Signed-off-by: Zack Rusin Fixes: 2ac863719e51 ("vmwgfx: Snoop DMA transfers with non-covering sizes") Cc: # v3.2+ Reviewed-by: Michael Banack Reviewed-by: Martin Krastev Link: https://patchwork.freedesktop.org/patch/msgid/20221026031936.1004280-1-zack@kde.org --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 0342efdf9063..d434b6ae1092 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -393,7 +393,8 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf, if (cmd->dma.guest.ptr.offset % PAGE_SIZE || box->x != 0 || box->y != 0 || box->z != 0 || box->srcx != 0 || box->srcy != 0 || box->srcz != 0 || - box->d != 1 || box_count != 1) { + box->d != 1 || box_count != 1 || + box->w > 64 || box->h > 64) { /* TODO handle none page aligned offsets */ /* TODO handle more dst & src != 0 */ /* TODO handle more then one copy */ -- cgit From da7ffb9660c96eec4167f177eb1cb6e78dd7fc0e Mon Sep 17 00:00:00 2001 From: Zack Rusin Date: Tue, 25 Oct 2022 23:19:36 -0400 Subject: drm/vmwgfx: Cleanup the cursor snooping code Cursor snooping depended on implicit size and format which made debugging quite difficult. Make the code easier to following by making everything explicit and instead of using magic numbers predefine all the parameters the code depends on. Also fixes incorrectly computed pitches for non-aligned cursor snoops. Fix which has no practical effect because non-aligned cursor snoops are not used by the X11 driver and Wayland cursors will go through mob cursors, instead of surface dma's. Signed-off-by: Zack Rusin Reviewed-by: Michael Banack Reviewed-by: Martin Krastev Link: https://patchwork.freedesktop.org/patch/msgid/20221026031936.1004280-2-zack@kde.org --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 4 ++++ drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 29 +++++++++++++++++------------ drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 14 +++++++++----- 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 4eb7339dd121..b062b020b378 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -98,6 +98,10 @@ #define VMW_RES_SHADER ttm_driver_type4 #define VMW_RES_HT_ORDER 12 +#define VMW_CURSOR_SNOOP_FORMAT SVGA3D_A8R8G8B8 +#define VMW_CURSOR_SNOOP_WIDTH 64 +#define VMW_CURSOR_SNOOP_HEIGHT 64 + #define MKSSTAT_CAPACITY_LOG2 5U #define MKSSTAT_CAPACITY (1U << MKSSTAT_CAPACITY_LOG2) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index d434b6ae1092..257f090071f1 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -25,6 +25,9 @@ * **************************************************************************/ +#include "vmwgfx_kms.h" +#include "vmw_surface_cache.h" + #include #include #include @@ -32,8 +35,6 @@ #include #include -#include "vmwgfx_kms.h" - void vmw_du_cleanup(struct vmw_display_unit *du) { struct vmw_private *dev_priv = vmw_priv(du->primary.dev); @@ -351,7 +352,6 @@ static void vmw_cursor_update_position(struct vmw_private *dev_priv, spin_unlock(&dev_priv->cursor_lock); } - void vmw_kms_cursor_snoop(struct vmw_surface *srf, struct ttm_object_file *tfile, struct ttm_buffer_object *bo, @@ -369,6 +369,9 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf, SVGA3dCmdSurfaceDMA dma; } *cmd; int i, ret; + const struct SVGA3dSurfaceDesc *desc = + vmw_surface_get_desc(VMW_CURSOR_SNOOP_FORMAT); + const u32 image_pitch = VMW_CURSOR_SNOOP_WIDTH * desc->pitchBytesPerBlock; cmd = container_of(header, struct vmw_dma_cmd, header); @@ -394,7 +397,7 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf, box->x != 0 || box->y != 0 || box->z != 0 || box->srcx != 0 || box->srcy != 0 || box->srcz != 0 || box->d != 1 || box_count != 1 || - box->w > 64 || box->h > 64) { + box->w > VMW_CURSOR_SNOOP_WIDTH || box->h > VMW_CURSOR_SNOOP_HEIGHT) { /* TODO handle none page aligned offsets */ /* TODO handle more dst & src != 0 */ /* TODO handle more then one copy */ @@ -408,7 +411,7 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf, } kmap_offset = cmd->dma.guest.ptr.offset >> PAGE_SHIFT; - kmap_num = (64*64*4) >> PAGE_SHIFT; + kmap_num = (VMW_CURSOR_SNOOP_HEIGHT*image_pitch) >> PAGE_SHIFT; ret = ttm_bo_reserve(bo, true, false, NULL); if (unlikely(ret != 0)) { @@ -422,14 +425,15 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf, virtual = ttm_kmap_obj_virtual(&map, &dummy); - if (box->w == 64 && cmd->dma.guest.pitch == 64*4) { - memcpy(srf->snooper.image, virtual, 64*64*4); + if (box->w == VMW_CURSOR_SNOOP_WIDTH && cmd->dma.guest.pitch == image_pitch) { + memcpy(srf->snooper.image, virtual, + VMW_CURSOR_SNOOP_HEIGHT*image_pitch); } else { /* Image is unsigned pointer. */ for (i = 0; i < box->h; i++) - memcpy(srf->snooper.image + i * 64, + memcpy(srf->snooper.image + i * image_pitch, virtual + i * cmd->dma.guest.pitch, - box->w * 4); + box->w * desc->pitchBytesPerBlock); } srf->snooper.age++; @@ -480,7 +484,8 @@ void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv) du->cursor_age = du->cursor_surface->snooper.age; vmw_send_define_cursor_cmd(dev_priv, du->cursor_surface->snooper.image, - 64, 64, + VMW_CURSOR_SNOOP_WIDTH, + VMW_CURSOR_SNOOP_HEIGHT, du->hotspot_x + du->core_hotspot_x, du->hotspot_y + du->core_hotspot_y); } @@ -1806,7 +1811,7 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, if (IS_ERR(vfb)) { ret = PTR_ERR(vfb); goto err_out; - } + } err_out: /* vmw_user_lookup_handle takes one ref so does new_fb */ @@ -2326,7 +2331,7 @@ retry: if (ret == -EDEADLK) { drm_modeset_backoff(&ctx); goto retry; - } + } goto out_fini; } } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index ace7ca150b03..3bc63ae768f3 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c @@ -815,11 +815,15 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, res->backup_size = cur_bo_offset; if (metadata->scanout && metadata->num_sizes == 1 && - metadata->sizes[0].width == 64 && - metadata->sizes[0].height == 64 && - metadata->format == SVGA3D_A8R8G8B8) { - - srf->snooper.image = kzalloc(64 * 64 * 4, GFP_KERNEL); + metadata->sizes[0].width == VMW_CURSOR_SNOOP_WIDTH && + metadata->sizes[0].height == VMW_CURSOR_SNOOP_HEIGHT && + metadata->format == VMW_CURSOR_SNOOP_FORMAT) { + const struct SVGA3dSurfaceDesc *desc = + vmw_surface_get_desc(VMW_CURSOR_SNOOP_FORMAT); + const u32 cursor_size_bytes = VMW_CURSOR_SNOOP_WIDTH * + VMW_CURSOR_SNOOP_HEIGHT * + desc->pitchBytesPerBlock; + srf->snooper.image = kzalloc(cursor_size_bytes, GFP_KERNEL); if (!srf->snooper.image) { DRM_ERROR("Failed to allocate cursor_image\n"); ret = -ENOMEM; -- cgit From d755f89220a2b49bc90b7b520bb6edeb4adb5f01 Mon Sep 17 00:00:00 2001 From: Jouni Högander Date: Mon, 24 Oct 2022 08:46:49 +0300 Subject: drm/i915/psr: Send update also on invalidate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we are observing mouse cursor stuttering when using xrandr --scaling=1.2x1.2. X scaling/transformation seems to be doing fronbuffer rendering. When moving mouse cursor X seems to perform several invalidates and only one DirtyFB. I.e. it seems to be assuming updates are sent to panel while drawing is done. Earlier we were disabling PSR in frontbuffer invalidate call back (when drawing in X started). PSR was re-enabled in frontbuffer flush callback (dirtyfb ioctl). This was working fine with X scaling/transformation. Now we are just enabling continuous full frame (cff) in PSR invalidate callback. Enabling cff doesn't trigger any updates. It just configures PSR to send full frame when updates are sent. I.e. there are no updates on screen before PSR flush callback is made. X seems to be doing several updates in frontbuffer before doing dirtyfb ioctl. Fix this by sending single update on every invalidate callback. Cc: José Roberto de Souza Cc: Ville Syrjälä Cc: Mika Kahola Fixes: 805f04d42a6b ("drm/i915/display/psr: Use continuos full frame to handle frontbuffer invalidations") Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/6679 Signed-off-by: Jouni Högander Reported-by: Brian J. Tarricone Tested-by: Brian J. Tarricone Reviewed-by: Mika Kahola Reviewed-by: José Roberto de Souza Signed-off-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20221024054649.31299-1-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_psr.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 904a1049eff3..564d4fd94048 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -2209,8 +2209,11 @@ static void _psr_invalidate_handle(struct intel_dp *intel_dp) if (intel_dp->psr.psr2_sel_fetch_enabled) { u32 val; - if (intel_dp->psr.psr2_sel_fetch_cff_enabled) + if (intel_dp->psr.psr2_sel_fetch_cff_enabled) { + /* Send one update otherwise lag is observed in screen */ + intel_de_write(dev_priv, CURSURFLIVE(intel_dp->psr.pipe), 0); return; + } val = man_trk_ctl_enable_bit_get(dev_priv) | man_trk_ctl_partial_frame_bit_get(dev_priv) | -- cgit From 9d1b073d018bcb1701a00cc3d4b8c6998cc34a4e Mon Sep 17 00:00:00 2001 From: Candice Li Date: Fri, 22 Jul 2022 20:39:12 +0800 Subject: drm/amdgpu: Enable GFX RAS feature for gfx v11_0_3 v1: Support gfx ras feature enablement for gfx v11_0_3. v2: Update function name and error message. Signed-off-by: Candice Li Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c index 5eefba2948a5..443ce664b663 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c @@ -4673,6 +4673,26 @@ static int gfx_v11_0_early_init(void *handle) return 0; } +static int gfx_v11_0_ras_late_init(void *handle) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct ras_common_if *gfx_common_if; + int ret; + + gfx_common_if = kzalloc(sizeof(struct ras_common_if), GFP_KERNEL); + if (!gfx_common_if) + return -ENOMEM; + + gfx_common_if->block = AMDGPU_RAS_BLOCK__GFX; + + ret = amdgpu_ras_feature_enable(adev, gfx_common_if, true); + if (ret) + dev_err(adev->dev, "Failed to enable gfx11 ras feature\n"); + + kfree(gfx_common_if); + return ret; +} + static int gfx_v11_0_late_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; @@ -4686,6 +4706,12 @@ static int gfx_v11_0_late_init(void *handle) if (r) return r; + if (adev->ip_versions[GC_HWIP][0] == IP_VERSION(11, 0, 3)) { + r = gfx_v11_0_ras_late_init(handle); + if (r) + return r; + } + return 0; } -- cgit From 2103c42198d38d6c02f8b9720c2a19cf3b4adddd Mon Sep 17 00:00:00 2001 From: Gavin Wan Date: Wed, 26 Oct 2022 13:45:25 -0400 Subject: drm/amdgpu: Disable GPU reset on SRIOV before remove pci. The recent change brought a bug on SRIOV envrionment. It caused unloading amdgpu failed on Guest VM. The reason is that the VF FLR was requested while unloading amdgpu driver, but the VF FLR of SRIOV sequence is wrong while removing PCI device. For SRIOV, the guest driver should not trigger the whole XGMI hive to do the reset. Host driver control how the device been reset. Fixes: f5c7e7797060 ("drm/amdgpu: Adjust removal control flow for smu v13_0_2") Acked-by: Alex Deucher Reviewed-by: Shaoyun Liu Signed-off-by: Gavin Wan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 3c9fecdd6b2f..bf2d50c8c92a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -2201,7 +2201,8 @@ amdgpu_pci_remove(struct pci_dev *pdev) pm_runtime_forbid(dev->dev); } - if (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 2)) { + if (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 2) && + !amdgpu_sriov_vf(adev)) { bool need_to_reset_gpu = false; if (adev->gmc.xgmi.num_physical_nodes > 1) { -- cgit From 47a7470bb2ca2d2ccbd945082e5ebf0279a33fe5 Mon Sep 17 00:00:00 2001 From: Yifan Zha Date: Tue, 25 Oct 2022 16:55:05 +0800 Subject: drm/amdgpu: Skip access GRBM_CNTL under SRIOV on gfx_v11 [Why] GRBM_CNTL is a PF_only register on gfx_v11. RLCG interface will return "out of range" under SRIOV VF. [How] Skip access GRBM_CNTL under gfx_v11 SRIOV VF. Signed-off-by: Yifan Zha Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c index 443ce664b663..f68e13b6282c 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c @@ -1626,7 +1626,8 @@ static void gfx_v11_0_constants_init(struct amdgpu_device *adev) u32 tmp; int i; - WREG32_FIELD15_PREREG(GC, 0, GRBM_CNTL, READ_TIMEOUT, 0xff); + if (!amdgpu_sriov_vf(adev)) + WREG32_FIELD15_PREREG(GC, 0, GRBM_CNTL, READ_TIMEOUT, 0xff); gfx_v11_0_setup_rb(adev); gfx_v11_0_get_cu_info(adev, &adev->gfx.cu_info); -- cgit From e1a29b28e70457549149d3b2c82e4333d68ac49d Mon Sep 17 00:00:00 2001 From: Yifan Zha Date: Tue, 25 Oct 2022 14:46:11 +0800 Subject: drm/amdgpu: Skip access SDMA0_F32_CNTL in sdma_v6_0_enable under SRIOV [Why] SDMA0_F32_CNTL is a PF_only regitser which will be blocked by L1. RLCG will not program the register as well. [How] Skip to program SDMA0_F32_CNTL under SRIOV VF. Signed-off-by: Yifan Zha Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c index d9ae69be5ea4..049c26a45d85 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c @@ -455,6 +455,9 @@ static void sdma_v6_0_enable(struct amdgpu_device *adev, bool enable) sdma_v6_0_rlc_stop(adev); } + if (amdgpu_sriov_vf(adev)) + return; + for (i = 0; i < adev->sdma.num_instances; i++) { f32_cntl = RREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_F32_CNTL)); f32_cntl = REG_SET_FIELD(f32_cntl, SDMA0_F32_CNTL, HALT, enable ? 0 : 1); -- cgit From 2c763f37d0a08d39c1a0b1318fa82896c31a6c9d Mon Sep 17 00:00:00 2001 From: Yifan Zha Date: Tue, 25 Oct 2022 15:47:19 +0800 Subject: drm/amdgpu: Skip program gfxhub_v3_0_3 system aperture registers under SRIOV [Why] gfxhub_v3_0_3 system aperture registers are removed from RLCG register access range. [How] Skip access gfxhub_v3_0_3 system aperture registers under SRIOV VF. These registers will be programmed on host side. Signed-off-by: Yifan Zha Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0_3.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0_3.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0_3.c index 5d3fffd4929f..716ae6f2aefe 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0_3.c +++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0_3.c @@ -154,6 +154,9 @@ static void gfxhub_v3_0_3_init_system_aperture_regs(struct amdgpu_device *adev) { uint64_t value; + if (amdgpu_sriov_vf(adev)) + return; + /* Disable AGP. */ WREG32_SOC15(GC, 0, regGCMC_VM_AGP_BASE, 0); WREG32_SOC15(GC, 0, regGCMC_VM_AGP_TOP, 0); -- cgit From ee22f63b1085fd5cf1649e8915b1e2617cd33ca0 Mon Sep 17 00:00:00 2001 From: Ma Jun Date: Wed, 26 Oct 2022 17:29:18 +0800 Subject: drm/amdkfd: Remove unused variable kfd_topology_device->cache_count is not used by other fucntions, so remove it. Signed-off-by: Ma Jun Reviewed-by: Felix Kuehling Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_crat.c | 1 - drivers/gpu/drm/amd/amdkfd/kfd_topology.h | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c index 339f60a4cddd..568cbf1d8259 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c @@ -1131,7 +1131,6 @@ static int kfd_parse_subtype_cache(struct crat_subtype_cache *cache, if (cache->flags & CRAT_CACHE_FLAGS_SIMD_CACHE) props->cache_type |= HSA_CACHE_TYPE_HSACU; - dev->cache_count++; dev->node_props.caches_count++; list_add_tail(&props->list, &dev->cache_props); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.h b/drivers/gpu/drm/amd/amdkfd/kfd_topology.h index 9f6c949186c1..90c069fbd581 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.h @@ -128,7 +128,6 @@ struct kfd_topology_device { uint32_t proximity_domain; struct kfd_node_properties node_props; struct list_head mem_props; - uint32_t cache_count; struct list_head cache_props; struct list_head io_link_props; struct list_head p2p_link_props; -- cgit From 26f2fe8608374e3dda39d01a6acd42d1f67b8ee1 Mon Sep 17 00:00:00 2001 From: Hamza Mahfooz Date: Mon, 31 Oct 2022 10:47:36 -0400 Subject: drm/amd/display: drop vblank_lock from struct amdgpu_display_manager As of commit 09a5df6c444c ("drm/amd/display: Fix multi-display support for idle opt workqueue"), vblank_lock is no longer being used. So, don't init it in amdgpu_dm_init() and remove it from struct amdgpu_display_manager. Reviewed-by: Harry Wentland Signed-off-by: Hamza Mahfooz Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 1 - drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 7 ------- 2 files changed, 8 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 94620f9b166c..3130da83e17b 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1399,7 +1399,6 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) mutex_init(&adev->dm.dc_lock); mutex_init(&adev->dm.audio_lock); - spin_lock_init(&adev->dm.vblank_lock); if(amdgpu_dm_irq_init(adev)) { DRM_ERROR("amdgpu: failed to initialize DM IRQ support.\n"); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index b5ce15c43bcc..b618b2586e7b 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -365,13 +365,6 @@ struct amdgpu_display_manager { */ struct mutex audio_lock; - /** - * @vblank_lock: - * - * Guards access to deferred vblank work state. - */ - spinlock_t vblank_lock; - /** * @audio_component: * -- cgit From 7fbf451e7639f4ce41e2e3e802e5c521c1827b48 Mon Sep 17 00:00:00 2001 From: Dillon Varone Date: Mon, 17 Oct 2022 18:51:15 -0400 Subject: drm/amd/display: Reinit DPG when exiting dynamic ODM [WHY] DPG must be returned to initialized state when pipe is disabled. [HOW] Reinit DPG on unused pipes when exiting dynamic ODM. Reviewed-by: Alvin Lee Acked-by: Alex Hung Signed-off-by: Dillon Varone Tested-by: Mark Broadworth Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c index feff834d5410..b465a83bde6f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c @@ -1079,6 +1079,29 @@ void dcn20_blank_pixel_data( 0); } + if (!blank && dc->debug.enable_single_display_2to1_odm_policy) { + /* when exiting dynamic ODM need to reinit DPG state for unused pipes */ + struct pipe_ctx *old_odm_pipe = dc->current_state->res_ctx.pipe_ctx[pipe_ctx->pipe_idx].next_odm_pipe; + + odm_pipe = pipe_ctx->next_odm_pipe; + + while (old_odm_pipe) { + if (!odm_pipe || old_odm_pipe->pipe_idx != odm_pipe->pipe_idx) + dc->hwss.set_disp_pattern_generator(dc, + old_odm_pipe, + CONTROLLER_DP_TEST_PATTERN_VIDEOMODE, + CONTROLLER_DP_COLOR_SPACE_UDEFINED, + COLOR_DEPTH_888, + NULL, + 0, + 0, + 0); + old_odm_pipe = old_odm_pipe->next_odm_pipe; + if (odm_pipe) + odm_pipe = odm_pipe->next_odm_pipe; + } + } + if (!blank) if (stream_res->abm) { dc->hwss.set_pipe(pipe_ctx); -- cgit From 368307cef69ccd9bf5511f25e58e3a103be169fb Mon Sep 17 00:00:00 2001 From: Eric Bernstein Date: Tue, 11 Oct 2022 14:28:47 -0400 Subject: drm/amd/display: Include virtual signal to set k1 and k2 values Reviewed-by: Charlene Liu Acked-by: Alex Hung Signed-off-by: Eric Bernstein Tested-by: Mark Broadworth Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c index cf5bd9713f54..aeb4822cebc8 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c @@ -1186,7 +1186,7 @@ unsigned int dcn32_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsign *k2_div = PIXEL_RATE_DIV_BY_2; else *k2_div = PIXEL_RATE_DIV_BY_4; - } else if (dc_is_dp_signal(pipe_ctx->stream->signal)) { + } else if (dc_is_dp_signal(pipe_ctx->stream->signal) || dc_is_virtual_signal(pipe_ctx->stream->signal)) { if (two_pix_per_container) { *k1_div = PIXEL_RATE_DIV_BY_1; *k2_div = PIXEL_RATE_DIV_BY_2; -- cgit From 667be3ef1bb93a599fd425acb914dfbbf433dda0 Mon Sep 17 00:00:00 2001 From: Alvin Lee Date: Thu, 20 Oct 2022 16:07:07 -0400 Subject: drm/amd/display: Don't enable ODM + MPO [Description] Driver doesn't support ODM + MPO Reviewed-by: Dillon Varone Acked-by: Alex Hung Signed-off-by: Alvin Lee Tested-by: Mark Broadworth Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c index aeb4822cebc8..5e0018efe055 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c @@ -989,10 +989,6 @@ void dcn32_init_hw(struct dc *dc) dc_dmub_srv_query_caps_cmd(dc->ctx->dmub_srv->dmub); dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr; } - - /* Enable support for ODM and windowed MPO if policy flag is set */ - if (dc->debug.enable_single_display_2to1_odm_policy) - dc->config.enable_windowed_mpo_odm = true; } static int calc_mpc_flow_ctrl_cnt(const struct dc_stream_state *stream, -- cgit From 6139ab41f26848c92fd20fd678e1b7e5fb17959c Mon Sep 17 00:00:00 2001 From: Charlene Liu Date: Thu, 20 Oct 2022 16:21:13 -0400 Subject: drm/amd/display: Update DML formula [why] This is to update SW DML implementation. Reviewed-by: Dmytro Laktyushkin Reviewed-by: Ariel Bernstein Acked-by: Alex Hung Signed-off-by: Charlene Liu Tested-by: Mark Broadworth Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c | 3 ++- drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c index b612edb14417..45ab0ce50860 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c @@ -1052,7 +1052,8 @@ static bool CalculatePrefetchSchedule( else bytes_pp = myPipe->BytePerPixelY + myPipe->BytePerPixelC; /*rev 99*/ - prefetch_bw_pr = dml_min(1, bytes_pp * myPipe->PixelClock / (double) myPipe->DPPPerPlane); + prefetch_bw_pr = bytes_pp * myPipe->PixelClock / (double) myPipe->DPPPerPlane; + prefetch_bw_pr = dml_min(1, myPipe->VRatio) * prefetch_bw_pr; max_Tsw = dml_max(PrefetchSourceLinesY, PrefetchSourceLinesC) * LineTime; prefetch_sw_bytes = PrefetchSourceLinesY * swath_width_luma_ub * myPipe->BytePerPixelY + PrefetchSourceLinesC * swath_width_chroma_ub * myPipe->BytePerPixelC; prefetch_bw_oto = dml_max(bytes_pp * myPipe->PixelClock / myPipe->DPPPerPlane, prefetch_sw_bytes / (dml_max(PrefetchSourceLinesY, PrefetchSourceLinesC) * LineTime)); diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c b/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c index 0d12fd079cd6..53e3e7364ec6 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c @@ -1074,7 +1074,8 @@ static bool CalculatePrefetchSchedule( else bytes_pp = myPipe->BytePerPixelY + myPipe->BytePerPixelC; /*rev 99*/ - prefetch_bw_pr = dml_min(1, bytes_pp * myPipe->PixelClock / (double) myPipe->DPPPerPlane); + prefetch_bw_pr = bytes_pp * myPipe->PixelClock / (double) myPipe->DPPPerPlane; + prefetch_bw_pr = dml_min(1, myPipe->VRatio) * prefetch_bw_pr; max_Tsw = dml_max(PrefetchSourceLinesY, PrefetchSourceLinesC) * LineTime; prefetch_sw_bytes = PrefetchSourceLinesY * swath_width_luma_ub * myPipe->BytePerPixelY + PrefetchSourceLinesC * swath_width_chroma_ub * myPipe->BytePerPixelC; prefetch_bw_oto = dml_max(bytes_pp * myPipe->PixelClock / myPipe->DPPPerPlane, prefetch_sw_bytes / (dml_max(PrefetchSourceLinesY, PrefetchSourceLinesC) * LineTime)); -- cgit From c40f8b132e6014e3034926cc492f113d9d5ca85b Mon Sep 17 00:00:00 2001 From: Dillon Varone Date: Wed, 19 Oct 2022 18:42:49 -0400 Subject: drm/amd/display: Check validation passed after applying pipe split changes [WHY?] Validation can fail for configurations that were previously supported, by only changing parameters such as the DET allocations, which is currently unexpected. [HOW?] Add a check that validation passes after applying pipe split related changes. Reviewed-by: Alvin Lee Acked-by: Alex Hung Signed-off-by: Dillon Varone Tested-by: Mark Broadworth Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c index b6cd10f3181c..9c03f62b9d19 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c @@ -1736,10 +1736,12 @@ bool dcn32_internal_validate_bw(struct dc *dc, * ensure all the params are calculated correctly. We do not need to run the * pipe split check again after this call (pipes are already split / merged). * */ - if (!fast_validate) { - context->bw_ctx.dml.soc.allow_for_pstate_or_stutter_in_vblank_final = - dm_prefetch_support_uclk_fclk_and_stutter_if_possible; - vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, pipe_cnt); + context->bw_ctx.dml.soc.allow_for_pstate_or_stutter_in_vblank_final = + dm_prefetch_support_uclk_fclk_and_stutter_if_possible; + vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, pipe_cnt); + if (vlevel == context->bw_ctx.dml.soc.num_states) { + /* failed after DET size changes */ + goto validate_fail; } } *vlevel_out = vlevel; -- cgit From 14e1f089d5ee0519af0c646efbc3196d3e1674ba Mon Sep 17 00:00:00 2001 From: Taimur Hassan Date: Fri, 21 Oct 2022 10:54:42 -0400 Subject: drm/amd/display: Remove rate check from pixel rate divider update [Why] This check is not needed, and can cause CRC mismatch. [How] Remove check and early exit from divider update. Reviewed-by: Nicholas Kazlauskas Acked-by: Alex Hung Signed-off-by: Taimur Hassan Tested-by: Mark Broadworth Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dccg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dccg.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dccg.c index 1bd7e0f327d8..367cb6e6d074 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dccg.c +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dccg.c @@ -97,7 +97,7 @@ static void dccg314_set_pixel_rate_div( enum pixel_rate_div cur_k1 = PIXEL_RATE_DIV_NA, cur_k2 = PIXEL_RATE_DIV_NA; dccg314_get_pixel_rate_div(dccg, otg_inst, &cur_k1, &cur_k2); - if (k1 == PIXEL_RATE_DIV_NA || k2 == PIXEL_RATE_DIV_NA || (k1 == cur_k1 && k2 == cur_k2)) + if (k1 == cur_k1 && k2 == cur_k2) return; switch (otg_inst) { -- cgit From 361edc61a05cdbc99c6b53264d42af1533e9c20c Mon Sep 17 00:00:00 2001 From: Iswara Nagulendran Date: Fri, 21 Oct 2022 12:27:12 -0400 Subject: drm/amd/display: Modify checks to enable TPS3 pattern when required [HOW&WHY] Checking if both DSC and FEC supported from sink and source before going with TPS3 pattern during link training. Reviewed-by: Anthony Koo Acked-by: Alex Hung Signed-off-by: Iswara Nagulendran Tested-by: Mark Broadworth Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c index bec5e9f787fc..cda1592c3a5b 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c @@ -399,7 +399,11 @@ static bool dmub_psr_copy_settings(struct dmub_psr *dmub, link->psr_settings.force_ffu_mode = 0; copy_settings_data->force_ffu_mode = link->psr_settings.force_ffu_mode; - if (link->fec_state == dc_link_fec_enabled && + if (((link->dpcd_caps.fec_cap.bits.FEC_CAPABLE && + !link->dc->debug.disable_fec) && + (link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_SUPPORT && + !link->panel_config.dsc.disable_dsc_edp && + link->dc->caps.edp_dsc_support)) && link->dpcd_caps.sink_dev_id == DP_DEVICE_ID_38EC11 && (!memcmp(link->dpcd_caps.sink_dev_id_str, DP_SINK_DEVICE_STR_ID_1, sizeof(DP_SINK_DEVICE_STR_ID_1)) || -- cgit From 935e35d8dbde76a02d00290cf4d9eb420514eaf3 Mon Sep 17 00:00:00 2001 From: Martin Leung Date: Fri, 21 Oct 2022 15:28:52 -0400 Subject: drm/amd/display: Stop waiting for vblank during pipe programming [why and how] This line was originally removed for a compliance issue, but then reverted as it caused a fringe underflow case. However, the addition of this line caused a underflow regression when subVP is on, and it needs to be removed again. We plan to fix subvp underflow and then re-add in this line. After that, we will investigate what to do next for the compliance issue. Reviewed-by: Alvin Lee Acked-by: Alex Hung Signed-off-by: Martin Leung Tested-by: Mark Broadworth Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c index b465a83bde6f..f3334f513eb4 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c @@ -1663,7 +1663,6 @@ static void dcn20_program_pipe( pipe_ctx->pipe_dlg_param.vupdate_width); if (pipe_ctx->stream->mall_stream_config.type != SUBVP_PHANTOM) { - pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VBLANK); pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE); } -- cgit From da339aa4573de3526890627490ee5f61c1de9c31 Mon Sep 17 00:00:00 2001 From: Leo Chen Date: Fri, 21 Oct 2022 18:24:02 -0400 Subject: drm/amd/display: Add a debug option HBR2CP2520 over TPS4 [Why & How] There are cases when we may need to override the hardcoded TPS4 test pattern. Added parameters and config option to be able to allow this. Reviewed-by: Charlene Liu Acked-by: Alex Hung Signed-off-by: Leo Chen Tested-by: Mark Broadworth Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc.h | 1 + drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c | 2 ++ drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c | 2 ++ drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c | 2 ++ drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c | 2 ++ drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c | 2 ++ 6 files changed, 11 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 2a6406440032..6be110b00b24 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -393,6 +393,7 @@ struct dc_config { bool disable_dmcu; bool enable_4to1MPC; bool enable_windowed_mpo_odm; + bool forceHBR2CP2520; // Used for switching between test patterns TPS4 and CP2520 uint32_t allow_edp_hotplug_detection; bool clamp_min_dcfclk; uint64_t vblank_alignment_dto_params; diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c index 8729d6305996..8f5e89cb9d3e 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c @@ -1902,6 +1902,8 @@ static bool dcn31_resource_construct( dc->caps.max_slave_rgb_planes = 2; dc->caps.post_blend_color_processing = true; dc->caps.force_dp_tps4_for_cp2520 = true; + if (dc->config.forceHBR2CP2520) + dc->caps.force_dp_tps4_for_cp2520 = false; dc->caps.dp_hpo = true; dc->caps.dp_hdmi21_pcon_support = true; dc->caps.edp_dsc_support = true; diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c index 85e2d87a8e44..3b3e093e9447 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c @@ -1770,6 +1770,8 @@ static bool dcn314_resource_construct( dc->caps.max_slave_rgb_planes = 2; dc->caps.post_blend_color_processing = true; dc->caps.force_dp_tps4_for_cp2520 = true; + if (dc->config.forceHBR2CP2520) + dc->caps.force_dp_tps4_for_cp2520 = false; dc->caps.dp_hpo = true; dc->caps.dp_hdmi21_pcon_support = true; dc->caps.edp_dsc_support = true; diff --git a/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c b/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c index 31cbc5762eab..96a3d41febff 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c @@ -1783,6 +1783,8 @@ static bool dcn315_resource_construct( dc->caps.max_slave_rgb_planes = 2; dc->caps.post_blend_color_processing = true; dc->caps.force_dp_tps4_for_cp2520 = true; + if (dc->config.forceHBR2CP2520) + dc->caps.force_dp_tps4_for_cp2520 = false; dc->caps.dp_hpo = true; dc->caps.dp_hdmi21_pcon_support = true; dc->caps.edp_dsc_support = true; diff --git a/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c b/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c index af3eddc0cf32..2f643cdaf59f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c @@ -1785,6 +1785,8 @@ static bool dcn316_resource_construct( dc->caps.max_slave_rgb_planes = 2; dc->caps.post_blend_color_processing = true; dc->caps.force_dp_tps4_for_cp2520 = true; + if (dc->config.forceHBR2CP2520) + dc->caps.force_dp_tps4_for_cp2520 = false; dc->caps.dp_hpo = true; dc->caps.dp_hdmi21_pcon_support = true; dc->caps.edp_dsc_support = true; diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c index 287b7fa9bf41..4ba9a8662185 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c @@ -2126,6 +2126,8 @@ static bool dcn32_resource_construct( dc->caps.max_slave_rgb_planes = 2; dc->caps.post_blend_color_processing = true; dc->caps.force_dp_tps4_for_cp2520 = true; + if (dc->config.forceHBR2CP2520) + dc->caps.force_dp_tps4_for_cp2520 = false; dc->caps.dp_hpo = true; dc->caps.dp_hdmi21_pcon_support = true; dc->caps.edp_dsc_support = true; -- cgit From cf472dbdd7204e1aaaf587df067e8e986616788b Mon Sep 17 00:00:00 2001 From: Anthony Koo Date: Sat, 22 Oct 2022 22:18:19 -0400 Subject: drm/amd/display: [FW Promotion] Release 0.0.141.0 - Add flag as a status read back that indicates back to back flips detected during psr. Reviewed-by: Aric Cyr Acked-by: Alex Hung Signed-off-by: Anthony Koo Tested-by: Mark Broadworth Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index bc9344af1995..9df330c86a55 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -225,6 +225,12 @@ union dmub_psr_debug_flags { * Use TPS3 signal when restore main link. */ uint32_t force_wakeup_by_tps3 : 1; + + /** + * Back to back flip, therefore cannot power down PHY + */ + uint32_t back_to_back_flip : 1; + } bitfields; /** -- cgit From 86975c34b6e2ce85b5b03f3b0a83333c97890ad7 Mon Sep 17 00:00:00 2001 From: George Shen Date: Fri, 7 Oct 2022 12:43:26 -0400 Subject: drm/amd/display: Fix DCN32 DSC delay calculation [Why] DCN32 DSC delay calculation had an unintentional integer division, resulting in a mismatch against the DML spreadsheet. [How] Cast numerator to double before performing the division. Reviewed-by: Alvin Lee Acked-by: Alex Hung Signed-off-by: George Shen Tested-by: Mark Broadworth Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c index ad66e241f9ae..4a3e7a5d2758 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c @@ -1746,7 +1746,7 @@ unsigned int dml32_DSCDelayRequirement(bool DSCEnabled, } DSCDelayRequirement_val = DSCDelayRequirement_val + (HTotal - HActive) * - dml_ceil(DSCDelayRequirement_val / HActive, 1); + dml_ceil((double)DSCDelayRequirement_val / HActive, 1); DSCDelayRequirement_val = DSCDelayRequirement_val * PixelClock / PixelClockBackEnd; -- cgit From e70a70d0c03f5594cd09a1a2732c7e136f9c8edd Mon Sep 17 00:00:00 2001 From: George Shen Date: Fri, 14 Oct 2022 17:36:32 -0400 Subject: drm/amd/display: Use forced DSC bpp in DML [Why] DSC config is calculated separately from DML calculations. DML should use these separately calculated DSC params. The issue is that the calculated bpp is not properly propagated into DML. [How] Correctly used forced_bpp value in DML. Reviewed-by: Alvin Lee Acked-by: Alex Hung Signed-off-by: George Shen Tested-by: Mark Broadworth Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c | 2 +- drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c index 5b91660a6496..60351b2891d0 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c @@ -1627,7 +1627,7 @@ static void mode_support_configuration(struct vba_vars_st *v, && !mode_lib->vba.MSOOrODMSplitWithNonDPLink && !mode_lib->vba.NotEnoughLanesForMSO && mode_lib->vba.LinkCapacitySupport[i] == true && !mode_lib->vba.P2IWith420 - && !mode_lib->vba.DSCOnlyIfNecessaryWithBPP + //&& !mode_lib->vba.DSCOnlyIfNecessaryWithBPP && !mode_lib->vba.DSC422NativeNotSupported && !mode_lib->vba.MPCCombineMethodIncompatible && mode_lib->vba.ODMCombine2To1SupportCheckOK[i] == true diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c index 03924aed8d5c..8e6585dab20e 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c @@ -625,7 +625,7 @@ static void fetch_pipe_params(struct display_mode_lib *mode_lib) mode_lib->vba.skip_dio_check[mode_lib->vba.NumberOfActivePlanes] = dout->is_virtual; - if (!dout->dsc_enable) + if (dout->dsc_enable) mode_lib->vba.ForcedOutputLinkBPP[mode_lib->vba.NumberOfActivePlanes] = dout->output_bpp; else mode_lib->vba.ForcedOutputLinkBPP[mode_lib->vba.NumberOfActivePlanes] = 0.0; -- cgit From fa7e2b031faf84a607c2b81c15328314b286bc6a Mon Sep 17 00:00:00 2001 From: George Shen Date: Fri, 14 Oct 2022 17:40:08 -0400 Subject: drm/amd/display: Round up DST_after_scaler to nearest int [Why] The DST_after_scaler value that DML spreadsheet outputs is generally the driver value round up to the nearest int. Reviewed-by: Alvin Lee Acked-by: Alex Hung Signed-off-by: George Shen Tested-by: Mark Broadworth Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dml/dcn32/display_rq_dlg_calc_32.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_rq_dlg_calc_32.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_rq_dlg_calc_32.c index a1276f6b9581..395ae8761980 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_rq_dlg_calc_32.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_rq_dlg_calc_32.c @@ -291,8 +291,8 @@ void dml32_rq_dlg_get_dlg_reg(struct display_mode_lib *mode_lib, dml_print("DML_DLG: %s: vready_after_vcount0 = %d\n", __func__, dlg_regs->vready_after_vcount0); - dst_x_after_scaler = get_dst_x_after_scaler(mode_lib, e2e_pipe_param, num_pipes, pipe_idx); - dst_y_after_scaler = get_dst_y_after_scaler(mode_lib, e2e_pipe_param, num_pipes, pipe_idx); + dst_x_after_scaler = dml_ceil(get_dst_x_after_scaler(mode_lib, e2e_pipe_param, num_pipes, pipe_idx), 1); + dst_y_after_scaler = dml_ceil(get_dst_y_after_scaler(mode_lib, e2e_pipe_param, num_pipes, pipe_idx), 1); // do some adjustment on the dst_after scaler to account for odm combine mode dml_print("DML_DLG: %s: input dst_x_after_scaler = %d\n", __func__, dst_x_after_scaler); -- cgit From f30508e918b4011f44f617f13f8251e72f1a5661 Mon Sep 17 00:00:00 2001 From: George Shen Date: Fri, 14 Oct 2022 17:46:03 -0400 Subject: drm/amd/display: Add DSC delay factor workaround [Why] Certain 4K high refresh rate modes requiring DSC are exhibiting top of screen underflow corruption. Increasing the DSC delay by a factor of 6 percent stops the underflow for most use cases. [How] Multiply DSC delay requirement in DML by a factor. Add debug option to make this DSC delay factor configurable. Reviewed-by: Alvin Lee Acked-by: Alex Hung Signed-off-by: George Shen Tested-by: Mark Broadworth Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc.h | 1 + drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c | 4 +++- drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c | 5 +++-- drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c | 5 +++-- drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.h | 3 ++- drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c | 5 ++++- drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h | 3 +++ 7 files changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 6be110b00b24..b2c1dcae4ca7 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -863,6 +863,7 @@ struct dc_debug_options { bool enable_double_buffered_dsc_pg_support; bool enable_dp_dig_pixel_rate_div_policy; enum lttpr_mode lttpr_mode_override; + unsigned int dsc_delay_factor_wa_x1000; }; struct gpu_info_soc_bounding_box_v1_0; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c index 9c03f62b9d19..0d704e302d03 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c @@ -2346,9 +2346,11 @@ void dcn32_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_pa if (dc->ctx->dc_bios->vram_info.dram_channel_width_bytes) dcn3_2_soc.dram_channel_width_bytes = dc->ctx->dc_bios->vram_info.dram_channel_width_bytes; - } + /* DML DSC delay factor workaround */ + dcn3_2_ip.dsc_delay_factor_wa = dc->debug.dsc_delay_factor_wa_x1000 / 1000.0; + /* Override dispclk_dppclk_vco_speed_mhz from Clk Mgr */ dcn3_2_soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0; dc->dml.soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c index 60351b2891d0..47ff0a8bd105 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c @@ -367,7 +367,7 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman mode_lib->vba.OutputBpp[k], mode_lib->vba.HActive[k], mode_lib->vba.HTotal[k], mode_lib->vba.NumberOfDSCSlices[k], mode_lib->vba.OutputFormat[k], mode_lib->vba.Output[k], mode_lib->vba.PixelClock[k], - mode_lib->vba.PixelClockBackEnd[k]); + mode_lib->vba.PixelClockBackEnd[k], mode_lib->vba.ip.dsc_delay_factor_wa); } for (k = 0; k < mode_lib->vba.NumberOfActiveSurfaces; ++k) @@ -2475,7 +2475,8 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l mode_lib->vba.OutputBppPerState[i][k], mode_lib->vba.HActive[k], mode_lib->vba.HTotal[k], mode_lib->vba.NumberOfDSCSlices[k], mode_lib->vba.OutputFormat[k], mode_lib->vba.Output[k], - mode_lib->vba.PixelClock[k], mode_lib->vba.PixelClockBackEnd[k]); + mode_lib->vba.PixelClock[k], mode_lib->vba.PixelClockBackEnd[k], + mode_lib->vba.ip.dsc_delay_factor_wa); } for (k = 0; k <= mode_lib->vba.NumberOfActiveSurfaces - 1; k++) { diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c index 4a3e7a5d2758..968924c491c1 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c @@ -1726,7 +1726,8 @@ unsigned int dml32_DSCDelayRequirement(bool DSCEnabled, enum output_format_class OutputFormat, enum output_encoder_class Output, double PixelClock, - double PixelClockBackEnd) + double PixelClockBackEnd, + double dsc_delay_factor_wa) { unsigned int DSCDelayRequirement_val; @@ -1764,7 +1765,7 @@ unsigned int dml32_DSCDelayRequirement(bool DSCEnabled, dml_print("DML::%s: DSCDelayRequirement_val = %d\n", __func__, DSCDelayRequirement_val); #endif - return DSCDelayRequirement_val; + return dml_ceil(DSCDelayRequirement_val * dsc_delay_factor_wa, 1); } void dml32_CalculateSurfaceSizeInMall( diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.h b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.h index 55cead0d4237..2c3827546ac7 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.h +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.h @@ -327,7 +327,8 @@ unsigned int dml32_DSCDelayRequirement(bool DSCEnabled, enum output_format_class OutputFormat, enum output_encoder_class Output, double PixelClock, - double PixelClockBackEnd); + double PixelClockBackEnd, + double dsc_delay_factor_wa); void dml32_CalculateSurfaceSizeInMall( unsigned int NumberOfActiveSurfaces, diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c index 7352f7514410..ec0486efab14 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c @@ -29,6 +29,7 @@ #include "dcn321_fpu.h" #include "dcn32/dcn32_resource.h" #include "dcn321/dcn321_resource.h" +#include "dml/dcn32/display_mode_vba_util_32.h" #define DCN3_2_DEFAULT_DET_SIZE 256 @@ -538,9 +539,11 @@ void dcn321_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_p if (dc->ctx->dc_bios->vram_info.dram_channel_width_bytes) dcn3_21_soc.dram_channel_width_bytes = dc->ctx->dc_bios->vram_info.dram_channel_width_bytes; - } + /* DML DSC delay factor workaround */ + dcn3_21_ip.dsc_delay_factor_wa = dc->debug.dsc_delay_factor_wa_x1000 / 1000.0; + /* Override dispclk_dppclk_vco_speed_mhz from Clk Mgr */ dcn3_21_soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0; dc->dml.soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0; diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h index f33a8879b05a..d7be01ac0751 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h @@ -364,6 +364,9 @@ struct _vcs_dpi_ip_params_st { unsigned int max_num_dp2p0_outputs; unsigned int max_num_dp2p0_streams; unsigned int VBlankNomDefaultUS; + + /* DM workarounds */ + double dsc_delay_factor_wa; // TODO: Remove after implementing root cause fix }; struct _vcs_dpi_display_xfc_params_st { -- cgit From 6818f755f737758211d196cf7015628a88622d85 Mon Sep 17 00:00:00 2001 From: Charlene Liu Date: Fri, 21 Oct 2022 15:39:09 -0400 Subject: drm/amd/display: Fix null pointer issues found in emulation [why] fix null point issues found in emulation Reviewed-by: Chris Park Acked-by: Alex Hung Signed-off-by: Charlene Liu Tested-by: Mark Broadworth Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c index bdf101547484..165c920ca776 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c @@ -89,7 +89,8 @@ static void enable_memory_low_power(struct dc *dc) REG_UPDATE(MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, 1); } - if (dc->debug.enable_mem_low_power.bits.mpc) + if (dc->debug.enable_mem_low_power.bits.mpc && + dc->res_pool->mpc->funcs->set_mpc_mem_lp_mode) dc->res_pool->mpc->funcs->set_mpc_mem_lp_mode(dc->res_pool->mpc); @@ -141,7 +142,8 @@ void dcn31_init_hw(struct dc *dc) if (!dcb->funcs->is_accelerated_mode(dcb)) { hws->funcs.bios_golden_init(dc); - hws->funcs.disable_vga(dc->hwseq); + if (hws->funcs.disable_vga) + hws->funcs.disable_vga(dc->hwseq); } // Initialize the dccg if (res_pool->dccg->funcs->dccg_init) -- cgit From 9ee8b902b891723237e3aace0c2ec640327f31d2 Mon Sep 17 00:00:00 2001 From: Nevenko Stupar Date: Fri, 6 May 2022 16:32:38 -0400 Subject: drm/amd/display: Investigate tool reported FCLK P-state deviations [Why] Fix for some of the tool reported modes for FCLK P-state deviations and UCLK P-state deviations that are coming from DSC terms and/or Scaling terms causing MinActiveFCLKChangeLatencySupported and MaxActiveDRAMClockChangeLatencySupported incorrectly calculated in DML for these configurations. Reviewed-by: Chaitanya Dhere Acked-by: Jasdeep Dhillon Acked-by: Alex Hung Signed-off-by: Nevenko Stupar Tested-by: Mark Broadworth Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c index 47ff0a8bd105..3d184679f129 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c @@ -364,7 +364,8 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman for (k = 0; k < mode_lib->vba.NumberOfActiveSurfaces; ++k) { v->DSCDelay[k] = dml32_DSCDelayRequirement(mode_lib->vba.DSCEnabled[k], mode_lib->vba.ODMCombineEnabled[k], mode_lib->vba.DSCInputBitPerComponent[k], - mode_lib->vba.OutputBpp[k], mode_lib->vba.HActive[k], mode_lib->vba.HTotal[k], + mode_lib->vba.OutputBppPerState[mode_lib->vba.VoltageLevel][k], + mode_lib->vba.HActive[k], mode_lib->vba.HTotal[k], mode_lib->vba.NumberOfDSCSlices[k], mode_lib->vba.OutputFormat[k], mode_lib->vba.Output[k], mode_lib->vba.PixelClock[k], mode_lib->vba.PixelClockBackEnd[k], mode_lib->vba.ip.dsc_delay_factor_wa); -- cgit From ba6029726854e43e77fec05af5299a671e8483a0 Mon Sep 17 00:00:00 2001 From: Aric Cyr Date: Sun, 23 Oct 2022 13:41:03 -0400 Subject: drm/amd/display: 3.2.210 DC version 3.2.210 brings along the following: - Investigate tool reported FCLK P-state deviations - Fix null pointer issues found in emulation - Add DSC delay factor workaround - Round up DST_after_scaler to nearest int - Use forced DSC bpp in DML - Fix DCN32 DSC delay calculation - Add a debug option HBR2CP2520 over TPS4 - Stop waiting for vblank during pipe programming - Modify checks to enable TPS3 pattern when required - Remove rate check from pixel rate divider update - Check validation passed after applying pipe split changes - Update DML formula - Don't enable ODM + MPO - Include virtual signal to set k1 and k2 values - Reinit DPG when exiting dynamic ODM Acked-by: Alex Hung Signed-off-by: Aric Cyr Tested-by: Mark Broadworth Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index b2c1dcae4ca7..84c82d3a6761 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -47,7 +47,7 @@ struct aux_payload; struct set_config_cmd_payload; struct dmub_notification; -#define DC_VER "3.2.209" +#define DC_VER "3.2.210" #define MAX_SURFACES 3 #define MAX_PLANES 6 -- cgit From 545094d993f4639482018becda5f2a47d126f0ab Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Mon, 31 Oct 2022 12:42:47 +0100 Subject: drm/amd/display (gcc13): fix enum mismatch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rn_vbios_smu_set_dcn_low_power_state() produces a valid warning with gcc-13: drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c:237:6: error: conflicting types for 'rn_vbios_smu_set_dcn_low_power_state' due to enum/integer mismatch; have 'void(struct clk_mgr_internal *, enum dcn_pwr_state)' drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.h:36:6: note: previous declaration of 'rn_vbios_smu_set_dcn_low_power_state' with type 'void(struct clk_mgr_internal *, int)' I.e. the type of the 2nd parameter of rn_vbios_smu_set_dcn_low_power_state() in the declaration is int, while the definition spells enum dcn_pwr_state. Synchronize them to the latter (and add a forward enum declaration). Cc: Martin Liska Cc: Harry Wentland Cc: Leo Li Cc: Rodrigo Siqueira Cc: Alex Deucher Cc: "Christian König" Cc: "Pan, Xinhui" Cc: David Airlie Cc: Daniel Vetter Cc: amd-gfx@lists.freedesktop.org Cc: dri-devel@lists.freedesktop.org Reviewed-by: Harry Wentland Signed-off-by: Jiri Slaby (SUSE) Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.h index 3e5df27aa96f..1ce19d875358 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.h +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.h @@ -26,6 +26,8 @@ #ifndef DAL_DC_RN_CLK_MGR_VBIOS_SMU_H_ #define DAL_DC_RN_CLK_MGR_VBIOS_SMU_H_ +enum dcn_pwr_state; + int rn_vbios_smu_get_smu_version(struct clk_mgr_internal *clk_mgr); int rn_vbios_smu_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_dispclk_khz); int rn_vbios_smu_set_dprefclk(struct clk_mgr_internal *clk_mgr); @@ -33,7 +35,7 @@ int rn_vbios_smu_set_hard_min_dcfclk(struct clk_mgr_internal *clk_mgr, int reque int rn_vbios_smu_set_min_deep_sleep_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_min_ds_dcfclk_khz); void rn_vbios_smu_set_phyclk(struct clk_mgr_internal *clk_mgr, int requested_phyclk_khz); int rn_vbios_smu_set_dppclk(struct clk_mgr_internal *clk_mgr, int requested_dpp_khz); -void rn_vbios_smu_set_dcn_low_power_state(struct clk_mgr_internal *clk_mgr, int display_count); +void rn_vbios_smu_set_dcn_low_power_state(struct clk_mgr_internal *clk_mgr, enum dcn_pwr_state); void rn_vbios_smu_enable_48mhz_tmdp_refclk_pwrdwn(struct clk_mgr_internal *clk_mgr, bool enable); void rn_vbios_smu_enable_pme_wa(struct clk_mgr_internal *clk_mgr); int rn_vbios_smu_is_periodic_retraining_disabled(struct clk_mgr_internal *clk_mgr); -- cgit From 2215cb3be5c28a1fd43036550c00c2371aeeba95 Mon Sep 17 00:00:00 2001 From: Marco Felsch Date: Tue, 1 Nov 2022 17:46:15 +0100 Subject: drm: lcdif: change burst size to 256B If a axi bus master with a higher priority do a lot of memory access FIFO underruns can be inspected. Increase the burst size to 256B to avoid such underruns and to improve the memory access efficiency. Fixes: 9db35bb349a0 ("drm: lcdif: Add support for i.MX8MP LCDIF variant") Signed-off-by: Marco Felsch Reviewed-by: Marek Vasut Signed-off-by: Marek Vasut Link: https://patchwork.freedesktop.org/patch/msgid/20221101164615.778299-1-m.felsch@pengutronix.de --- drivers/gpu/drm/mxsfb/lcdif_kms.c | 14 ++++++++++++-- drivers/gpu/drm/mxsfb/lcdif_regs.h | 4 ++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/mxsfb/lcdif_kms.c b/drivers/gpu/drm/mxsfb/lcdif_kms.c index 33ee40876994..f0ad6e2a9352 100644 --- a/drivers/gpu/drm/mxsfb/lcdif_kms.c +++ b/drivers/gpu/drm/mxsfb/lcdif_kms.c @@ -314,8 +314,18 @@ static void lcdif_set_mode(struct lcdif_drm_private *lcdif, u32 bus_flags) CTRLDESCL0_1_WIDTH(m->hdisplay), lcdif->base + LCDC_V8_CTRLDESCL0_1); - writel(CTRLDESCL0_3_PITCH(lcdif->crtc.primary->state->fb->pitches[0]), - lcdif->base + LCDC_V8_CTRLDESCL0_3); + /* + * Undocumented P_SIZE and T_SIZE register but those written in the + * downstream kernel those registers control the AXI burst size. As of + * now there are two known values: + * 1 - 128Byte + * 2 - 256Byte + * Downstream set it to 256B burst size to improve the memory + * efficiency so set it here too. + */ + ctrl = CTRLDESCL0_3_P_SIZE(2) | CTRLDESCL0_3_T_SIZE(2) | + CTRLDESCL0_3_PITCH(lcdif->crtc.primary->state->fb->pitches[0]); + writel(ctrl, lcdif->base + LCDC_V8_CTRLDESCL0_3); } static void lcdif_enable_controller(struct lcdif_drm_private *lcdif) diff --git a/drivers/gpu/drm/mxsfb/lcdif_regs.h b/drivers/gpu/drm/mxsfb/lcdif_regs.h index 2d3920b8371e..fb74eb5ccbf1 100644 --- a/drivers/gpu/drm/mxsfb/lcdif_regs.h +++ b/drivers/gpu/drm/mxsfb/lcdif_regs.h @@ -190,6 +190,10 @@ #define CTRLDESCL0_1_WIDTH(n) ((n) & 0xffff) #define CTRLDESCL0_1_WIDTH_MASK GENMASK(15, 0) +#define CTRLDESCL0_3_P_SIZE(n) (((n) << 20) & CTRLDESCL0_3_P_SIZE_MASK) +#define CTRLDESCL0_3_P_SIZE_MASK GENMASK(22, 20) +#define CTRLDESCL0_3_T_SIZE(n) (((n) << 16) & CTRLDESCL0_3_T_SIZE_MASK) +#define CTRLDESCL0_3_T_SIZE_MASK GENMASK(17, 16) #define CTRLDESCL0_3_PITCH(n) ((n) & 0xffff) #define CTRLDESCL0_3_PITCH_MASK GENMASK(15, 0) -- cgit From c1cdee9b685a174fca849e1451c201a846a69318 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 13 Oct 2022 00:11:59 +0200 Subject: drm/panel/panel-sitronix-st7701: Fix RTNI calculation The RTNI field is multiplied by 16 and incremented by 512 before being used as the minimum number of pixel clock per horizontal line, hence it is necessary to subtract those 512 bytes from htotal and then divide the result by 16 before writing the value into the RTNI field. Fix the calculation. Fixes: de2b4917843c ("drm/panel/panel-sitronix-st7701: Infer horizontal pixel count from TFT mode") Signed-off-by: Marek Vasut Reviewed-by: Linus Walleij Link: https://patchwork.freedesktop.org/patch/msgid/20221012221159.88397-1-marex@denx.de --- drivers/gpu/drm/panel/panel-sitronix-st7701.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7701.c b/drivers/gpu/drm/panel/panel-sitronix-st7701.c index c481daa4bbce..9578f461f5e4 100644 --- a/drivers/gpu/drm/panel/panel-sitronix-st7701.c +++ b/drivers/gpu/drm/panel/panel-sitronix-st7701.c @@ -244,7 +244,7 @@ static void st7701_init_sequence(struct st7701 *st7701) DSI_CMD2_BK0_INVSEL_ONES_MASK | FIELD_PREP(DSI_CMD2_BK0_INVSEL_NLINV_MASK, desc->nlinv), FIELD_PREP(DSI_CMD2_BK0_INVSEL_RTNI_MASK, - DIV_ROUND_UP(mode->htotal, 16))); + (clamp((u32)mode->htotal, 512U, 1008U) - 512) / 16)); /* Command2, BK1 */ ST7701_DSI(st7701, DSI_CMD2BKX_SEL, -- cgit From 57cadf5b77b5ff21ffba4b82bc1f24be62d361ad Mon Sep 17 00:00:00 2001 From: Jouni Högander Date: Tue, 1 Nov 2022 13:53:42 +0200 Subject: drm/i915/mtl: Fix PSR2_MAN_TRK_CTL bit getter functions for MTL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MTL shares PSR2_MAN_TRK_CTL bits with ADL. Currently some bit getter functions are incorrect for MTL. This patch fixes those. Bspec: 49274 Cc: José Roberto de Souza Cc: Mika Kahola Cc: Radhakrishna Sripada Fixes: 47d4ae2192cb ("drm/i915/mtl: Extend PSR support") Signed-off-by: Jouni Högander Reviewed-by: José Roberto de Souza Signed-off-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20221101115342.1136720-1-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_psr.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 564d4fd94048..e11b0592055f 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -1470,7 +1470,8 @@ unlock: static u32 man_trk_ctl_enable_bit_get(struct drm_i915_private *dev_priv) { - return IS_ALDERLAKE_P(dev_priv) ? 0 : PSR2_MAN_TRK_CTL_ENABLE; + return IS_ALDERLAKE_P(dev_priv) || DISPLAY_VER(dev_priv) >= 14 ? 0 : + PSR2_MAN_TRK_CTL_ENABLE; } static u32 man_trk_ctl_single_full_frame_bit_get(struct drm_i915_private *dev_priv) @@ -1482,14 +1483,14 @@ static u32 man_trk_ctl_single_full_frame_bit_get(struct drm_i915_private *dev_pr static u32 man_trk_ctl_partial_frame_bit_get(struct drm_i915_private *dev_priv) { - return IS_ALDERLAKE_P(dev_priv) ? + return IS_ALDERLAKE_P(dev_priv) || DISPLAY_VER(dev_priv) >= 14 ? ADLP_PSR2_MAN_TRK_CTL_SF_PARTIAL_FRAME_UPDATE : PSR2_MAN_TRK_CTL_SF_PARTIAL_FRAME_UPDATE; } static u32 man_trk_ctl_continuos_full_frame(struct drm_i915_private *dev_priv) { - return IS_ALDERLAKE_P(dev_priv) ? + return IS_ALDERLAKE_P(dev_priv) || DISPLAY_VER(dev_priv) >= 14 ? ADLP_PSR2_MAN_TRK_CTL_SF_CONTINUOS_FULL_FRAME : PSR2_MAN_TRK_CTL_SF_CONTINUOS_FULL_FRAME; } -- cgit From ea9c6215ac6ba8db51d0af6cce71b6aa959364c2 Mon Sep 17 00:00:00 2001 From: Wayne Boyer Date: Mon, 31 Oct 2022 06:15:09 -0700 Subject: drm/i915/dg2: Introduce Wa_18017747507 WA 18017747507 applies to all DG2 skus. BSpec: 56035, 46121, 68173 Signed-off-by: Wayne Boyer Reviewed-by: Matt Roper Signed-off-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20221031131509.3411195-1-wayne.boyer@intel.com --- drivers/gpu/drm/i915/gt/intel_gt_regs.h | 3 +++ drivers/gpu/drm/i915/gt/intel_workarounds.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_regs.h b/drivers/gpu/drm/i915/gt/intel_gt_regs.h index 1b901970cfa4..dfbf093ec562 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_regs.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_regs.h @@ -498,6 +498,9 @@ #define VF_PREEMPTION _MMIO(0x83a4) #define PREEMPTION_VERTEX_COUNT REG_GENMASK(15, 0) +#define VFG_PREEMPTION_CHICKEN _MMIO(0x83b4) +#define POLYGON_TRIFAN_LINELOOP_DISABLE REG_BIT(4) + #define GEN8_RC6_CTX_INFO _MMIO(0x8504) #define XEHP_SQCM MCR_REG(0x8724) diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c index f87d4bde761b..8c98567f7a78 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds.c +++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c @@ -2975,6 +2975,9 @@ general_render_compute_wa_init(struct intel_engine_cs *engine, struct i915_wa_li * Wa_22015475538:dg2 */ wa_mcr_write_or(wal, LSC_CHICKEN_BIT_0_UDW, DIS_CHAIN_2XSIMD8); + + /* Wa_18017747507:dg2 */ + wa_masked_en(wal, VFG_PREEMPTION_CHICKEN, POLYGON_TRIFAN_LINELOOP_DISABLE); } } -- cgit From 49ee766b364edf7aca412d7418eb4cfe7ab1b1db Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 15 Oct 2022 01:10:42 +0200 Subject: drm/panel/panel-sitronix-st7701: Clean up CMDnBKx selection There are two command register files, CMD1 and CMD2, where only the CMD2 contains additional register sub-files BK0..3 . Pull the register file selection call into separate function instead of duplicating it all over the driver. The CMD2BK2 file is undocumented in datasheet, and is used for BIST. No functional change. Signed-off-by: Marek Vasut Signed-off-by: Linus Walleij Link: https://patchwork.freedesktop.org/patch/msgid/20221014231042.468033-1-marex@denx.de --- drivers/gpu/drm/panel/panel-sitronix-st7701.c | 58 ++++++++++++--------------- 1 file changed, 25 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7701.c b/drivers/gpu/drm/panel/panel-sitronix-st7701.c index 9578f461f5e4..baeb952b6e24 100644 --- a/drivers/gpu/drm/panel/panel-sitronix-st7701.c +++ b/drivers/gpu/drm/panel/panel-sitronix-st7701.c @@ -19,6 +19,9 @@ /* Command2 BKx selection command */ #define DSI_CMD2BKX_SEL 0xFF +#define DSI_CMD1 0 +#define DSI_CMD2 BIT(4) +#define DSI_CMD2BK_MASK GENMASK(3, 0) /* Command2, BK0 commands */ #define DSI_CMD2_BK0_PVGAMCTRL 0xB0 /* Positive Voltage Gamma Control */ @@ -39,21 +42,6 @@ #define DSI_CMD2_BK1_SPD2 0xC2 /* Source EQ2 Setting */ #define DSI_CMD2_BK1_MIPISET1 0xD0 /* MIPI Setting 1 */ -/* - * Command2 with BK function selection. - * - * BIT[4].....CN2 - * BIT[1:0]...BKXSEL - * 1:00 = CMD2BK0, Command2 BK0 - * 1:01 = CMD2BK1, Command2 BK1 - * 1:11 = CMD2BK3, Command2 BK3 - * 0:00 = Command2 disable - */ -#define DSI_CMD2BK0_SEL 0x10 -#define DSI_CMD2BK1_SEL 0x11 -#define DSI_CMD2BK3_SEL 0x13 -#define DSI_CMD2BKX_SEL_NONE 0x00 - /* Command2, BK0 bytes */ #define DSI_CMD2_BK0_GAMCTRL_AJ_MASK GENMASK(7, 6) #define DSI_CMD2_BK0_GAMCTRL_VC0_MASK GENMASK(3, 0) @@ -191,6 +179,18 @@ static u8 st7701_vgls_map(struct st7701 *st7701) return 0; } +static void st7701_switch_cmd_bkx(struct st7701 *st7701, bool cmd2, u8 bkx) +{ + u8 val; + + if (cmd2) + val = DSI_CMD2 | FIELD_PREP(DSI_CMD2BK_MASK, bkx); + else + val = DSI_CMD1; + + ST7701_DSI(st7701, DSI_CMD2BKX_SEL, 0x77, 0x01, 0x00, 0x00, val); +} + static void st7701_init_sequence(struct st7701 *st7701) { const struct st7701_panel_desc *desc = st7701->desc; @@ -208,8 +208,8 @@ static void st7701_init_sequence(struct st7701 *st7701) msleep(st7701->sleep_delay); /* Command2, BK0 */ - ST7701_DSI(st7701, DSI_CMD2BKX_SEL, - 0x77, 0x01, 0x00, 0x00, DSI_CMD2BK0_SEL); + st7701_switch_cmd_bkx(st7701, true, 0); + mipi_dsi_dcs_write(st7701->dsi, DSI_CMD2_BK0_PVGAMCTRL, desc->pv_gamma, ARRAY_SIZE(desc->pv_gamma)); mipi_dsi_dcs_write(st7701->dsi, DSI_CMD2_BK0_NVGAMCTRL, @@ -247,8 +247,7 @@ static void st7701_init_sequence(struct st7701 *st7701) (clamp((u32)mode->htotal, 512U, 1008U) - 512) / 16)); /* Command2, BK1 */ - ST7701_DSI(st7701, DSI_CMD2BKX_SEL, - 0x77, 0x01, 0x00, 0x00, DSI_CMD2BK1_SEL); + st7701_switch_cmd_bkx(st7701, true, 1); /* Vop = 3.5375V + (VRHA[7:0] * 0.0125V) */ ST7701_DSI(st7701, DSI_CMD2_BK1_VRHS, @@ -373,33 +372,27 @@ static void dmt028vghmcmi_1a_gip_sequence(struct st7701 *st7701) 0x08, 0x08, 0x08, 0x40, 0x3F, 0x64); - ST7701_DSI(st7701, DSI_CMD2BKX_SEL, - 0x77, 0x01, 0x00, 0x00, DSI_CMD2BKX_SEL_NONE); + st7701_switch_cmd_bkx(st7701, false, 0); - ST7701_DSI(st7701, DSI_CMD2BKX_SEL, - 0x77, 0x01, 0x00, 0x00, DSI_CMD2BK3_SEL); + st7701_switch_cmd_bkx(st7701, true, 3); ST7701_DSI(st7701, 0xE6, 0x7C); ST7701_DSI(st7701, 0xE8, 0x00, 0x0E); - ST7701_DSI(st7701, DSI_CMD2BKX_SEL, - 0x77, 0x01, 0x00, 0x00, DSI_CMD2BKX_SEL_NONE); + st7701_switch_cmd_bkx(st7701, false, 0); ST7701_DSI(st7701, 0x11); msleep(120); - ST7701_DSI(st7701, DSI_CMD2BKX_SEL, - 0x77, 0x01, 0x00, 0x00, DSI_CMD2BK3_SEL); + st7701_switch_cmd_bkx(st7701, true, 3); ST7701_DSI(st7701, 0xE8, 0x00, 0x0C); msleep(10); ST7701_DSI(st7701, 0xE8, 0x00, 0x00); - ST7701_DSI(st7701, DSI_CMD2BKX_SEL, - 0x77, 0x01, 0x00, 0x00, DSI_CMD2BKX_SEL_NONE); + st7701_switch_cmd_bkx(st7701, false, 0); ST7701_DSI(st7701, 0x11); msleep(120); ST7701_DSI(st7701, 0xE8, 0x00, 0x00); - ST7701_DSI(st7701, DSI_CMD2BKX_SEL, - 0x77, 0x01, 0x00, 0x00, DSI_CMD2BKX_SEL_NONE); + st7701_switch_cmd_bkx(st7701, false, 0); ST7701_DSI(st7701, 0x3A, 0x70); } @@ -426,8 +419,7 @@ static int st7701_prepare(struct drm_panel *panel) st7701->desc->gip_sequence(st7701); /* Disable Command2 */ - ST7701_DSI(st7701, DSI_CMD2BKX_SEL, - 0x77, 0x01, 0x00, 0x00, DSI_CMD2BKX_SEL_NONE); + st7701_switch_cmd_bkx(st7701, false, 0); return 0; } -- cgit From c62102165dd79284d42383d2f7ed17301bd8e629 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 15 Oct 2022 01:11:06 +0200 Subject: drm/panel/panel-sitronix-st7701: Remove panel on DSI attach failure In case mipi_dsi_attach() fails, call drm_panel_remove() to avoid memory leak. Fixes: 849b2e3ff969 ("drm/panel: Add Sitronix ST7701 panel driver") Signed-off-by: Marek Vasut Signed-off-by: Linus Walleij Link: https://patchwork.freedesktop.org/patch/msgid/20221014231106.468063-1-marex@denx.de --- drivers/gpu/drm/panel/panel-sitronix-st7701.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7701.c b/drivers/gpu/drm/panel/panel-sitronix-st7701.c index baeb952b6e24..0b8cf65172ff 100644 --- a/drivers/gpu/drm/panel/panel-sitronix-st7701.c +++ b/drivers/gpu/drm/panel/panel-sitronix-st7701.c @@ -754,7 +754,15 @@ static int st7701_dsi_probe(struct mipi_dsi_device *dsi) st7701->dsi = dsi; st7701->desc = desc; - return mipi_dsi_attach(dsi); + ret = mipi_dsi_attach(dsi); + if (ret) + goto err_attach; + + return 0; + +err_attach: + drm_panel_remove(&st7701->panel); + return ret; } static void st7701_dsi_remove(struct mipi_dsi_device *dsi) -- cgit From ad1ea98019e209eff32e4e22012a4b3276cfdf93 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 31 Oct 2022 15:56:58 +0200 Subject: drm/i915: Fix cs timestamp frequency for ctg/elk/ilk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On ilk the UDW of TIMESTAMP increments every 1000 ns, LDW is mbz. In order to represent that we'd need 52 bits, but we only have 32 bits. Even worse most things want to only deal with 32 bits of timestamp. So let's just set up the timestamp frequency as if we only had the UDW. On ctg/elk 63:20 of TIMESTAMP increments every 1/4 ns, 19:0 are mbz. To make life simpler let's ignore the LDW and set up timestamp frequency based on the UDW only (increments every 1024 ns). v2: Rebase Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221031135703.14670-2-ville.syrjala@linux.intel.com Reviewed-by: Lionel Landwerlin --- drivers/gpu/drm/i915/gt/intel_gt_clock_utils.c | 28 ++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_clock_utils.c b/drivers/gpu/drm/i915/gt/intel_gt_clock_utils.c index 3f656d3dba9a..ebb7a5b3e87c 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_clock_utils.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_clock_utils.c @@ -107,7 +107,7 @@ static u32 gen9_read_clock_frequency(struct intel_uncore *uncore) return freq; } -static u32 gen5_read_clock_frequency(struct intel_uncore *uncore) +static u32 gen6_read_clock_frequency(struct intel_uncore *uncore) { /* * PRMs say: @@ -119,6 +119,26 @@ static u32 gen5_read_clock_frequency(struct intel_uncore *uncore) return 12500000; } +static u32 gen5_read_clock_frequency(struct intel_uncore *uncore) +{ + /* + * 63:32 increments every 1000 ns + * 31:0 mbz + */ + return 1000000000 / 1000; +} + +static u32 g4x_read_clock_frequency(struct intel_uncore *uncore) +{ + /* + * 63:20 increments every 1/4 ns + * 19:0 mbz + * + * -> 63:32 increments every 1024 ns + */ + return 1000000000 / 1024; +} + static u32 gen2_read_clock_frequency(struct intel_uncore *uncore) { /* @@ -137,8 +157,12 @@ static u32 read_clock_frequency(struct intel_uncore *uncore) return gen11_read_clock_frequency(uncore); else if (GRAPHICS_VER(uncore->i915) >= 9) return gen9_read_clock_frequency(uncore); - else if (GRAPHICS_VER(uncore->i915) >= 5) + else if (GRAPHICS_VER(uncore->i915) >= 6) + return gen6_read_clock_frequency(uncore); + else if (GRAPHICS_VER(uncore->i915) == 5) return gen5_read_clock_frequency(uncore); + else if (IS_G4X(uncore->i915)) + return g4x_read_clock_frequency(uncore); else return gen2_read_clock_frequency(uncore); } -- cgit From 78e418d0ea7f74bca0c2312281a28de831ae8edf Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 31 Oct 2022 15:56:59 +0200 Subject: drm/i915: Stop claiming cs timestamp frquency on gen2/3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Gen2/3 have no TIMESTAMP registers to sample so no point in thinking we have any frequency for it either. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221031135703.14670-3-ville.syrjala@linux.intel.com Reviewed-by: Lionel Landwerlin --- drivers/gpu/drm/i915/gt/intel_gt_clock_utils.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_clock_utils.c b/drivers/gpu/drm/i915/gt/intel_gt_clock_utils.c index ebb7a5b3e87c..23a27e49b898 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_clock_utils.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_clock_utils.c @@ -139,7 +139,7 @@ static u32 g4x_read_clock_frequency(struct intel_uncore *uncore) return 1000000000 / 1024; } -static u32 gen2_read_clock_frequency(struct intel_uncore *uncore) +static u32 gen4_read_clock_frequency(struct intel_uncore *uncore) { /* * PRMs say: @@ -163,8 +163,10 @@ static u32 read_clock_frequency(struct intel_uncore *uncore) return gen5_read_clock_frequency(uncore); else if (IS_G4X(uncore->i915)) return g4x_read_clock_frequency(uncore); + else if (GRAPHICS_VER(uncore->i915) == 4) + return gen4_read_clock_frequency(uncore); else - return gen2_read_clock_frequency(uncore); + return 0; } void intel_gt_init_clock_frequency(struct intel_gt *gt) -- cgit From dbea79a50221899e2c3b4be9967f535e89fd6d00 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 31 Oct 2022 15:57:00 +0200 Subject: drm/i915: Fix cs timestamp frequency for cl/bw MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Despite what the spec says the TIMESTAMP register seems to tick once every hrawclk (confirmed on i965gm and g35). v2: Rebase Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221031135703.14670-4-ville.syrjala@linux.intel.com Reviewed-by: Lionel Landwerlin --- drivers/gpu/drm/i915/gt/intel_gt_clock_utils.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gt/intel_gt_clock_utils.c b/drivers/gpu/drm/i915/gt/intel_gt_clock_utils.c index 23a27e49b898..2a6a4ca7fdad 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_clock_utils.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_clock_utils.c @@ -147,8 +147,10 @@ static u32 gen4_read_clock_frequency(struct intel_uncore *uncore) * "The value in this register increments once every 16 * hclks." (through the “Clocking Configuration” * (“CLKCFG”) MCHBAR register) + * + * Testing on actual hardware has shown there is no /16. */ - return RUNTIME_INFO(uncore->i915)->rawclk_freq * 1000 / 16; + return RUNTIME_INFO(uncore->i915)->rawclk_freq * 1000; } static u32 read_clock_frequency(struct intel_uncore *uncore) -- cgit From cf8a82de21c0d2a4e74c159f8479eb1a742ec519 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 31 Oct 2022 15:57:01 +0200 Subject: drm/i915/selftests: Run MI_BB perf selftests on SNB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SNB does have the RING_TIMESTAMP register on the RCS engine. Run the MI_BB perf tests on it. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221031135703.14670-5-ville.syrjala@linux.intel.com Reviewed-by: Lionel Landwerlin --- drivers/gpu/drm/i915/gt/selftest_engine_cs.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/selftest_engine_cs.c b/drivers/gpu/drm/i915/gt/selftest_engine_cs.c index 1b75f478d1b8..b11152f87627 100644 --- a/drivers/gpu/drm/i915/gt/selftest_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/selftest_engine_cs.c @@ -125,7 +125,7 @@ static int perf_mi_bb_start(void *arg) enum intel_engine_id id; int err = 0; - if (GRAPHICS_VER(gt->i915) < 7) /* for per-engine CS_TIMESTAMP */ + if (GRAPHICS_VER(gt->i915) < 6) /* for per-engine CS_TIMESTAMP */ return 0; perf_begin(gt); @@ -135,6 +135,9 @@ static int perf_mi_bb_start(void *arg) u32 cycles[COUNT]; int i; + if (GRAPHICS_VER(engine->i915) < 7 && engine->id != RCS0) + continue; + intel_engine_pm_get(engine); batch = create_empty_batch(ce); @@ -249,7 +252,7 @@ static int perf_mi_noop(void *arg) enum intel_engine_id id; int err = 0; - if (GRAPHICS_VER(gt->i915) < 7) /* for per-engine CS_TIMESTAMP */ + if (GRAPHICS_VER(gt->i915) < 6) /* for per-engine CS_TIMESTAMP */ return 0; perf_begin(gt); @@ -259,6 +262,9 @@ static int perf_mi_noop(void *arg) u32 cycles[COUNT]; int i; + if (GRAPHICS_VER(engine->i915) < 7 && engine->id != RCS0) + continue; + intel_engine_pm_get(engine); base = create_empty_batch(ce); -- cgit From 38530a37de499bbb6244018d8d515995fbd89441 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 31 Oct 2022 15:57:02 +0200 Subject: drm/i915/selftests: Test RING_TIMESTAMP on gen4/5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that we actually know the cs timestamp frequency on gen4/5 let's run the corresponding test. On g4x/ilk we must read the udw of the 64bit timestamp register. Details in {g4x,gen5)_read_clock_frequency(). The one extra caveat is that on i965 (or at least CL, don't recall if I ever tested on BW) we must read the register twice to get an up to date value. For some unknown reason the first read tends to return a stale value. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221031135703.14670-6-ville.syrjala@linux.intel.com Reviewed-by: Lionel Landwerlin --- drivers/gpu/drm/i915/gt/selftest_gt_pm.c | 36 +++++++++++++------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/selftest_gt_pm.c b/drivers/gpu/drm/i915/gt/selftest_gt_pm.c index be94f863bdef..b46425aeb2f0 100644 --- a/drivers/gpu/drm/i915/gt/selftest_gt_pm.c +++ b/drivers/gpu/drm/i915/gt/selftest_gt_pm.c @@ -36,6 +36,19 @@ static int cmp_u32(const void *A, const void *B) return 0; } +static u32 read_timestamp(struct intel_engine_cs *engine) +{ + struct drm_i915_private *i915 = engine->i915; + + /* On i965 the first read tends to give a stale value */ + ENGINE_READ_FW(engine, RING_TIMESTAMP); + + if (GRAPHICS_VER(i915) == 5 || IS_G4X(i915)) + return ENGINE_READ_FW(engine, RING_TIMESTAMP_UDW); + else + return ENGINE_READ_FW(engine, RING_TIMESTAMP); +} + static void measure_clocks(struct intel_engine_cs *engine, u32 *out_cycles, ktime_t *out_dt) { @@ -45,13 +58,13 @@ static void measure_clocks(struct intel_engine_cs *engine, for (i = 0; i < 5; i++) { local_irq_disable(); - cycles[i] = -ENGINE_READ_FW(engine, RING_TIMESTAMP); + cycles[i] = -read_timestamp(engine); dt[i] = ktime_get(); udelay(1000); dt[i] = ktime_sub(ktime_get(), dt[i]); - cycles[i] += ENGINE_READ_FW(engine, RING_TIMESTAMP); + cycles[i] += read_timestamp(engine); local_irq_enable(); } @@ -78,25 +91,6 @@ static int live_gt_clocks(void *arg) if (GRAPHICS_VER(gt->i915) < 4) /* Any CS_TIMESTAMP? */ return 0; - if (GRAPHICS_VER(gt->i915) == 5) - /* - * XXX CS_TIMESTAMP low dword is dysfunctional? - * - * Ville's experiments indicate the high dword still works, - * but at a correspondingly reduced frequency. - */ - return 0; - - if (GRAPHICS_VER(gt->i915) == 4) - /* - * XXX CS_TIMESTAMP appears gibberish - * - * Ville's experiments indicate that it mostly appears 'stuck' - * in that we see the register report the same cycle count - * for a couple of reads. - */ - return 0; - intel_gt_pm_get(gt); intel_uncore_forcewake_get(gt->uncore, FORCEWAKE_ALL); -- cgit From 1086af67b9ab5229a8166909df01f289bc9a17bd Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 31 Oct 2022 15:57:03 +0200 Subject: drm/i915/selftests: Run the perf MI_BB tests on gen4/5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that we know the ring timestamp frequency on gen4/5 we can run the perf tests that depend on sampling the timestamp. On g4x/ilk we must read the udw of the 64bit timestamp register. Details in {g4x,gen5)_read_clock_frequency(). When executing the read via the CS i965 doesn't seem to need the double read trick that CPU mmio reads need. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221031135703.14670-7-ville.syrjala@linux.intel.com Reviewed-by: Lionel Landwerlin --- drivers/gpu/drm/i915/gt/selftest_engine_cs.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/selftest_engine_cs.c b/drivers/gpu/drm/i915/gt/selftest_engine_cs.c index b11152f87627..881b64f3e7b9 100644 --- a/drivers/gpu/drm/i915/gt/selftest_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/selftest_engine_cs.c @@ -39,6 +39,16 @@ static int perf_end(struct intel_gt *gt) return igt_flush_test(gt->i915); } +static i915_reg_t timestamp_reg(struct intel_engine_cs *engine) +{ + struct drm_i915_private *i915 = engine->i915; + + if (GRAPHICS_VER(i915) == 5 || IS_G4X(i915)) + return RING_TIMESTAMP_UDW(engine->mmio_base); + else + return RING_TIMESTAMP(engine->mmio_base); +} + static int write_timestamp(struct i915_request *rq, int slot) { struct intel_timeline *tl = @@ -55,7 +65,7 @@ static int write_timestamp(struct i915_request *rq, int slot) if (GRAPHICS_VER(rq->engine->i915) >= 8) cmd++; *cs++ = cmd; - *cs++ = i915_mmio_reg_offset(RING_TIMESTAMP(rq->engine->mmio_base)); + *cs++ = i915_mmio_reg_offset(timestamp_reg(rq->engine)); *cs++ = tl->hwsp_offset + slot * sizeof(u32); *cs++ = 0; @@ -125,7 +135,7 @@ static int perf_mi_bb_start(void *arg) enum intel_engine_id id; int err = 0; - if (GRAPHICS_VER(gt->i915) < 6) /* for per-engine CS_TIMESTAMP */ + if (GRAPHICS_VER(gt->i915) < 4) /* Any CS_TIMESTAMP? */ return 0; perf_begin(gt); @@ -252,7 +262,7 @@ static int perf_mi_noop(void *arg) enum intel_engine_id id; int err = 0; - if (GRAPHICS_VER(gt->i915) < 6) /* for per-engine CS_TIMESTAMP */ + if (GRAPHICS_VER(gt->i915) < 4) /* Any CS_TIMESTAMP? */ return 0; perf_begin(gt); -- cgit From 387659939c00156f8d6bab0fbc55b4eaf2b6bc5b Mon Sep 17 00:00:00 2001 From: Gaosheng Cui Date: Mon, 31 Oct 2022 19:33:50 +0800 Subject: drm/ttm: fix undefined behavior in bit shift for TTM_TT_FLAG_PRIV_POPULATED MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Shifting signed 32-bit value by 31 bits is undefined, so changing significant bit to unsigned. The UBSAN warning calltrace like below: UBSAN: shift-out-of-bounds in ./include/drm/ttm/ttm_tt.h:122:26 left shift of 1 by 31 places cannot be represented in type 'int' Call Trace: dump_stack_lvl+0x7d/0xa5 dump_stack+0x15/0x1b ubsan_epilogue+0xe/0x4e __ubsan_handle_shift_out_of_bounds+0x1e7/0x20c ttm_bo_move_memcpy+0x3b4/0x460 [ttm] bo_driver_move+0x32/0x40 [drm_vram_helper] ttm_bo_handle_move_mem+0x118/0x200 [ttm] ttm_bo_validate+0xfa/0x220 [ttm] drm_gem_vram_pin_locked+0x70/0x1b0 [drm_vram_helper] drm_gem_vram_pin+0x48/0xb0 [drm_vram_helper] drm_gem_vram_plane_helper_prepare_fb+0x53/0xe0 [drm_vram_helper] drm_gem_vram_simple_display_pipe_prepare_fb+0x26/0x30 [drm_vram_helper] drm_simple_kms_plane_prepare_fb+0x4d/0xe0 [drm_kms_helper] drm_atomic_helper_prepare_planes+0xda/0x210 [drm_kms_helper] drm_atomic_helper_commit+0xc3/0x1e0 [drm_kms_helper] drm_atomic_commit+0x9c/0x160 [drm] drm_client_modeset_commit_atomic+0x33a/0x380 [drm] drm_client_modeset_commit_locked+0x77/0x220 [drm] drm_client_modeset_commit+0x31/0x60 [drm] __drm_fb_helper_restore_fbdev_mode_unlocked+0xa7/0x170 [drm_kms_helper] drm_fb_helper_set_par+0x51/0x90 [drm_kms_helper] fbcon_init+0x316/0x790 visual_init+0x113/0x1d0 do_bind_con_driver+0x2a3/0x5c0 do_take_over_console+0xa9/0x270 do_fbcon_takeover+0xa1/0x170 do_fb_registered+0x2a8/0x340 fbcon_fb_registered+0x47/0xe0 register_framebuffer+0x294/0x4a0 __drm_fb_helper_initial_config_and_unlock+0x43c/0x880 [drm_kms_helper] drm_fb_helper_initial_config+0x52/0x80 [drm_kms_helper] drm_fbdev_client_hotplug+0x156/0x1b0 [drm_kms_helper] drm_fbdev_generic_setup+0xfc/0x290 [drm_kms_helper] bochs_pci_probe+0x6ca/0x772 [bochs] local_pci_probe+0x4d/0xb0 pci_device_probe+0x119/0x320 really_probe+0x181/0x550 __driver_probe_device+0xc6/0x220 driver_probe_device+0x32/0x100 __driver_attach+0x195/0x200 bus_for_each_dev+0xbb/0x120 driver_attach+0x27/0x30 bus_add_driver+0x22e/0x2f0 driver_register+0xa9/0x190 __pci_register_driver+0x90/0xa0 bochs_pci_driver_init+0x52/0x1000 [bochs] do_one_initcall+0x76/0x430 do_init_module+0x61/0x28a load_module+0x1f82/0x2e50 __do_sys_finit_module+0xf8/0x190 __x64_sys_finit_module+0x23/0x30 do_syscall_64+0x58/0x80 entry_SYSCALL_64_after_hwframe+0x63/0xcd Fixes: 3312be8f6fc8 ("drm/ttm: move populated state into page flags") Signed-off-by: Gaosheng Cui Reviewed-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20221031113350.4180975-1-cuigaosheng1@huawei.com Signed-off-by: Christian König --- include/drm/ttm/ttm_tt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/drm/ttm/ttm_tt.h b/include/drm/ttm/ttm_tt.h index 17a0310e8aaa..b7d3f3843f1e 100644 --- a/include/drm/ttm/ttm_tt.h +++ b/include/drm/ttm/ttm_tt.h @@ -88,7 +88,7 @@ struct ttm_tt { #define TTM_TT_FLAG_EXTERNAL (1 << 2) #define TTM_TT_FLAG_EXTERNAL_MAPPABLE (1 << 3) -#define TTM_TT_FLAG_PRIV_POPULATED (1 << 31) +#define TTM_TT_FLAG_PRIV_POPULATED (1U << 31) uint32_t page_flags; /** @num_pages: Number of pages in the page array. */ uint32_t num_pages; -- cgit From d3292daee319581d0a502fcd8ef3c3c285a1750a Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sun, 30 Oct 2022 18:44:11 +0300 Subject: dma-buf: Make locking consistent in dma_buf_detach() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dma_buf_detach() locks attach->dmabuf->resv and then unlocks dmabuf->resv, which could be a two different locks from a static code checker perspective. In particular this triggers Smatch to report the "double unlock" error. Make the locking pointers consistent. Reported-by: Dan Carpenter Reviewed-by: Christian König Link: https://lore.kernel.org/dri-devel/Y1fLfsccW3AS%2Fo+%2F@kili/ Fixes: 809d9c72c2f8 ("dma-buf: Move dma_buf_attach() to dynamic locking specification") Signed-off-by: Dmitry Osipenko Link: https://patchwork.freedesktop.org/patch/msgid/20221030154412.8320-2-dmitry.osipenko@collabora.com --- drivers/dma-buf/dma-buf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index c40d72d318fd..13bfd2d09c56 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -995,10 +995,10 @@ static void __unmap_dma_buf(struct dma_buf_attachment *attach, */ void dma_buf_detach(struct dma_buf *dmabuf, struct dma_buf_attachment *attach) { - if (WARN_ON(!dmabuf || !attach)) + if (WARN_ON(!dmabuf || !attach || dmabuf != attach->dmabuf)) return; - dma_resv_lock(attach->dmabuf->resv, NULL); + dma_resv_lock(dmabuf->resv, NULL); if (attach->sgt) { -- cgit From 444bbba708e804c13ad757068d1cb31ed6460754 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sun, 30 Oct 2022 18:44:12 +0300 Subject: drm/client: Prevent NULL dereference in drm_client_buffer_delete() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The drm_gem_vunmap() will crash with a NULL dereference if the passed object pointer is NULL. It wasn't a problem before we added the locking support to drm_gem_vunmap function because the mapping argument was always NULL together with the object. Make drm_client_buffer_delete() to check whether GEM is NULL before trying to unmap the GEM, it will happen on framebuffer creation error. Reported-by: Dan Carpenter Reviewed-by: Christian König Link: https://lore.kernel.org/dri-devel/Y1kFEGxT8MVlf32V@kili/ Fixes: 79e2cf2e7a19 ("drm/gem: Take reservation lock for vmap/vunmap operations") Signed-off-by: Dmitry Osipenko Link: https://patchwork.freedesktop.org/patch/msgid/20221030154412.8320-3-dmitry.osipenko@collabora.com --- drivers/gpu/drm/drm_client.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c index 38e1be991caa..fd67efe37c63 100644 --- a/drivers/gpu/drm/drm_client.c +++ b/drivers/gpu/drm/drm_client.c @@ -235,10 +235,10 @@ static void drm_client_buffer_delete(struct drm_client_buffer *buffer) { struct drm_device *dev = buffer->client->dev; - drm_gem_vunmap_unlocked(buffer->gem, &buffer->map); - - if (buffer->gem) + if (buffer->gem) { + drm_gem_vunmap_unlocked(buffer->gem, &buffer->map); drm_gem_object_put(buffer->gem); + } if (buffer->handle) drm_mode_destroy_dumb(dev, buffer->handle, buffer->client->file); -- cgit From ce28ab1380e823e0afdff06a59a04375ef9d9a29 Mon Sep 17 00:00:00 2001 From: Arthur Grillo Date: Fri, 28 Oct 2022 19:17:54 -0300 Subject: drm/tests: Add back seed value information MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As reported by Michał, the drm_mm and drm_buddy unit tests lost the printk with seed value after they were refactored into KUnit. Add kunit_info with seed value information to assure reproducibility. Reported-by: Michał Winiarski Signed-off-by: Arthur Grillo Signed-off-by: Maíra Canal Link: https://patchwork.freedesktop.org/patch/msgid/20221028221755.340487-1-arthurgrillo@riseup.net --- drivers/gpu/drm/tests/drm_buddy_test.c | 6 ++++-- drivers/gpu/drm/tests/drm_mm_test.c | 8 ++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/tests/drm_buddy_test.c b/drivers/gpu/drm/tests/drm_buddy_test.c index 62f69589a72d..f8ee714df396 100644 --- a/drivers/gpu/drm/tests/drm_buddy_test.c +++ b/drivers/gpu/drm/tests/drm_buddy_test.c @@ -726,11 +726,13 @@ static void drm_test_buddy_alloc_limit(struct kunit *test) drm_buddy_fini(&mm); } -static int drm_buddy_init_test(struct kunit *test) +static int drm_buddy_suite_init(struct kunit_suite *suite) { while (!random_seed) random_seed = get_random_u32(); + kunit_info(suite, "Testing DRM buddy manager, with random_seed=0x%x\n", random_seed); + return 0; } @@ -746,7 +748,7 @@ static struct kunit_case drm_buddy_tests[] = { static struct kunit_suite drm_buddy_test_suite = { .name = "drm_buddy", - .init = drm_buddy_init_test, + .suite_init = drm_buddy_suite_init, .test_cases = drm_buddy_tests, }; diff --git a/drivers/gpu/drm/tests/drm_mm_test.c b/drivers/gpu/drm/tests/drm_mm_test.c index c4b66eeae203..89f12d3b4a21 100644 --- a/drivers/gpu/drm/tests/drm_mm_test.c +++ b/drivers/gpu/drm/tests/drm_mm_test.c @@ -2209,11 +2209,15 @@ err_nodes: vfree(nodes); } -static int drm_mm_init_test(struct kunit *test) +static int drm_mm_suite_init(struct kunit_suite *suite) { while (!random_seed) random_seed = get_random_u32(); + kunit_info(suite, + "Testing DRM range manager, with random_seed=0x%x max_iterations=%u max_prime=%u\n", + random_seed, max_iterations, max_prime); + return 0; } @@ -2246,7 +2250,7 @@ static struct kunit_case drm_mm_tests[] = { static struct kunit_suite drm_mm_test_suite = { .name = "drm_mm", - .init = drm_mm_init_test, + .suite_init = drm_mm_suite_init, .test_cases = drm_mm_tests, }; -- cgit From 92bab9142456c37d14a0de212b272cdd94846c6d Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 15 Jun 2022 16:59:31 +0300 Subject: drm/msm: less magic numbers in msm_mdss_enable Replace magic register writes in msm_mdss_enable() with version that contains less magic and more variable names that can be traced back to the dpu_hw_catalog or the downstream dtsi files. Reviewed-by: Abhinav Kumar Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/489578/ Link: https://lore.kernel.org/r/20220615135935.87381-1-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/msm_mdss.c | 80 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 72 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_mdss.c b/drivers/gpu/drm/msm/msm_mdss.c index e13c5c12b775..6a4549ef34d4 100644 --- a/drivers/gpu/drm/msm/msm_mdss.c +++ b/drivers/gpu/drm/msm/msm_mdss.c @@ -22,6 +22,7 @@ #define HW_REV 0x0 #define HW_INTR_STATUS 0x0010 +#define UBWC_DEC_HW_VERSION 0x58 #define UBWC_STATIC 0x144 #define UBWC_CTRL_2 0x150 #define UBWC_PREDICTION_MODE 0x154 @@ -174,9 +175,63 @@ static int _msm_mdss_irq_domain_add(struct msm_mdss *msm_mdss) return 0; } +#define UBWC_1_0 0x10000000 +#define UBWC_2_0 0x20000000 +#define UBWC_3_0 0x30000000 +#define UBWC_4_0 0x40000000 + +static void msm_mdss_setup_ubwc_dec_20(struct msm_mdss *msm_mdss, + u32 ubwc_static) +{ + writel_relaxed(ubwc_static, msm_mdss->mmio + UBWC_STATIC); +} + +static void msm_mdss_setup_ubwc_dec_30(struct msm_mdss *msm_mdss, + unsigned int ubwc_version, + u32 ubwc_swizzle, + u32 highest_bank_bit, + u32 macrotile_mode) +{ + u32 value = (ubwc_swizzle & 0x1) | + (highest_bank_bit & 0x3) << 4 | + (macrotile_mode & 0x1) << 12; + + if (ubwc_version == UBWC_3_0) + value |= BIT(10); + + if (ubwc_version == UBWC_1_0) + value |= BIT(8); + + writel_relaxed(value, msm_mdss->mmio + UBWC_STATIC); +} + +static void msm_mdss_setup_ubwc_dec_40(struct msm_mdss *msm_mdss, + unsigned int ubwc_version, + u32 ubwc_swizzle, + u32 ubwc_static, + u32 highest_bank_bit, + u32 macrotile_mode) +{ + u32 value = (ubwc_swizzle & 0x7) | + (ubwc_static & 0x1) << 3 | + (highest_bank_bit & 0x7) << 4 | + (macrotile_mode & 0x1) << 12; + + writel_relaxed(value, msm_mdss->mmio + UBWC_STATIC); + + if (ubwc_version == UBWC_3_0) { + writel_relaxed(1, msm_mdss->mmio + UBWC_CTRL_2); + writel_relaxed(0, msm_mdss->mmio + UBWC_PREDICTION_MODE); + } else { + writel_relaxed(2, msm_mdss->mmio + UBWC_CTRL_2); + writel_relaxed(1, msm_mdss->mmio + UBWC_PREDICTION_MODE); + } +} + static int msm_mdss_enable(struct msm_mdss *msm_mdss) { int ret; + u32 hw_rev; /* * Several components have AXI clocks that can only be turned on if @@ -198,26 +253,35 @@ static int msm_mdss_enable(struct msm_mdss *msm_mdss) if (msm_mdss->is_mdp5) return 0; + hw_rev = readl_relaxed(msm_mdss->mmio + HW_REV); + dev_dbg(msm_mdss->dev, "HW_REV: 0x%x\n", hw_rev); + dev_dbg(msm_mdss->dev, "UBWC_DEC_HW_VERSION: 0x%x\n", + readl_relaxed(msm_mdss->mmio + UBWC_DEC_HW_VERSION)); + /* * ubwc config is part of the "mdss" region which is not accessible * from the rest of the driver. hardcode known configurations here + * + * Decoder version can be read from the UBWC_DEC_HW_VERSION reg, + * UBWC_n and the rest of params comes from hw_catalog. + * Unforunately this driver can not access hw catalog, so we have to + * hardcode them here. */ - switch (readl_relaxed(msm_mdss->mmio + HW_REV)) { + switch (hw_rev) { case DPU_HW_VER_500: case DPU_HW_VER_501: - writel_relaxed(0x420, msm_mdss->mmio + UBWC_STATIC); + msm_mdss_setup_ubwc_dec_30(msm_mdss, UBWC_3_0, 0, 2, 0); break; case DPU_HW_VER_600: - /* TODO: 0x102e for LP_DDR4 */ - writel_relaxed(0x103e, msm_mdss->mmio + UBWC_STATIC); - writel_relaxed(2, msm_mdss->mmio + UBWC_CTRL_2); - writel_relaxed(1, msm_mdss->mmio + UBWC_PREDICTION_MODE); + /* TODO: highest_bank_bit = 2 for LP_DDR4 */ + msm_mdss_setup_ubwc_dec_40(msm_mdss, UBWC_4_0, 6, 1, 3, 1); break; case DPU_HW_VER_620: - writel_relaxed(0x1e, msm_mdss->mmio + UBWC_STATIC); + /* UBWC_2_0 */ + msm_mdss_setup_ubwc_dec_20(msm_mdss, 0x1e); break; case DPU_HW_VER_720: - writel_relaxed(0x101e, msm_mdss->mmio + UBWC_STATIC); + msm_mdss_setup_ubwc_dec_40(msm_mdss, UBWC_3_0, 6, 1, 1, 1); break; } -- cgit From da7716a249b699978fb555c13dde941002980759 Mon Sep 17 00:00:00 2001 From: Jessica Zhang Date: Thu, 1 Sep 2022 13:34:21 -0700 Subject: drm/msm/dpu: Add support for XR30 format Add support for XR30 color format. This supports both linear and compressed formats. Signed-off-by: Jessica Zhang Reviewed-by: Rob Clark Patchwork: https://patchwork.freedesktop.org/patch/500820/ Link: https://lore.kernel.org/r/20220901203422.217-2-quic_jesszhan@quicinc.com Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c | 7 +++++++ drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c | 2 ++ drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 1 + 3 files changed, 10 insertions(+) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c index f436a1f3419d..57971c08f57c 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c @@ -524,6 +524,12 @@ static const struct dpu_format dpu_format_map_ubwc[] = { true, 4, DPU_FORMAT_FLAG_DX | DPU_FORMAT_FLAG_COMPRESSED, DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_UBWC), + INTERLEAVED_RGB_FMT_TILED(XRGB2101010, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + true, 4, DPU_FORMAT_FLAG_DX | DPU_FORMAT_FLAG_COMPRESSED, + DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_UBWC), + PSEUDO_YUV_FMT_TILED(NV12, 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, C1_B_Cb, C2_R_Cr, @@ -571,6 +577,7 @@ static int _dpu_format_get_media_color_ubwc(const struct dpu_format *fmt) {DRM_FORMAT_XBGR8888, COLOR_FMT_RGBA8888_UBWC}, {DRM_FORMAT_XRGB8888, COLOR_FMT_RGBA8888_UBWC}, {DRM_FORMAT_ABGR2101010, COLOR_FMT_RGBA1010102_UBWC}, + {DRM_FORMAT_XRGB2101010, COLOR_FMT_RGBA1010102_UBWC}, {DRM_FORMAT_XBGR2101010, COLOR_FMT_RGBA1010102_UBWC}, {DRM_FORMAT_BGR565, COLOR_FMT_RGB565_UBWC}, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c index 27f029fdc682..4e79f9bec8c8 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c @@ -156,6 +156,7 @@ static const uint32_t plane_formats[] = { DRM_FORMAT_RGBX8888, DRM_FORMAT_BGRX8888, DRM_FORMAT_XBGR8888, + DRM_FORMAT_XRGB2101010, DRM_FORMAT_RGB888, DRM_FORMAT_BGR888, DRM_FORMAT_RGB565, @@ -184,6 +185,7 @@ static const uint32_t plane_formats_yuv[] = { DRM_FORMAT_RGBA8888, DRM_FORMAT_BGRX8888, DRM_FORMAT_BGRA8888, + DRM_FORMAT_XRGB2101010, DRM_FORMAT_XRGB8888, DRM_FORMAT_XBGR8888, DRM_FORMAT_RGBX8888, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c index 658005f609f4..33bdb9ce65a3 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c @@ -69,6 +69,7 @@ static const uint32_t qcom_compressed_supported_formats[] = { DRM_FORMAT_ARGB8888, DRM_FORMAT_XBGR8888, DRM_FORMAT_XRGB8888, + DRM_FORMAT_XRGB2101010, DRM_FORMAT_BGR565, DRM_FORMAT_NV12, -- cgit From d54c518a496f8cd6db857ec65c6c8bc68f87f16d Mon Sep 17 00:00:00 2001 From: Kuogee Hsieh Date: Mon, 12 Sep 2022 09:23:49 -0700 Subject: drm/msm/dp: replace variable err with len at dp_aux_link_power_up() drm_dp_dpcd_readb() will return 1 to indicate one byte had been read successfully. This patch replace variable "err" with "len" have more correct meaning. changes in v5: -- split into 3 patches Signed-off-by: Kuogee Hsieh Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/502533/ Link: https://lore.kernel.org/r/1662999830-13916-3-git-send-email-quic_khsieh@quicinc.com Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/dp/dp_link.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_link.c b/drivers/gpu/drm/msm/dp/dp_link.c index 36bb6191d2f0..ef35fac333f7 100644 --- a/drivers/gpu/drm/msm/dp/dp_link.c +++ b/drivers/gpu/drm/msm/dp/dp_link.c @@ -49,21 +49,21 @@ static int dp_aux_link_power_up(struct drm_dp_aux *aux, struct dp_link_info *link) { u8 value; - int err; + ssize_t len; if (link->revision < 0x11) return 0; - err = drm_dp_dpcd_readb(aux, DP_SET_POWER, &value); - if (err < 0) - return err; + len = drm_dp_dpcd_readb(aux, DP_SET_POWER, &value); + if (len < 0) + return len; value &= ~DP_SET_POWER_MASK; value |= DP_SET_POWER_D0; - err = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value); - if (err < 0) - return err; + len = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value); + if (len < 0) + return len; usleep_range(1000, 2000); -- cgit From f07c9946cc1a2fc437d10610d43bd558624d9d6a Mon Sep 17 00:00:00 2001 From: Jessica Zhang Date: Thu, 1 Sep 2022 13:34:22 -0700 Subject: drm/msm/dpu: Add support for P010 format Add support for P010 color format. This adds support for both linear and compressed formats. Signed-off-by: Jessica Zhang Reviewed-by: Rob Clark Patchwork: https://patchwork.freedesktop.org/patch/500822/ Link: https://lore.kernel.org/r/20220901203422.217-3-quic_jesszhan@quicinc.com Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c | 17 ++++++++++++++++- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c | 1 + drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 1 + 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c index 57971c08f57c..d95540309d4d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c @@ -434,6 +434,12 @@ static const struct dpu_format dpu_format_map[] = { DPU_CHROMA_H2V1, DPU_FORMAT_FLAG_YUV, DPU_FETCH_LINEAR, 2), + PSEUDO_YUV_FMT_LOOSE(P010, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C2_R_Cr, + DPU_CHROMA_420, DPU_FORMAT_FLAG_DX | DPU_FORMAT_FLAG_YUV, + DPU_FETCH_LINEAR, 2), + INTERLEAVED_YUV_FMT(VYUY, 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, C2_R_Cr, C0_G_Y, C1_B_Cb, C0_G_Y, @@ -536,6 +542,14 @@ static const struct dpu_format dpu_format_map_ubwc[] = { DPU_CHROMA_420, DPU_FORMAT_FLAG_YUV | DPU_FORMAT_FLAG_COMPRESSED, DPU_FETCH_UBWC, 4, DPU_TILE_HEIGHT_NV12), + + PSEUDO_YUV_FMT_TILED(P010, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C2_R_Cr, + DPU_CHROMA_420, DPU_FORMAT_FLAG_DX | + DPU_FORMAT_FLAG_YUV | + DPU_FORMAT_FLAG_COMPRESSED, + DPU_FETCH_UBWC, 4, DPU_TILE_HEIGHT_UBWC), }; /* _dpu_get_v_h_subsample_rate - Get subsample rates for all formats we support @@ -584,7 +598,8 @@ static int _dpu_format_get_media_color_ubwc(const struct dpu_format *fmt) int color_fmt = -1; int i; - if (fmt->base.pixel_format == DRM_FORMAT_NV12) { + if (fmt->base.pixel_format == DRM_FORMAT_NV12 || + fmt->base.pixel_format == DRM_FORMAT_P010) { if (DPU_FORMAT_IS_DX(fmt)) { if (fmt->unpack_tight) color_fmt = COLOR_FMT_NV12_BPP10_UBWC; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c index 4e79f9bec8c8..bae3cc3adb3f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c @@ -210,6 +210,7 @@ static const uint32_t plane_formats_yuv[] = { DRM_FORMAT_RGBX4444, DRM_FORMAT_BGRX4444, + DRM_FORMAT_P010, DRM_FORMAT_NV12, DRM_FORMAT_NV21, DRM_FORMAT_NV16, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c index 33bdb9ce65a3..86719020afe2 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c @@ -73,6 +73,7 @@ static const uint32_t qcom_compressed_supported_formats[] = { DRM_FORMAT_BGR565, DRM_FORMAT_NV12, + DRM_FORMAT_P010, }; /** -- cgit From af309c0c0654f4580c44d1f6db1809e9a78d079e Mon Sep 17 00:00:00 2001 From: Kuogee Hsieh Date: Mon, 12 Sep 2022 09:23:50 -0700 Subject: drm/msm/dp: retry 3 times if set sink to D0 poweer state failed Bring sink out of D3 (power down) mode into D0 (normal operation) mode by setting DP_SET_POWER_D0 bit to DP_SET_POWER dpcd register. This patch will retry 3 times if written to DP_SET_POWER register failed. Changes in v5: -- split into two patches Signed-off-by: Kuogee Hsieh Patchwork: https://patchwork.freedesktop.org/patch/502536/ Link: https://lore.kernel.org/r/1662999830-13916-4-git-send-email-quic_khsieh@quicinc.com Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/dp/dp_link.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_link.c b/drivers/gpu/drm/msm/dp/dp_link.c index ef35fac333f7..f1f1d646539d 100644 --- a/drivers/gpu/drm/msm/dp/dp_link.c +++ b/drivers/gpu/drm/msm/dp/dp_link.c @@ -50,6 +50,7 @@ static int dp_aux_link_power_up(struct drm_dp_aux *aux, { u8 value; ssize_t len; + int i; if (link->revision < 0x11) return 0; @@ -61,11 +62,13 @@ static int dp_aux_link_power_up(struct drm_dp_aux *aux, value &= ~DP_SET_POWER_MASK; value |= DP_SET_POWER_D0; - len = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value); - if (len < 0) - return len; - - usleep_range(1000, 2000); + /* retry for 1ms to give the sink time to wake up */ + for (i = 0; i < 3; i++) { + len = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value); + usleep_range(1000, 2000); + if (len == 1) + break; + } return 0; } -- cgit From c6122688f2652d7f8a44000ce21e84e82bae2b5e Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 24 Oct 2022 18:26:42 +0300 Subject: drm/msm/mdp5: stop overriding drvdata The rest of the code expects that master's device drvdata is the struct msm_drm_private instance. Do not override the mdp5's drvdata. Fixes: 6874f48bb8b0 ("drm/msm: make mdp5/dpu devices master components") Signed-off-by: Dmitry Baryshkov Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/508334/ Link: https://lore.kernel.org/r/20221024152642.3213488-1-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c index b0d21838a134..b46f983f2b46 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c @@ -203,7 +203,7 @@ static int mdp5_set_split_display(struct msm_kms *kms, slave_encoder); } -static void mdp5_destroy(struct platform_device *pdev); +static void mdp5_destroy(struct mdp5_kms *mdp5_kms); static void mdp5_kms_destroy(struct msm_kms *kms) { @@ -223,7 +223,7 @@ static void mdp5_kms_destroy(struct msm_kms *kms) } mdp_kms_destroy(&mdp5_kms->base); - mdp5_destroy(mdp5_kms->pdev); + mdp5_destroy(mdp5_kms); } #ifdef CONFIG_DEBUG_FS @@ -519,9 +519,10 @@ static void read_mdp_hw_revision(struct mdp5_kms *mdp5_kms, struct device *dev = &mdp5_kms->pdev->dev; u32 version; - pm_runtime_get_sync(dev); + /* Manually enable the MDP5, as pm runtime isn't usable yet. */ + mdp5_enable(mdp5_kms); version = mdp5_read(mdp5_kms, REG_MDP5_HW_VERSION); - pm_runtime_put_sync(dev); + mdp5_disable(mdp5_kms); *major = FIELD(version, MDP5_HW_VERSION_MAJOR); *minor = FIELD(version, MDP5_HW_VERSION_MINOR); @@ -559,6 +560,8 @@ static int mdp5_kms_init(struct drm_device *dev) int irq, i, ret; ret = mdp5_init(to_platform_device(dev->dev), dev); + if (ret) + return ret; /* priv->kms would have been populated by the MDP5 driver */ kms = priv->kms; @@ -632,9 +635,8 @@ fail: return ret; } -static void mdp5_destroy(struct platform_device *pdev) +static void mdp5_destroy(struct mdp5_kms *mdp5_kms) { - struct mdp5_kms *mdp5_kms = platform_get_drvdata(pdev); int i; if (mdp5_kms->ctlm) @@ -648,7 +650,7 @@ static void mdp5_destroy(struct platform_device *pdev) kfree(mdp5_kms->intfs[i]); if (mdp5_kms->rpm_enabled) - pm_runtime_disable(&pdev->dev); + pm_runtime_disable(&mdp5_kms->pdev->dev); drm_atomic_private_obj_fini(&mdp5_kms->glob_state); drm_modeset_lock_fini(&mdp5_kms->glob_state_lock); @@ -797,8 +799,6 @@ static int mdp5_init(struct platform_device *pdev, struct drm_device *dev) goto fail; } - platform_set_drvdata(pdev, mdp5_kms); - spin_lock_init(&mdp5_kms->resource_lock); mdp5_kms->dev = dev; @@ -839,9 +839,6 @@ static int mdp5_init(struct platform_device *pdev, struct drm_device *dev) */ clk_set_rate(mdp5_kms->core_clk, 200000000); - pm_runtime_enable(&pdev->dev); - mdp5_kms->rpm_enabled = true; - read_mdp_hw_revision(mdp5_kms, &major, &minor); mdp5_kms->cfg = mdp5_cfg_init(mdp5_kms, major, minor); @@ -893,10 +890,13 @@ static int mdp5_init(struct platform_device *pdev, struct drm_device *dev) /* set uninit-ed kms */ priv->kms = &mdp5_kms->base.base; + pm_runtime_enable(&pdev->dev); + mdp5_kms->rpm_enabled = true; + return 0; fail: if (mdp5_kms) - mdp5_destroy(pdev); + mdp5_destroy(mdp5_kms); return ret; } @@ -953,7 +953,8 @@ static int mdp5_dev_remove(struct platform_device *pdev) static __maybe_unused int mdp5_runtime_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); - struct mdp5_kms *mdp5_kms = platform_get_drvdata(pdev); + struct msm_drm_private *priv = platform_get_drvdata(pdev); + struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms)); DBG(""); @@ -963,7 +964,8 @@ static __maybe_unused int mdp5_runtime_suspend(struct device *dev) static __maybe_unused int mdp5_runtime_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); - struct mdp5_kms *mdp5_kms = platform_get_drvdata(pdev); + struct msm_drm_private *priv = platform_get_drvdata(pdev); + struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms)); DBG(""); -- cgit From fa0cf3e4763efe30eca6ae8171a4e7536dbaca57 Mon Sep 17 00:00:00 2001 From: Liu Shixin Date: Thu, 22 Sep 2022 22:21:47 +0800 Subject: drm/msm/dpu: use DEFINE_SHOW_ATTRIBUTE to simplify dpu_regset32 Use DEFINE_SHOW_ATTRIBUTE helper macro to simplify the code. No functional change. Signed-off-by: Liu Shixin Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/504252/ Link: https://lore.kernel.org/r/20220922142147.3246649-1-liushixin2@huawei.com Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 5e6e2626151e..f3660cd14f4f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -194,7 +194,7 @@ struct dpu_debugfs_regset32 { struct dpu_kms *dpu_kms; }; -static int _dpu_debugfs_show_regset32(struct seq_file *s, void *data) +static int dpu_regset32_show(struct seq_file *s, void *data) { struct dpu_debugfs_regset32 *regset = s->private; struct dpu_kms *dpu_kms = regset->dpu_kms; @@ -227,19 +227,7 @@ static int _dpu_debugfs_show_regset32(struct seq_file *s, void *data) return 0; } - -static int dpu_debugfs_open_regset32(struct inode *inode, - struct file *file) -{ - return single_open(file, _dpu_debugfs_show_regset32, inode->i_private); -} - -static const struct file_operations dpu_fops_regset32 = { - .open = dpu_debugfs_open_regset32, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(dpu_regset32); void dpu_debugfs_create_regset32(const char *name, umode_t mode, void *parent, @@ -259,7 +247,7 @@ void dpu_debugfs_create_regset32(const char *name, umode_t mode, regset->blk_len = length; regset->dpu_kms = dpu_kms; - debugfs_create_file(name, mode, parent, regset, &dpu_fops_regset32); + debugfs_create_file(name, mode, parent, regset, &dpu_regset32_fops); } static int dpu_kms_debugfs_init(struct msm_kms *kms, struct drm_minor *minor) -- cgit From 90d2c87f325ff3422995175bd92812b28d8eb2a9 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Fri, 23 Sep 2022 10:33:07 -0700 Subject: drm/msm: Add MSM_INFO_GET_FLAGS In some cases crosvm needs a way to query the cache flags to communicate them to the guest kernel for guest userspace mapping. Signed-off-by: Rob Clark Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/504453/ Link: https://lore.kernel.org/r/20220923173307.2429872-1-robdclark@gmail.com Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/msm_drv.c | 10 ++++++++++ include/uapi/drm/msm_drm.h | 1 + 2 files changed, 11 insertions(+) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 105b5b48e828..862b60a5e886 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -819,6 +819,7 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data, case MSM_INFO_GET_OFFSET: case MSM_INFO_GET_IOVA: case MSM_INFO_SET_IOVA: + case MSM_INFO_GET_FLAGS: /* value returned as immediate, not pointer, so len==0: */ if (args->len) return -EINVAL; @@ -846,6 +847,15 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data, case MSM_INFO_SET_IOVA: ret = msm_ioctl_gem_info_set_iova(dev, file, obj, args->value); break; + case MSM_INFO_GET_FLAGS: + if (obj->import_attach) { + ret = -EINVAL; + break; + } + /* Hide internal kernel-only flags: */ + args->value = to_msm_bo(obj)->flags & MSM_BO_FLAGS; + ret = 0; + break; case MSM_INFO_SET_NAME: /* length check should leave room for terminating null: */ if (args->len >= sizeof(msm_obj->name)) { diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h index 3c7b097c4e3d..f54b48ef6a2d 100644 --- a/include/uapi/drm/msm_drm.h +++ b/include/uapi/drm/msm_drm.h @@ -138,6 +138,7 @@ struct drm_msm_gem_new { #define MSM_INFO_SET_NAME 0x02 /* set the debug name (by pointer) */ #define MSM_INFO_GET_NAME 0x03 /* get debug name, returned by pointer */ #define MSM_INFO_SET_IOVA 0x04 /* set the iova, passed by value */ +#define MSM_INFO_GET_FLAGS 0x05 /* get the MSM_BO_x flags */ struct drm_msm_gem_info { __u32 handle; /* in */ -- cgit From f7d46c5efee26349b49c13f9ebbfbd6aad8d1e71 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 24 Oct 2022 19:42:14 +0300 Subject: dt-bindings: display/msm: split qcom, mdss bindings Split Mobile Display SubSystem (MDSS) root node bindings to the separate yaml file. Changes to the existing (txt) schema: - Added optional "vbif_nrt_phys" region used by msm8996 - Made "bus" and "vsync" clocks optional (they are not used by some platforms) - Added optional resets property referencing MDSS reset - Defined child nodes pointing to corresponding reference schema. - Dropped the "lut" clock. It was added to the schema by mistake (it is a part of mdp4 schema, not the mdss). Reviewed-by: Rob Herring Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/508378/ Link: https://lore.kernel.org/r/20221024164225.3236654-2-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov --- .../devicetree/bindings/display/msm/mdp5.txt | 30 +--- .../devicetree/bindings/display/msm/qcom,mdss.yaml | 196 +++++++++++++++++++++ 2 files changed, 197 insertions(+), 29 deletions(-) create mode 100644 Documentation/devicetree/bindings/display/msm/qcom,mdss.yaml diff --git a/Documentation/devicetree/bindings/display/msm/mdp5.txt b/Documentation/devicetree/bindings/display/msm/mdp5.txt index 43d11279c925..65d03c58dee6 100644 --- a/Documentation/devicetree/bindings/display/msm/mdp5.txt +++ b/Documentation/devicetree/bindings/display/msm/mdp5.txt @@ -2,37 +2,9 @@ Qualcomm adreno/snapdragon MDP5 display controller Description: -This is the bindings documentation for the Mobile Display Subsytem(MDSS) that -encapsulates sub-blocks like MDP5, DSI, HDMI, eDP etc, and the MDP5 display +This is the bindings documentation for the MDP5 display controller found in SoCs like MSM8974, APQ8084, MSM8916, MSM8994 and MSM8996. -MDSS: -Required properties: -- compatible: - * "qcom,mdss" - MDSS -- reg: Physical base address and length of the controller's registers. -- reg-names: The names of register regions. The following regions are required: - * "mdss_phys" - * "vbif_phys" -- interrupts: The interrupt signal from MDSS. -- interrupt-controller: identifies the node as an interrupt controller. -- #interrupt-cells: specifies the number of cells needed to encode an interrupt - source, should be 1. -- power-domains: a power domain consumer specifier according to - Documentation/devicetree/bindings/power/power_domain.txt -- clocks: device clocks. See ../clocks/clock-bindings.txt for details. -- clock-names: the following clocks are required. - * "iface" - * "bus" - * "vsync" -- #address-cells: number of address cells for the MDSS children. Should be 1. -- #size-cells: Should be 1. -- ranges: parent bus address space is the same as the child bus address space. - -Optional properties: -- clock-names: the following clocks are optional: - * "lut" - MDP5: Required properties: - compatible: diff --git a/Documentation/devicetree/bindings/display/msm/qcom,mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,mdss.yaml new file mode 100644 index 000000000000..ba0460268731 --- /dev/null +++ b/Documentation/devicetree/bindings/display/msm/qcom,mdss.yaml @@ -0,0 +1,196 @@ +# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/msm/qcom,mdss.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Mobile Display SubSystem (MDSS) + +maintainers: + - Dmitry Baryshkov + - Rob Clark + +description: + This is the bindings documentation for the Mobile Display Subsytem(MDSS) that + encapsulates sub-blocks like MDP5, DSI, HDMI, eDP, etc. + +properties: + compatible: + enum: + - qcom,mdss + + reg: + minItems: 2 + maxItems: 3 + + reg-names: + minItems: 2 + items: + - const: mdss_phys + - const: vbif_phys + - const: vbif_nrt_phys + + interrupts: + maxItems: 1 + + interrupt-controller: true + + "#interrupt-cells": + const: 1 + + power-domains: + maxItems: 1 + description: | + The MDSS power domain provided by GCC + + clocks: + minItems: 1 + items: + - description: Display abh clock + - description: Display axi clock + - description: Display vsync clock + + clock-names: + minItems: 1 + items: + - const: iface + - const: bus + - const: vsync + + "#address-cells": + const: 1 + + "#size-cells": + const: 1 + + ranges: true + + resets: + items: + - description: MDSS_CORE reset + +required: + - compatible + - reg + - reg-names + - interrupts + - interrupt-controller + - "#interrupt-cells" + - power-domains + - clocks + - clock-names + - "#address-cells" + - "#size-cells" + - ranges + +patternProperties: + "^mdp@[1-9a-f][0-9a-f]*$": + type: object + properties: + compatible: + const: qcom,mdp5 + + "^dsi@[1-9a-f][0-9a-f]*$": + type: object + properties: + compatible: + const: qcom,mdss-dsi-ctrl + + "^phy@[1-9a-f][0-9a-f]*$": + type: object + properties: + compatible: + enum: + - qcom,dsi-phy-14nm + - qcom,dsi-phy-14nm-660 + - qcom,dsi-phy-14nm-8953 + - qcom,dsi-phy-20nm + - qcom,dsi-phy-28nm-hpm + - qcom,dsi-phy-28nm-lp + + "^hdmi-phy@[1-9a-f][0-9a-f]*$": + type: object + properties: + compatible: + enum: + - qcom,hdmi-phy-8084 + - qcom,hdmi-phy-8660 + - qcom,hdmi-phy-8960 + - qcom,hdmi-phy-8974 + - qcom,hdmi-phy-8996 + + "^hdmi-tx@[1-9a-f][0-9a-f]*$": + type: object + properties: + compatible: + enum: + - qcom,hdmi-tx-8084 + - qcom,hdmi-tx-8660 + - qcom,hdmi-tx-8960 + - qcom,hdmi-tx-8974 + - qcom,hdmi-tx-8994 + - qcom,hdmi-tx-8996 + +additionalProperties: false + +examples: + - | + #include + #include + mdss@1a00000 { + compatible = "qcom,mdss"; + reg = <0x1a00000 0x1000>, + <0x1ac8000 0x3000>; + reg-names = "mdss_phys", "vbif_phys"; + + power-domains = <&gcc MDSS_GDSC>; + + clocks = <&gcc GCC_MDSS_AHB_CLK>, + <&gcc GCC_MDSS_AXI_CLK>, + <&gcc GCC_MDSS_VSYNC_CLK>; + clock-names = "iface", + "bus", + "vsync"; + + interrupts = ; + + interrupt-controller; + #interrupt-cells = <1>; + + #address-cells = <1>; + #size-cells = <1>; + ranges; + + mdp@1a01000 { + compatible = "qcom,mdp5"; + reg = <0x01a01000 0x89000>; + reg-names = "mdp_phys"; + + interrupt-parent = <&mdss>; + interrupts = <0>; + + clocks = <&gcc GCC_MDSS_AHB_CLK>, + <&gcc GCC_MDSS_AXI_CLK>, + <&gcc GCC_MDSS_MDP_CLK>, + <&gcc GCC_MDSS_VSYNC_CLK>; + clock-names = "iface", + "bus", + "core", + "vsync"; + + iommus = <&apps_iommu 4>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + mdp5_intf1_out: endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; + }; + }; + }; +... -- cgit From 1db11fc37fdd903b7f4765b83ba5c9961be7ab56 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 24 Oct 2022 19:42:15 +0300 Subject: dt-bindings: display/msm: add gcc-bus clock to dpu-smd845 Add gcc-bus clock required for the SDM845 DPU device tree node. This change was made in the commit 111c52854102 ("arm64: dts: qcom: sdm845: move bus clock to mdp node for sdm845 target"), but was not reflected in the schema. Reviewed-by: Rob Herring Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/508379/ Link: https://lore.kernel.org/r/20221024164225.3236654-3-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov --- Documentation/devicetree/bindings/display/msm/dpu-sdm845.yaml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/display/msm/dpu-sdm845.yaml b/Documentation/devicetree/bindings/display/msm/dpu-sdm845.yaml index 7d1037373175..3cb2ae336996 100644 --- a/Documentation/devicetree/bindings/display/msm/dpu-sdm845.yaml +++ b/Documentation/devicetree/bindings/display/msm/dpu-sdm845.yaml @@ -84,6 +84,7 @@ patternProperties: clocks: items: + - description: Display GCC bus clock - description: Display ahb clock - description: Display axi clock - description: Display core clock @@ -91,6 +92,7 @@ patternProperties: clock-names: items: + - const: gcc-bus - const: iface - const: bus - const: core @@ -183,11 +185,12 @@ examples: <0x0aeb0000 0x2008>; reg-names = "mdp", "vbif"; - clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + clocks = <&gcc GCC_DISP_AXI_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, <&dispcc DISP_CC_MDSS_AXI_CLK>, <&dispcc DISP_CC_MDSS_MDP_CLK>, <&dispcc DISP_CC_MDSS_VSYNC_CLK>; - clock-names = "iface", "bus", "core", "vsync"; + clock-names = "gcc-bus", "iface", "bus", "core", "vsync"; interrupt-parent = <&mdss>; interrupts = <0>; -- cgit From 4116c9ad3a9d0ec4c6aa558b58472c51afff9c24 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 24 Oct 2022 19:42:16 +0300 Subject: dt-bindings: display/msm: add interconnects property to qcom, mdss-smd845 Add interconnects required for the SDM845 MDSS device tree node. This change was made in the commit c8c61c09e38b ("arm64: dts: qcom: sdm845: Add interconnects property for display"), but was not reflected in the schema. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/508380/ Link: https://lore.kernel.org/r/20221024164225.3236654-4-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov --- Documentation/devicetree/bindings/display/msm/dpu-sdm845.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Documentation/devicetree/bindings/display/msm/dpu-sdm845.yaml b/Documentation/devicetree/bindings/display/msm/dpu-sdm845.yaml index 3cb2ae336996..a87deea8e9bc 100644 --- a/Documentation/devicetree/bindings/display/msm/dpu-sdm845.yaml +++ b/Documentation/devicetree/bindings/display/msm/dpu-sdm845.yaml @@ -57,6 +57,16 @@ properties: ranges: true + interconnects: + items: + - description: Interconnect path from mdp0 port to the data bus + - description: Interconnect path from mdp1 port to the data bus + + interconnect-names: + items: + - const: mdp0-mem + - const: mdp1-mem + resets: items: - description: MDSS_CORE reset -- cgit From c3d7f3e7bbab635d1846844b747bf7e01d1c339a Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 24 Oct 2022 19:42:17 +0300 Subject: dt-bindings: display/msm: move common DPU properties to dpu-common.yaml Move properties common to all DPU DT nodes to the dpu-common.yaml. Note, this removes description of individual DPU port@ nodes. However such definitions add no additional value. The reg values do not correspond to hardware INTF indices. The driver discovers and binds these ports not paying any care for the order of these items. Thus just leave the reference to graph.yaml#/properties/ports and the description. Reviewed-by: Rob Herring Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/508384/ Link: https://lore.kernel.org/r/20221024164225.3236654-5-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov --- .../bindings/display/msm/dpu-common.yaml | 52 ++++++++++++++++++++++ .../bindings/display/msm/dpu-msm8998.yaml | 44 +----------------- .../bindings/display/msm/dpu-qcm2290.yaml | 39 +--------------- .../bindings/display/msm/dpu-sc7180.yaml | 43 +----------------- .../bindings/display/msm/dpu-sc7280.yaml | 43 +----------------- .../bindings/display/msm/dpu-sdm845.yaml | 44 +----------------- 6 files changed, 62 insertions(+), 203 deletions(-) create mode 100644 Documentation/devicetree/bindings/display/msm/dpu-common.yaml diff --git a/Documentation/devicetree/bindings/display/msm/dpu-common.yaml b/Documentation/devicetree/bindings/display/msm/dpu-common.yaml new file mode 100644 index 000000000000..8ffbc30c6b7f --- /dev/null +++ b/Documentation/devicetree/bindings/display/msm/dpu-common.yaml @@ -0,0 +1,52 @@ +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/msm/dpu-common.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Display DPU common properties + +maintainers: + - Krishna Manikandan + - Dmitry Baryshkov + - Rob Clark + +description: | + Common properties for QCom DPU display controller. + +properties: + interrupts: + maxItems: 1 + + power-domains: + maxItems: 1 + + operating-points-v2: true + opp-table: + type: object + + ports: + $ref: /schemas/graph.yaml#/properties/ports + description: | + Contains the list of output ports from DPU device. These ports + connect to interfaces that are external to the DPU hardware, + such as DSI, DP etc. + + patternProperties: + "^port@[0-9a-f]+$": + $ref: /schemas/graph.yaml#/properties/port + + # at least one port is required + required: + - port@0 + +required: + - compatible + - reg + - reg-names + - clocks + - interrupts + - power-domains + - operating-points-v2 + - ports + +additionalProperties: true diff --git a/Documentation/devicetree/bindings/display/msm/dpu-msm8998.yaml b/Documentation/devicetree/bindings/display/msm/dpu-msm8998.yaml index 253665c693e6..200eeace1c71 100644 --- a/Documentation/devicetree/bindings/display/msm/dpu-msm8998.yaml +++ b/Documentation/devicetree/bindings/display/msm/dpu-msm8998.yaml @@ -61,8 +61,9 @@ properties: patternProperties: "^display-controller@[0-9a-f]+$": type: object + $ref: /schemas/display/msm/dpu-common.yaml# description: Node containing the properties of DPU. - additionalProperties: false + unevaluatedProperties: false properties: compatible: @@ -99,47 +100,6 @@ patternProperties: - const: core - const: vsync - interrupts: - maxItems: 1 - - power-domains: - maxItems: 1 - - operating-points-v2: true - opp-table: - type: object - - ports: - $ref: /schemas/graph.yaml#/properties/ports - description: | - Contains the list of output ports from DPU device. These ports - connect to interfaces that are external to the DPU hardware, - such as DSI, DP etc. Each output port contains an endpoint that - describes how it is connected to an external interface. - - properties: - port@0: - $ref: /schemas/graph.yaml#/properties/port - description: DPU_INTF1 (DSI1) - - port@1: - $ref: /schemas/graph.yaml#/properties/port - description: DPU_INTF2 (DSI2) - - required: - - port@0 - - port@1 - - required: - - compatible - - reg - - reg-names - - clocks - - interrupts - - power-domains - - operating-points-v2 - - ports - required: - compatible - reg diff --git a/Documentation/devicetree/bindings/display/msm/dpu-qcm2290.yaml b/Documentation/devicetree/bindings/display/msm/dpu-qcm2290.yaml index c5824e1d2382..d5f1d16b13d3 100644 --- a/Documentation/devicetree/bindings/display/msm/dpu-qcm2290.yaml +++ b/Documentation/devicetree/bindings/display/msm/dpu-qcm2290.yaml @@ -73,8 +73,9 @@ properties: patternProperties: "^display-controller@[0-9a-f]+$": type: object + $ref: /schemas/display/msm/dpu-common.yaml# description: Node containing the properties of DPU. - additionalProperties: false + unevaluatedProperties: false properties: compatible: @@ -107,42 +108,6 @@ patternProperties: - const: lut - const: vsync - interrupts: - maxItems: 1 - - power-domains: - maxItems: 1 - - operating-points-v2: true - opp-table: - type: object - - ports: - $ref: /schemas/graph.yaml#/properties/ports - description: | - Contains the list of output ports from DPU device. These ports - connect to interfaces that are external to the DPU hardware, - such as DSI. Each output port contains an endpoint that - describes how it is connected to an external interface. - - properties: - port@0: - $ref: /schemas/graph.yaml#/properties/port - description: DPU_INTF1 (DSI1) - - required: - - port@0 - - required: - - compatible - - reg - - reg-names - - clocks - - interrupts - - power-domains - - operating-points-v2 - - ports - required: - compatible - reg diff --git a/Documentation/devicetree/bindings/display/msm/dpu-sc7180.yaml b/Documentation/devicetree/bindings/display/msm/dpu-sc7180.yaml index 4890bc25f3fd..2ac10664d79a 100644 --- a/Documentation/devicetree/bindings/display/msm/dpu-sc7180.yaml +++ b/Documentation/devicetree/bindings/display/msm/dpu-sc7180.yaml @@ -72,8 +72,9 @@ properties: patternProperties: "^display-controller@[0-9a-f]+$": type: object + $ref: /schemas/display/msm/dpu-common.yaml# description: Node containing the properties of DPU. - additionalProperties: false + unevaluatedProperties: false properties: compatible: @@ -108,46 +109,6 @@ patternProperties: - const: core - const: vsync - interrupts: - maxItems: 1 - - power-domains: - maxItems: 1 - - operating-points-v2: true - opp-table: - type: object - - ports: - $ref: /schemas/graph.yaml#/properties/ports - description: | - Contains the list of output ports from DPU device. These ports - connect to interfaces that are external to the DPU hardware, - such as DSI, DP etc. Each output port contains an endpoint that - describes how it is connected to an external interface. - - properties: - port@0: - $ref: /schemas/graph.yaml#/properties/port - description: DPU_INTF1 (DSI1) - - port@2: - $ref: /schemas/graph.yaml#/properties/port - description: DPU_INTF0 (DP) - - required: - - port@0 - - required: - - compatible - - reg - - reg-names - - clocks - - interrupts - - power-domains - - operating-points-v2 - - ports - required: - compatible - reg diff --git a/Documentation/devicetree/bindings/display/msm/dpu-sc7280.yaml b/Documentation/devicetree/bindings/display/msm/dpu-sc7280.yaml index 584d646021d5..4ca7bc7f0185 100644 --- a/Documentation/devicetree/bindings/display/msm/dpu-sc7280.yaml +++ b/Documentation/devicetree/bindings/display/msm/dpu-sc7280.yaml @@ -71,8 +71,9 @@ properties: patternProperties: "^display-controller@[0-9a-f]+$": type: object + $ref: /schemas/display/msm/dpu-common.yaml# description: Node containing the properties of DPU. - additionalProperties: false + unevaluatedProperties: false properties: compatible: @@ -106,46 +107,6 @@ patternProperties: - const: core - const: vsync - interrupts: - maxItems: 1 - - power-domains: - maxItems: 1 - - operating-points-v2: true - opp-table: - type: object - - ports: - $ref: /schemas/graph.yaml#/properties/ports - description: | - Contains the list of output ports from DPU device. These ports - connect to interfaces that are external to the DPU hardware, - such as DSI, DP etc. Each output port contains an endpoint that - describes how it is connected to an external interface. - - properties: - port@0: - $ref: /schemas/graph.yaml#/properties/port - description: DPU_INTF1 (DSI) - - port@1: - $ref: /schemas/graph.yaml#/properties/port - description: DPU_INTF5 (EDP) - - required: - - port@0 - - required: - - compatible - - reg - - reg-names - - clocks - - interrupts - - power-domains - - operating-points-v2 - - ports - required: - compatible - reg diff --git a/Documentation/devicetree/bindings/display/msm/dpu-sdm845.yaml b/Documentation/devicetree/bindings/display/msm/dpu-sdm845.yaml index a87deea8e9bc..de193ca11265 100644 --- a/Documentation/devicetree/bindings/display/msm/dpu-sdm845.yaml +++ b/Documentation/devicetree/bindings/display/msm/dpu-sdm845.yaml @@ -74,8 +74,9 @@ properties: patternProperties: "^display-controller@[0-9a-f]+$": type: object + $ref: /schemas/display/msm/dpu-common.yaml# description: Node containing the properties of DPU. - additionalProperties: false + unevaluatedProperties: false properties: compatible: @@ -108,47 +109,6 @@ patternProperties: - const: core - const: vsync - interrupts: - maxItems: 1 - - power-domains: - maxItems: 1 - - operating-points-v2: true - opp-table: - type: object - - ports: - $ref: /schemas/graph.yaml#/properties/ports - description: | - Contains the list of output ports from DPU device. These ports - connect to interfaces that are external to the DPU hardware, - such as DSI, DP etc. Each output port contains an endpoint that - describes how it is connected to an external interface. - - properties: - port@0: - $ref: /schemas/graph.yaml#/properties/port - description: DPU_INTF1 (DSI1) - - port@1: - $ref: /schemas/graph.yaml#/properties/port - description: DPU_INTF2 (DSI2) - - required: - - port@0 - - port@1 - - required: - - compatible - - reg - - reg-names - - clocks - - interrupts - - power-domains - - operating-points-v2 - - ports - required: - compatible - reg -- cgit From 5a5c7b35f00f734b38f320ab95b0e571c1874e09 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 24 Oct 2022 19:42:18 +0300 Subject: dt-bindings: display/msm: move common MDSS properties to mdss-common.yaml Move properties common to all MDSS DT nodes to the mdss-common.yaml. This extends qcom,msm8998-mdss schema to allow interconnect nodes, which will be added later, once msm8998 gains interconnect support. Reviewed-by: Rob Herring Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/508385/ Link: https://lore.kernel.org/r/20221024164225.3236654-6-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov --- .../bindings/display/msm/dpu-msm8998.yaml | 41 ++--------- .../bindings/display/msm/dpu-qcm2290.yaml | 51 ++----------- .../bindings/display/msm/dpu-sc7180.yaml | 50 ++----------- .../bindings/display/msm/dpu-sc7280.yaml | 50 ++----------- .../bindings/display/msm/dpu-sdm845.yaml | 54 ++------------ .../bindings/display/msm/mdss-common.yaml | 83 ++++++++++++++++++++++ 6 files changed, 111 insertions(+), 218 deletions(-) create mode 100644 Documentation/devicetree/bindings/display/msm/mdss-common.yaml diff --git a/Documentation/devicetree/bindings/display/msm/dpu-msm8998.yaml b/Documentation/devicetree/bindings/display/msm/dpu-msm8998.yaml index 200eeace1c71..67791dbc3b5d 100644 --- a/Documentation/devicetree/bindings/display/msm/dpu-msm8998.yaml +++ b/Documentation/devicetree/bindings/display/msm/dpu-msm8998.yaml @@ -14,20 +14,13 @@ description: | sub-blocks like DPU display controller, DSI and DP interfaces etc. Device tree bindings of MDSS and DPU are mentioned for MSM8998 target. +$ref: /schemas/display/msm/mdss-common.yaml# + properties: compatible: items: - const: qcom,msm8998-mdss - reg: - maxItems: 1 - - reg-names: - const: mdss - - power-domains: - maxItems: 1 - clocks: items: - description: Display AHB clock @@ -40,23 +33,8 @@ properties: - const: bus - const: core - interrupts: - maxItems: 1 - - interrupt-controller: true - - "#address-cells": true - - "#size-cells": true - - "#interrupt-cells": - const: 1 - iommus: - items: - - description: Phandle to apps_smmu node with SID mask for Hard-Fail port0 - - ranges: true + maxItems: 1 patternProperties: "^display-controller@[0-9a-f]+$": @@ -100,18 +78,7 @@ patternProperties: - const: core - const: vsync -required: - - compatible - - reg - - reg-names - - power-domains - - clocks - - interrupts - - interrupt-controller - - iommus - - ranges - -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/display/msm/dpu-qcm2290.yaml b/Documentation/devicetree/bindings/display/msm/dpu-qcm2290.yaml index d5f1d16b13d3..42e676bdda4e 100644 --- a/Documentation/devicetree/bindings/display/msm/dpu-qcm2290.yaml +++ b/Documentation/devicetree/bindings/display/msm/dpu-qcm2290.yaml @@ -14,20 +14,13 @@ description: | sub-blocks like DPU display controller and DSI. Device tree bindings of MDSS and DPU are mentioned for QCM2290 target. +$ref: /schemas/display/msm/mdss-common.yaml# + properties: compatible: items: - const: qcom,qcm2290-mdss - reg: - maxItems: 1 - - reg-names: - const: mdss - - power-domains: - maxItems: 1 - clocks: items: - description: Display AHB clock from gcc @@ -40,35 +33,14 @@ properties: - const: bus - const: core - interrupts: - maxItems: 1 - - interrupt-controller: true - - "#address-cells": true - - "#size-cells": true - - "#interrupt-cells": - const: 1 - iommus: - items: - - description: Phandle to apps_smmu node with SID mask for Hard-Fail port0 - - description: Phandle to apps_smmu node with SID mask for Hard-Fail port1 - - ranges: true + maxItems: 2 interconnects: - items: - - description: Interconnect path specifying the port ids for data bus + maxItems: 1 interconnect-names: - const: mdp0-mem - - resets: - items: - - description: MDSS_CORE reset + maxItems: 1 patternProperties: "^display-controller@[0-9a-f]+$": @@ -108,18 +80,7 @@ patternProperties: - const: lut - const: vsync -required: - - compatible - - reg - - reg-names - - power-domains - - clocks - - interrupts - - interrupt-controller - - iommus - - ranges - -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/display/msm/dpu-sc7180.yaml b/Documentation/devicetree/bindings/display/msm/dpu-sc7180.yaml index 2ac10664d79a..99d6bbd45faf 100644 --- a/Documentation/devicetree/bindings/display/msm/dpu-sc7180.yaml +++ b/Documentation/devicetree/bindings/display/msm/dpu-sc7180.yaml @@ -14,20 +14,13 @@ description: | sub-blocks like DPU display controller, DSI and DP interfaces etc. Device tree bindings of MDSS and DPU are mentioned for SC7180 target. +$ref: /schemas/display/msm/mdss-common.yaml# + properties: compatible: items: - const: qcom,sc7180-mdss - reg: - maxItems: 1 - - reg-names: - const: mdss - - power-domains: - maxItems: 1 - clocks: items: - description: Display AHB clock from gcc @@ -40,34 +33,14 @@ properties: - const: ahb - const: core - interrupts: - maxItems: 1 - - interrupt-controller: true - - "#address-cells": true - - "#size-cells": true - - "#interrupt-cells": - const: 1 - iommus: - items: - - description: Phandle to apps_smmu node with SID mask for Hard-Fail port0 - - ranges: true + maxItems: 1 interconnects: - items: - - description: Interconnect path specifying the port ids for data bus + maxItems: 1 interconnect-names: - const: mdp0-mem - - resets: - items: - - description: MDSS_CORE reset + maxItems: 1 patternProperties: "^display-controller@[0-9a-f]+$": @@ -109,18 +82,7 @@ patternProperties: - const: core - const: vsync -required: - - compatible - - reg - - reg-names - - power-domains - - clocks - - interrupts - - interrupt-controller - - iommus - - ranges - -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/display/msm/dpu-sc7280.yaml b/Documentation/devicetree/bindings/display/msm/dpu-sc7280.yaml index 4ca7bc7f0185..01ff88c06c51 100644 --- a/Documentation/devicetree/bindings/display/msm/dpu-sc7280.yaml +++ b/Documentation/devicetree/bindings/display/msm/dpu-sc7280.yaml @@ -14,19 +14,12 @@ description: | sub-blocks like DPU display controller, DSI and DP interfaces etc. Device tree bindings of MDSS and DPU are mentioned for SC7280. +$ref: /schemas/display/msm/mdss-common.yaml# + properties: compatible: const: qcom,sc7280-mdss - reg: - maxItems: 1 - - reg-names: - const: mdss - - power-domains: - maxItems: 1 - clocks: items: - description: Display AHB clock from gcc @@ -39,34 +32,14 @@ properties: - const: ahb - const: core - interrupts: - maxItems: 1 - - interrupt-controller: true - - "#address-cells": true - - "#size-cells": true - - "#interrupt-cells": - const: 1 - iommus: - items: - - description: Phandle to apps_smmu node with SID mask for Hard-Fail port0 - - ranges: true + maxItems: 1 interconnects: - items: - - description: Interconnect path specifying the port ids for data bus + maxItems: 1 interconnect-names: - const: mdp0-mem - - resets: - items: - - description: MDSS_CORE reset + maxItems: 1 patternProperties: "^display-controller@[0-9a-f]+$": @@ -107,18 +80,7 @@ patternProperties: - const: core - const: vsync -required: - - compatible - - reg - - reg-names - - power-domains - - clocks - - interrupts - - interrupt-controller - - iommus - - ranges - -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/display/msm/dpu-sdm845.yaml b/Documentation/devicetree/bindings/display/msm/dpu-sdm845.yaml index de193ca11265..ae649bb6aa81 100644 --- a/Documentation/devicetree/bindings/display/msm/dpu-sdm845.yaml +++ b/Documentation/devicetree/bindings/display/msm/dpu-sdm845.yaml @@ -14,20 +14,13 @@ description: | sub-blocks like DPU display controller, DSI and DP interfaces etc. Device tree bindings of MDSS and DPU are mentioned for SDM845 target. +$ref: /schemas/display/msm/mdss-common.yaml# + properties: compatible: items: - const: qcom,sdm845-mdss - reg: - maxItems: 1 - - reg-names: - const: mdss - - power-domains: - maxItems: 1 - clocks: items: - description: Display AHB clock from gcc @@ -38,38 +31,14 @@ properties: - const: iface - const: core - interrupts: - maxItems: 1 - - interrupt-controller: true - - "#address-cells": true - - "#size-cells": true - - "#interrupt-cells": - const: 1 - iommus: - items: - - description: Phandle to apps_smmu node with SID mask for Hard-Fail port0 - - description: Phandle to apps_smmu node with SID mask for Hard-Fail port1 - - ranges: true + maxItems: 2 interconnects: - items: - - description: Interconnect path from mdp0 port to the data bus - - description: Interconnect path from mdp1 port to the data bus + maxItems: 2 interconnect-names: - items: - - const: mdp0-mem - - const: mdp1-mem - - resets: - items: - - description: MDSS_CORE reset + maxItems: 2 patternProperties: "^display-controller@[0-9a-f]+$": @@ -109,18 +78,7 @@ patternProperties: - const: core - const: vsync -required: - - compatible - - reg - - reg-names - - power-domains - - clocks - - interrupts - - interrupt-controller - - iommus - - ranges - -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/display/msm/mdss-common.yaml b/Documentation/devicetree/bindings/display/msm/mdss-common.yaml new file mode 100644 index 000000000000..2a476bd0215e --- /dev/null +++ b/Documentation/devicetree/bindings/display/msm/mdss-common.yaml @@ -0,0 +1,83 @@ +# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/msm/mdss-common.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Display MDSS common properties + +maintainers: + - Krishna Manikandan + - Dmitry Baryshkov + - Rob Clark + +description: + Device tree bindings for MSM Mobile Display Subsystem(MDSS) that encapsulates + sub-blocks like DPU display controller, DSI and DP interfaces etc. + +properties: + reg: + maxItems: 1 + + reg-names: + const: mdss + + power-domains: + maxItems: 1 + + clocks: + minItems: 2 + maxItems: 3 + + clock-names: + minItems: 2 + maxItems: 3 + + interrupts: + maxItems: 1 + + interrupt-controller: true + + "#address-cells": true + + "#size-cells": true + + "#interrupt-cells": + const: 1 + + iommus: + minItems: 1 + items: + - description: Phandle to apps_smmu node with SID mask for Hard-Fail port0 + - description: Phandle to apps_smmu node with SID mask for Hard-Fail port1 + + ranges: true + + interconnects: + minItems: 1 + items: + - description: Interconnect path from mdp0 (or a single mdp) port to the data bus + - description: Interconnect path from mdp1 port to the data bus + + interconnect-names: + minItems: 1 + items: + - const: mdp0-mem + - const: mdp1-mem + + resets: + items: + - description: MDSS_CORE reset + +required: + - compatible + - reg + - reg-names + - power-domains + - clocks + - interrupts + - interrupt-controller + - iommus + - ranges + +additionalProperties: true -- cgit From aba04b0db9154125b5b328e9435378c7ed332969 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 24 Oct 2022 19:42:19 +0300 Subject: dt-bindings: display/msm: split dpu-sc7180 into DPU and MDSS parts In order to make the schema more readable, split dpu-sc7180 into the DPU and MDSS parts, each one describing just a single device binding. Reviewed-by: Rob Herring Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/508386/ Link: https://lore.kernel.org/r/20221024164225.3236654-7-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov --- .../bindings/display/msm/dpu-sc7180.yaml | 158 --------------------- .../bindings/display/msm/qcom,sc7180-dpu.yaml | 95 +++++++++++++ .../bindings/display/msm/qcom,sc7180-mdss.yaml | 125 ++++++++++++++++ 3 files changed, 220 insertions(+), 158 deletions(-) delete mode 100644 Documentation/devicetree/bindings/display/msm/dpu-sc7180.yaml create mode 100644 Documentation/devicetree/bindings/display/msm/qcom,sc7180-dpu.yaml create mode 100644 Documentation/devicetree/bindings/display/msm/qcom,sc7180-mdss.yaml diff --git a/Documentation/devicetree/bindings/display/msm/dpu-sc7180.yaml b/Documentation/devicetree/bindings/display/msm/dpu-sc7180.yaml deleted file mode 100644 index 99d6bbd45faf..000000000000 --- a/Documentation/devicetree/bindings/display/msm/dpu-sc7180.yaml +++ /dev/null @@ -1,158 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/display/msm/dpu-sc7180.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Qualcomm Display DPU dt properties for SC7180 target - -maintainers: - - Krishna Manikandan - -description: | - Device tree bindings for MSM Mobile Display Subsystem(MDSS) that encapsulates - sub-blocks like DPU display controller, DSI and DP interfaces etc. Device tree - bindings of MDSS and DPU are mentioned for SC7180 target. - -$ref: /schemas/display/msm/mdss-common.yaml# - -properties: - compatible: - items: - - const: qcom,sc7180-mdss - - clocks: - items: - - description: Display AHB clock from gcc - - description: Display AHB clock from dispcc - - description: Display core clock - - clock-names: - items: - - const: iface - - const: ahb - - const: core - - iommus: - maxItems: 1 - - interconnects: - maxItems: 1 - - interconnect-names: - maxItems: 1 - -patternProperties: - "^display-controller@[0-9a-f]+$": - type: object - $ref: /schemas/display/msm/dpu-common.yaml# - description: Node containing the properties of DPU. - unevaluatedProperties: false - - properties: - compatible: - items: - - const: qcom,sc7180-dpu - - reg: - items: - - description: Address offset and size for mdp register set - - description: Address offset and size for vbif register set - - reg-names: - items: - - const: mdp - - const: vbif - - clocks: - items: - - description: Display hf axi clock - - description: Display ahb clock - - description: Display rotator clock - - description: Display lut clock - - description: Display core clock - - description: Display vsync clock - - clock-names: - items: - - const: bus - - const: iface - - const: rot - - const: lut - - const: core - - const: vsync - -unevaluatedProperties: false - -examples: - - | - #include - #include - #include - #include - #include - - display-subsystem@ae00000 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "qcom,sc7180-mdss"; - reg = <0xae00000 0x1000>; - reg-names = "mdss"; - power-domains = <&dispcc MDSS_GDSC>; - clocks = <&gcc GCC_DISP_AHB_CLK>, - <&dispcc DISP_CC_MDSS_AHB_CLK>, - <&dispcc DISP_CC_MDSS_MDP_CLK>; - clock-names = "iface", "ahb", "core"; - - interrupts = ; - interrupt-controller; - #interrupt-cells = <1>; - - interconnects = <&mmss_noc MASTER_MDP0 &mc_virt SLAVE_EBI1>; - interconnect-names = "mdp0-mem"; - - iommus = <&apps_smmu 0x800 0x2>; - ranges; - - display-controller@ae01000 { - compatible = "qcom,sc7180-dpu"; - reg = <0x0ae01000 0x8f000>, - <0x0aeb0000 0x2008>; - - reg-names = "mdp", "vbif"; - - clocks = <&gcc GCC_DISP_HF_AXI_CLK>, - <&dispcc DISP_CC_MDSS_AHB_CLK>, - <&dispcc DISP_CC_MDSS_ROT_CLK>, - <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>, - <&dispcc DISP_CC_MDSS_MDP_CLK>, - <&dispcc DISP_CC_MDSS_VSYNC_CLK>; - clock-names = "bus", "iface", "rot", "lut", "core", - "vsync"; - - interrupt-parent = <&mdss>; - interrupts = <0>; - power-domains = <&rpmhpd SC7180_CX>; - operating-points-v2 = <&mdp_opp_table>; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - dpu_intf1_out: endpoint { - remote-endpoint = <&dsi0_in>; - }; - }; - - port@2 { - reg = <2>; - dpu_intf0_out: endpoint { - remote-endpoint = <&dp_in>; - }; - }; - }; - }; - }; -... diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sc7180-dpu.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sc7180-dpu.yaml new file mode 100644 index 000000000000..bd590a6b5b96 --- /dev/null +++ b/Documentation/devicetree/bindings/display/msm/qcom,sc7180-dpu.yaml @@ -0,0 +1,95 @@ +# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/msm/qcom,sc7180-dpu.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Display DPU dt properties for SC7180 target + +maintainers: + - Krishna Manikandan + +$ref: /schemas/display/msm/dpu-common.yaml# + +properties: + compatible: + items: + - const: qcom,sc7180-dpu + + reg: + items: + - description: Address offset and size for mdp register set + - description: Address offset and size for vbif register set + + reg-names: + items: + - const: mdp + - const: vbif + + clocks: + items: + - description: Display hf axi clock + - description: Display ahb clock + - description: Display rotator clock + - description: Display lut clock + - description: Display core clock + - description: Display vsync clock + + clock-names: + items: + - const: bus + - const: iface + - const: rot + - const: lut + - const: core + - const: vsync + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + + display-controller@ae01000 { + compatible = "qcom,sc7180-dpu"; + reg = <0x0ae01000 0x8f000>, + <0x0aeb0000 0x2008>; + + reg-names = "mdp", "vbif"; + + clocks = <&gcc GCC_DISP_HF_AXI_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_ROT_CLK>, + <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>, + <&dispcc DISP_CC_MDSS_VSYNC_CLK>; + clock-names = "bus", "iface", "rot", "lut", "core", + "vsync"; + + interrupt-parent = <&mdss>; + interrupts = <0>; + power-domains = <&rpmhpd SC7180_CX>; + operating-points-v2 = <&mdp_opp_table>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; + + port@2 { + reg = <2>; + endpoint { + remote-endpoint = <&dp_in>; + }; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sc7180-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sc7180-mdss.yaml new file mode 100644 index 000000000000..103cfd60c61b --- /dev/null +++ b/Documentation/devicetree/bindings/display/msm/qcom,sc7180-mdss.yaml @@ -0,0 +1,125 @@ +# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/msm/qcom,sc7180-mdss.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm SC7180 Display MDSS + +maintainers: + - Krishna Manikandan + +description: + Device tree bindings for MSM Mobile Display Subsystem(MDSS) that encapsulates + sub-blocks like DPU display controller, DSI and DP interfaces etc. Device tree + bindings of MDSS are mentioned for SC7180 target. + +$ref: /schemas/display/msm/mdss-common.yaml# + +properties: + compatible: + items: + - const: qcom,sc7180-mdss + + clocks: + items: + - description: Display AHB clock from gcc + - description: Display AHB clock from dispcc + - description: Display core clock + + clock-names: + items: + - const: iface + - const: ahb + - const: core + + iommus: + maxItems: 1 + + interconnects: + maxItems: 1 + + interconnect-names: + maxItems: 1 + +patternProperties: + "^display-controller@[0-9a-f]+$": + type: object + properties: + compatible: + const: qcom,sc7180-dpu + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + #include + #include + + display-subsystem@ae00000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "qcom,sc7180-mdss"; + reg = <0xae00000 0x1000>; + reg-names = "mdss"; + power-domains = <&dispcc MDSS_GDSC>; + clocks = <&gcc GCC_DISP_AHB_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>; + clock-names = "iface", "ahb", "core"; + + interrupts = ; + interrupt-controller; + #interrupt-cells = <1>; + + interconnects = <&mmss_noc MASTER_MDP0 &mc_virt SLAVE_EBI1>; + interconnect-names = "mdp0-mem"; + + iommus = <&apps_smmu 0x800 0x2>; + ranges; + + display-controller@ae01000 { + compatible = "qcom,sc7180-dpu"; + reg = <0x0ae01000 0x8f000>, + <0x0aeb0000 0x2008>; + + reg-names = "mdp", "vbif"; + + clocks = <&gcc GCC_DISP_HF_AXI_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_ROT_CLK>, + <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>, + <&dispcc DISP_CC_MDSS_VSYNC_CLK>; + clock-names = "bus", "iface", "rot", "lut", "core", + "vsync"; + + interrupt-parent = <&mdss>; + interrupts = <0>; + power-domains = <&rpmhpd SC7180_CX>; + operating-points-v2 = <&mdp_opp_table>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dpu_intf1_out: endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; + + port@2 { + reg = <2>; + dpu_intf0_out: endpoint { + remote-endpoint = <&dp_in>; + }; + }; + }; + }; + }; +... -- cgit From 2c44a9936636b8fb33aff9ea6ee9da5b372f8dfb Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 24 Oct 2022 19:42:20 +0300 Subject: dt-bindings: display/msm: split dpu-sc7280 into DPU and MDSS parts In order to make the schema more readable, split dpu-sc7280 into the DPU and MDSS parts, each one describing just a single device binding. Reviewed-by: Rob Herring Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/508387/ Link: https://lore.kernel.org/r/20221024164225.3236654-8-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov --- .../bindings/display/msm/dpu-sc7280.yaml | 162 --------------------- .../bindings/display/msm/qcom,sc7280-dpu.yaml | 98 +++++++++++++ .../bindings/display/msm/qcom,sc7280-mdss.yaml | 130 +++++++++++++++++ 3 files changed, 228 insertions(+), 162 deletions(-) delete mode 100644 Documentation/devicetree/bindings/display/msm/dpu-sc7280.yaml create mode 100644 Documentation/devicetree/bindings/display/msm/qcom,sc7280-dpu.yaml create mode 100644 Documentation/devicetree/bindings/display/msm/qcom,sc7280-mdss.yaml diff --git a/Documentation/devicetree/bindings/display/msm/dpu-sc7280.yaml b/Documentation/devicetree/bindings/display/msm/dpu-sc7280.yaml deleted file mode 100644 index 01ff88c06c51..000000000000 --- a/Documentation/devicetree/bindings/display/msm/dpu-sc7280.yaml +++ /dev/null @@ -1,162 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/display/msm/dpu-sc7280.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Qualcomm Display DPU dt properties for SC7280 - -maintainers: - - Krishna Manikandan - -description: | - Device tree bindings for MSM Mobile Display Subsystem (MDSS) that encapsulates - sub-blocks like DPU display controller, DSI and DP interfaces etc. Device tree - bindings of MDSS and DPU are mentioned for SC7280. - -$ref: /schemas/display/msm/mdss-common.yaml# - -properties: - compatible: - const: qcom,sc7280-mdss - - clocks: - items: - - description: Display AHB clock from gcc - - description: Display AHB clock from dispcc - - description: Display core clock - - clock-names: - items: - - const: iface - - const: ahb - - const: core - - iommus: - maxItems: 1 - - interconnects: - maxItems: 1 - - interconnect-names: - maxItems: 1 - -patternProperties: - "^display-controller@[0-9a-f]+$": - type: object - $ref: /schemas/display/msm/dpu-common.yaml# - description: Node containing the properties of DPU. - unevaluatedProperties: false - - properties: - compatible: - const: qcom,sc7280-dpu - - reg: - items: - - description: Address offset and size for mdp register set - - description: Address offset and size for vbif register set - - reg-names: - items: - - const: mdp - - const: vbif - - clocks: - items: - - description: Display hf axi clock - - description: Display sf axi clock - - description: Display ahb clock - - description: Display lut clock - - description: Display core clock - - description: Display vsync clock - - clock-names: - items: - - const: bus - - const: nrt_bus - - const: iface - - const: lut - - const: core - - const: vsync - -unevaluatedProperties: false - -examples: - - | - #include - #include - #include - #include - #include - - display-subsystem@ae00000 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "qcom,sc7280-mdss"; - reg = <0xae00000 0x1000>; - reg-names = "mdss"; - power-domains = <&dispcc DISP_CC_MDSS_CORE_GDSC>; - clocks = <&gcc GCC_DISP_AHB_CLK>, - <&dispcc DISP_CC_MDSS_AHB_CLK>, - <&dispcc DISP_CC_MDSS_MDP_CLK>; - clock-names = "iface", - "ahb", - "core"; - - interrupts = ; - interrupt-controller; - #interrupt-cells = <1>; - - interconnects = <&mmss_noc MASTER_MDP0 &mc_virt SLAVE_EBI1>; - interconnect-names = "mdp0-mem"; - - iommus = <&apps_smmu 0x900 0x402>; - ranges; - - display-controller@ae01000 { - compatible = "qcom,sc7280-dpu"; - reg = <0x0ae01000 0x8f000>, - <0x0aeb0000 0x2008>; - - reg-names = "mdp", "vbif"; - - clocks = <&gcc GCC_DISP_HF_AXI_CLK>, - <&gcc GCC_DISP_SF_AXI_CLK>, - <&dispcc DISP_CC_MDSS_AHB_CLK>, - <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>, - <&dispcc DISP_CC_MDSS_MDP_CLK>, - <&dispcc DISP_CC_MDSS_VSYNC_CLK>; - clock-names = "bus", - "nrt_bus", - "iface", - "lut", - "core", - "vsync"; - - interrupt-parent = <&mdss>; - interrupts = <0>; - power-domains = <&rpmhpd SC7280_CX>; - operating-points-v2 = <&mdp_opp_table>; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - dpu_intf1_out: endpoint { - remote-endpoint = <&dsi0_in>; - }; - }; - - port@1 { - reg = <1>; - dpu_intf5_out: endpoint { - remote-endpoint = <&edp_in>; - }; - }; - }; - }; - }; -... diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sc7280-dpu.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sc7280-dpu.yaml new file mode 100644 index 000000000000..924059b387b6 --- /dev/null +++ b/Documentation/devicetree/bindings/display/msm/qcom,sc7280-dpu.yaml @@ -0,0 +1,98 @@ +# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/msm/qcom,sc7280-dpu.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Display DPU dt properties for SC7280 + +maintainers: + - Krishna Manikandan + +$ref: /schemas/display/msm/dpu-common.yaml# + +properties: + compatible: + const: qcom,sc7280-dpu + + reg: + items: + - description: Address offset and size for mdp register set + - description: Address offset and size for vbif register set + + reg-names: + items: + - const: mdp + - const: vbif + + clocks: + items: + - description: Display hf axi clock + - description: Display sf axi clock + - description: Display ahb clock + - description: Display lut clock + - description: Display core clock + - description: Display vsync clock + + clock-names: + items: + - const: bus + - const: nrt_bus + - const: iface + - const: lut + - const: core + - const: vsync + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + + display-controller@ae01000 { + compatible = "qcom,sc7280-dpu"; + reg = <0x0ae01000 0x8f000>, + <0x0aeb0000 0x2008>; + + reg-names = "mdp", "vbif"; + + clocks = <&gcc GCC_DISP_HF_AXI_CLK>, + <&gcc GCC_DISP_SF_AXI_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>, + <&dispcc DISP_CC_MDSS_VSYNC_CLK>; + clock-names = "bus", + "nrt_bus", + "iface", + "lut", + "core", + "vsync"; + + interrupt-parent = <&mdss>; + interrupts = <0>; + power-domains = <&rpmhpd SC7280_CX>; + operating-points-v2 = <&mdp_opp_table>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; + + port@1 { + reg = <1>; + endpoint { + remote-endpoint = <&edp_in>; + }; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sc7280-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sc7280-mdss.yaml new file mode 100644 index 000000000000..d4ac2d5d13fb --- /dev/null +++ b/Documentation/devicetree/bindings/display/msm/qcom,sc7280-mdss.yaml @@ -0,0 +1,130 @@ +# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/msm/qcom,sc7280-mdss.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm SC7280 Display MDSS + +maintainers: + - Krishna Manikandan + +description: + Device tree bindings for MSM Mobile Display Subsystem (MDSS) that encapsulates + sub-blocks like DPU display controller, DSI and DP interfaces etc. Device tree + bindings of MDSS are mentioned for SC7280. + +$ref: /schemas/display/msm/mdss-common.yaml# + +properties: + compatible: + const: qcom,sc7280-mdss + + clocks: + items: + - description: Display AHB clock from gcc + - description: Display AHB clock from dispcc + - description: Display core clock + + clock-names: + items: + - const: iface + - const: ahb + - const: core + + iommus: + maxItems: 1 + + interconnects: + maxItems: 1 + + interconnect-names: + maxItems: 1 + +patternProperties: + "^display-controller@[0-9a-f]+$": + type: object + properties: + compatible: + const: qcom,sc7280-dpu + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + #include + #include + + display-subsystem@ae00000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "qcom,sc7280-mdss"; + reg = <0xae00000 0x1000>; + reg-names = "mdss"; + power-domains = <&dispcc DISP_CC_MDSS_CORE_GDSC>; + clocks = <&gcc GCC_DISP_AHB_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>; + clock-names = "iface", + "ahb", + "core"; + + interrupts = ; + interrupt-controller; + #interrupt-cells = <1>; + + interconnects = <&mmss_noc MASTER_MDP0 &mc_virt SLAVE_EBI1>; + interconnect-names = "mdp0-mem"; + + iommus = <&apps_smmu 0x900 0x402>; + ranges; + + display-controller@ae01000 { + compatible = "qcom,sc7280-dpu"; + reg = <0x0ae01000 0x8f000>, + <0x0aeb0000 0x2008>; + + reg-names = "mdp", "vbif"; + + clocks = <&gcc GCC_DISP_HF_AXI_CLK>, + <&gcc GCC_DISP_SF_AXI_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>, + <&dispcc DISP_CC_MDSS_VSYNC_CLK>; + clock-names = "bus", + "nrt_bus", + "iface", + "lut", + "core", + "vsync"; + + interrupt-parent = <&mdss>; + interrupts = <0>; + power-domains = <&rpmhpd SC7280_CX>; + operating-points-v2 = <&mdp_opp_table>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dpu_intf1_out: endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; + + port@1 { + reg = <1>; + dpu_intf5_out: endpoint { + remote-endpoint = <&edp_in>; + }; + }; + }; + }; + }; +... -- cgit From 2abfd6a2873f1f7ad9e309fa2735fe096adc9d67 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 24 Oct 2022 19:42:21 +0300 Subject: dt-bindings: display/msm: split dpu-sdm845 into DPU and MDSS parts In order to make the schema more readable, split dpu-sdm845 into the DPU and MDSS parts, each one describing just a single device binding. Reviewed-by: Rob Herring Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/508382/ Link: https://lore.kernel.org/r/20221024164225.3236654-9-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov --- .../bindings/display/msm/dpu-sdm845.yaml | 148 --------------------- .../bindings/display/msm/qcom,sdm845-dpu.yaml | 90 +++++++++++++ .../bindings/display/msm/qcom,sdm845-mdss.yaml | 117 ++++++++++++++++ 3 files changed, 207 insertions(+), 148 deletions(-) delete mode 100644 Documentation/devicetree/bindings/display/msm/dpu-sdm845.yaml create mode 100644 Documentation/devicetree/bindings/display/msm/qcom,sdm845-dpu.yaml create mode 100644 Documentation/devicetree/bindings/display/msm/qcom,sdm845-mdss.yaml diff --git a/Documentation/devicetree/bindings/display/msm/dpu-sdm845.yaml b/Documentation/devicetree/bindings/display/msm/dpu-sdm845.yaml deleted file mode 100644 index ae649bb6aa81..000000000000 --- a/Documentation/devicetree/bindings/display/msm/dpu-sdm845.yaml +++ /dev/null @@ -1,148 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/display/msm/dpu-sdm845.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Qualcomm Display DPU dt properties for SDM845 target - -maintainers: - - Krishna Manikandan - -description: | - Device tree bindings for MSM Mobile Display Subsystem(MDSS) that encapsulates - sub-blocks like DPU display controller, DSI and DP interfaces etc. Device tree - bindings of MDSS and DPU are mentioned for SDM845 target. - -$ref: /schemas/display/msm/mdss-common.yaml# - -properties: - compatible: - items: - - const: qcom,sdm845-mdss - - clocks: - items: - - description: Display AHB clock from gcc - - description: Display core clock - - clock-names: - items: - - const: iface - - const: core - - iommus: - maxItems: 2 - - interconnects: - maxItems: 2 - - interconnect-names: - maxItems: 2 - -patternProperties: - "^display-controller@[0-9a-f]+$": - type: object - $ref: /schemas/display/msm/dpu-common.yaml# - description: Node containing the properties of DPU. - unevaluatedProperties: false - - properties: - compatible: - items: - - const: qcom,sdm845-dpu - - reg: - items: - - description: Address offset and size for mdp register set - - description: Address offset and size for vbif register set - - reg-names: - items: - - const: mdp - - const: vbif - - clocks: - items: - - description: Display GCC bus clock - - description: Display ahb clock - - description: Display axi clock - - description: Display core clock - - description: Display vsync clock - - clock-names: - items: - - const: gcc-bus - - const: iface - - const: bus - - const: core - - const: vsync - -unevaluatedProperties: false - -examples: - - | - #include - #include - #include - #include - - display-subsystem@ae00000 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "qcom,sdm845-mdss"; - reg = <0x0ae00000 0x1000>; - reg-names = "mdss"; - power-domains = <&dispcc MDSS_GDSC>; - - clocks = <&gcc GCC_DISP_AHB_CLK>, - <&dispcc DISP_CC_MDSS_MDP_CLK>; - clock-names = "iface", "core"; - - interrupts = ; - interrupt-controller; - #interrupt-cells = <1>; - - iommus = <&apps_smmu 0x880 0x8>, - <&apps_smmu 0xc80 0x8>; - ranges; - - display-controller@ae01000 { - compatible = "qcom,sdm845-dpu"; - reg = <0x0ae01000 0x8f000>, - <0x0aeb0000 0x2008>; - reg-names = "mdp", "vbif"; - - clocks = <&gcc GCC_DISP_AXI_CLK>, - <&dispcc DISP_CC_MDSS_AHB_CLK>, - <&dispcc DISP_CC_MDSS_AXI_CLK>, - <&dispcc DISP_CC_MDSS_MDP_CLK>, - <&dispcc DISP_CC_MDSS_VSYNC_CLK>; - clock-names = "gcc-bus", "iface", "bus", "core", "vsync"; - - interrupt-parent = <&mdss>; - interrupts = <0>; - power-domains = <&rpmhpd SDM845_CX>; - operating-points-v2 = <&mdp_opp_table>; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - dpu_intf1_out: endpoint { - remote-endpoint = <&dsi0_in>; - }; - }; - - port@1 { - reg = <1>; - dpu_intf2_out: endpoint { - remote-endpoint = <&dsi1_in>; - }; - }; - }; - }; - }; -... diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sdm845-dpu.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sdm845-dpu.yaml new file mode 100644 index 000000000000..5719b45f2860 --- /dev/null +++ b/Documentation/devicetree/bindings/display/msm/qcom,sdm845-dpu.yaml @@ -0,0 +1,90 @@ +# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/msm/qcom,sdm845-dpu.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Display DPU dt properties for SDM845 target + +maintainers: + - Krishna Manikandan + +$ref: /schemas/display/msm/dpu-common.yaml# + +properties: + compatible: + items: + - const: qcom,sdm845-dpu + + reg: + items: + - description: Address offset and size for mdp register set + - description: Address offset and size for vbif register set + + reg-names: + items: + - const: mdp + - const: vbif + + clocks: + items: + - description: Display GCC bus clock + - description: Display ahb clock + - description: Display axi clock + - description: Display core clock + - description: Display vsync clock + + clock-names: + items: + - const: gcc-bus + - const: iface + - const: bus + - const: core + - const: vsync + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + + display-controller@ae01000 { + compatible = "qcom,sdm845-dpu"; + reg = <0x0ae01000 0x8f000>, + <0x0aeb0000 0x2008>; + reg-names = "mdp", "vbif"; + + clocks = <&gcc GCC_DISP_AXI_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_AXI_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>, + <&dispcc DISP_CC_MDSS_VSYNC_CLK>; + clock-names = "gcc-bus", "iface", "bus", "core", "vsync"; + + interrupt-parent = <&mdss>; + interrupts = <0>; + power-domains = <&rpmhpd SDM845_CX>; + operating-points-v2 = <&mdp_opp_table>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; + + port@1 { + reg = <1>; + endpoint { + remote-endpoint = <&dsi1_in>; + }; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sdm845-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sdm845-mdss.yaml new file mode 100644 index 000000000000..47fe66f4da54 --- /dev/null +++ b/Documentation/devicetree/bindings/display/msm/qcom,sdm845-mdss.yaml @@ -0,0 +1,117 @@ +# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/msm/qcom,sdm845-mdss.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm SDM845 Display MDSS + +maintainers: + - Krishna Manikandan + +description: + Device tree bindings for MSM Mobile Display Subsystem(MDSS) that encapsulates + sub-blocks like DPU display controller, DSI and DP interfaces etc. Device tree + bindings of MDSS are mentioned for SDM845 target. + +$ref: /schemas/display/msm/mdss-common.yaml# + +properties: + compatible: + items: + - const: qcom,sdm845-mdss + + clocks: + items: + - description: Display AHB clock from gcc + - description: Display core clock + + clock-names: + items: + - const: iface + - const: core + + iommus: + maxItems: 2 + + interconnects: + maxItems: 2 + + interconnect-names: + maxItems: 2 + +patternProperties: + "^display-controller@[0-9a-f]+$": + type: object + properties: + compatible: + const: qcom,sdm845-dpu + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + #include + + display-subsystem@ae00000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "qcom,sdm845-mdss"; + reg = <0x0ae00000 0x1000>; + reg-names = "mdss"; + power-domains = <&dispcc MDSS_GDSC>; + + clocks = <&gcc GCC_DISP_AHB_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>; + clock-names = "iface", "core"; + + interrupts = ; + interrupt-controller; + #interrupt-cells = <1>; + + iommus = <&apps_smmu 0x880 0x8>, + <&apps_smmu 0xc80 0x8>; + ranges; + + display-controller@ae01000 { + compatible = "qcom,sdm845-dpu"; + reg = <0x0ae01000 0x8f000>, + <0x0aeb0000 0x2008>; + reg-names = "mdp", "vbif"; + + clocks = <&gcc GCC_DISP_AXI_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_AXI_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>, + <&dispcc DISP_CC_MDSS_VSYNC_CLK>; + clock-names = "gcc-bus", "iface", "bus", "core", "vsync"; + + interrupt-parent = <&mdss>; + interrupts = <0>; + power-domains = <&rpmhpd SDM845_CX>; + operating-points-v2 = <&mdp_opp_table>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dpu_intf1_out: endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; + + port@1 { + reg = <1>; + dpu_intf2_out: endpoint { + remote-endpoint = <&dsi1_in>; + }; + }; + }; + }; + }; +... -- cgit From 9410872ff04062924d15569b22ceb4e341c1b049 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 24 Oct 2022 19:42:22 +0300 Subject: dt-bindings: display/msm: split dpu-msm8998 into DPU and MDSS parts In order to make the schema more readable, split dpu-msm8998 into the DPU and MDSS parts, each one describing just a single device binding. Reviewed-by: Rob Herring Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/508388/ Link: https://lore.kernel.org/r/20221024164225.3236654-10-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov --- .../bindings/display/msm/dpu-msm8998.yaml | 150 --------------------- .../bindings/display/msm/qcom,msm8998-dpu.yaml | 95 +++++++++++++ .../bindings/display/msm/qcom,msm8998-mdss.yaml | 115 ++++++++++++++++ 3 files changed, 210 insertions(+), 150 deletions(-) delete mode 100644 Documentation/devicetree/bindings/display/msm/dpu-msm8998.yaml create mode 100644 Documentation/devicetree/bindings/display/msm/qcom,msm8998-dpu.yaml create mode 100644 Documentation/devicetree/bindings/display/msm/qcom,msm8998-mdss.yaml diff --git a/Documentation/devicetree/bindings/display/msm/dpu-msm8998.yaml b/Documentation/devicetree/bindings/display/msm/dpu-msm8998.yaml deleted file mode 100644 index 67791dbc3b5d..000000000000 --- a/Documentation/devicetree/bindings/display/msm/dpu-msm8998.yaml +++ /dev/null @@ -1,150 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/display/msm/dpu-msm8998.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Qualcomm Display DPU dt properties for MSM8998 target - -maintainers: - - AngeloGioacchino Del Regno - -description: | - Device tree bindings for MSM Mobile Display Subsystem(MDSS) that encapsulates - sub-blocks like DPU display controller, DSI and DP interfaces etc. Device tree - bindings of MDSS and DPU are mentioned for MSM8998 target. - -$ref: /schemas/display/msm/mdss-common.yaml# - -properties: - compatible: - items: - - const: qcom,msm8998-mdss - - clocks: - items: - - description: Display AHB clock - - description: Display AXI clock - - description: Display core clock - - clock-names: - items: - - const: iface - - const: bus - - const: core - - iommus: - maxItems: 1 - -patternProperties: - "^display-controller@[0-9a-f]+$": - type: object - $ref: /schemas/display/msm/dpu-common.yaml# - description: Node containing the properties of DPU. - unevaluatedProperties: false - - properties: - compatible: - items: - - const: qcom,msm8998-dpu - - reg: - items: - - description: Address offset and size for mdp register set - - description: Address offset and size for regdma register set - - description: Address offset and size for vbif register set - - description: Address offset and size for non-realtime vbif register set - - reg-names: - items: - - const: mdp - - const: regdma - - const: vbif - - const: vbif_nrt - - clocks: - items: - - description: Display ahb clock - - description: Display axi clock - - description: Display mem-noc clock - - description: Display core clock - - description: Display vsync clock - - clock-names: - items: - - const: iface - - const: bus - - const: mnoc - - const: core - - const: vsync - -unevaluatedProperties: false - -examples: - - | - #include - #include - #include - - mdss: display-subsystem@c900000 { - compatible = "qcom,msm8998-mdss"; - reg = <0x0c900000 0x1000>; - reg-names = "mdss"; - - clocks = <&mmcc MDSS_AHB_CLK>, - <&mmcc MDSS_AXI_CLK>, - <&mmcc MDSS_MDP_CLK>; - clock-names = "iface", "bus", "core"; - - #address-cells = <1>; - #interrupt-cells = <1>; - #size-cells = <1>; - - interrupts = ; - interrupt-controller; - iommus = <&mmss_smmu 0>; - - power-domains = <&mmcc MDSS_GDSC>; - ranges; - - display-controller@c901000 { - compatible = "qcom,msm8998-dpu"; - reg = <0x0c901000 0x8f000>, - <0x0c9a8e00 0xf0>, - <0x0c9b0000 0x2008>, - <0x0c9b8000 0x1040>; - reg-names = "mdp", "regdma", "vbif", "vbif_nrt"; - - clocks = <&mmcc MDSS_AHB_CLK>, - <&mmcc MDSS_AXI_CLK>, - <&mmcc MNOC_AHB_CLK>, - <&mmcc MDSS_MDP_CLK>, - <&mmcc MDSS_VSYNC_CLK>; - clock-names = "iface", "bus", "mnoc", "core", "vsync"; - - interrupt-parent = <&mdss>; - interrupts = <0>; - operating-points-v2 = <&mdp_opp_table>; - power-domains = <&rpmpd MSM8998_VDDMX>; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - dpu_intf1_out: endpoint { - remote-endpoint = <&dsi0_in>; - }; - }; - - port@1 { - reg = <1>; - dpu_intf2_out: endpoint { - remote-endpoint = <&dsi1_in>; - }; - }; - }; - }; - }; -... diff --git a/Documentation/devicetree/bindings/display/msm/qcom,msm8998-dpu.yaml b/Documentation/devicetree/bindings/display/msm/qcom,msm8998-dpu.yaml new file mode 100644 index 000000000000..b02adba36e9e --- /dev/null +++ b/Documentation/devicetree/bindings/display/msm/qcom,msm8998-dpu.yaml @@ -0,0 +1,95 @@ +# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/msm/qcom,msm8998-dpu.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Display DPU dt properties for MSM8998 target + +maintainers: + - AngeloGioacchino Del Regno + +$ref: /schemas/display/msm/dpu-common.yaml# + +properties: + compatible: + items: + - const: qcom,msm8998-dpu + + reg: + items: + - description: Address offset and size for mdp register set + - description: Address offset and size for regdma register set + - description: Address offset and size for vbif register set + - description: Address offset and size for non-realtime vbif register set + + reg-names: + items: + - const: mdp + - const: regdma + - const: vbif + - const: vbif_nrt + + clocks: + items: + - description: Display ahb clock + - description: Display axi clock + - description: Display mem-noc clock + - description: Display core clock + - description: Display vsync clock + + clock-names: + items: + - const: iface + - const: bus + - const: mnoc + - const: core + - const: vsync + +unevaluatedProperties: false + +examples: + - | + #include + #include + + display-controller@c901000 { + compatible = "qcom,msm8998-dpu"; + reg = <0x0c901000 0x8f000>, + <0x0c9a8e00 0xf0>, + <0x0c9b0000 0x2008>, + <0x0c9b8000 0x1040>; + reg-names = "mdp", "regdma", "vbif", "vbif_nrt"; + + clocks = <&mmcc MDSS_AHB_CLK>, + <&mmcc MDSS_AXI_CLK>, + <&mmcc MNOC_AHB_CLK>, + <&mmcc MDSS_MDP_CLK>, + <&mmcc MDSS_VSYNC_CLK>; + clock-names = "iface", "bus", "mnoc", "core", "vsync"; + + interrupt-parent = <&mdss>; + interrupts = <0>; + operating-points-v2 = <&mdp_opp_table>; + power-domains = <&rpmpd MSM8998_VDDMX>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; + + port@1 { + reg = <1>; + endpoint { + remote-endpoint = <&dsi1_in>; + }; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/display/msm/qcom,msm8998-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,msm8998-mdss.yaml new file mode 100644 index 000000000000..192a832ef808 --- /dev/null +++ b/Documentation/devicetree/bindings/display/msm/qcom,msm8998-mdss.yaml @@ -0,0 +1,115 @@ +# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/msm/qcom,msm8998-mdss.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm MSM8998 Display MDSS + +maintainers: + - AngeloGioacchino Del Regno + +description: + Device tree bindings for MSM Mobile Display Subsystem(MDSS) that encapsulates + sub-blocks like DPU display controller, DSI and DP interfaces etc. Device tree + bindings of MDSS are mentioned for MSM8998 target. + +$ref: /schemas/display/msm/mdss-common.yaml# + +properties: + compatible: + items: + - const: qcom,msm8998-mdss + + clocks: + items: + - description: Display AHB clock + - description: Display AXI clock + - description: Display core clock + + clock-names: + items: + - const: iface + - const: bus + - const: core + + iommus: + maxItems: 1 + +patternProperties: + "^display-controller@[0-9a-f]+$": + type: object + properties: + compatible: + const: qcom,msm8998-dpu + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + + display-subsystem@c900000 { + compatible = "qcom,msm8998-mdss"; + reg = <0x0c900000 0x1000>; + reg-names = "mdss"; + + clocks = <&mmcc MDSS_AHB_CLK>, + <&mmcc MDSS_AXI_CLK>, + <&mmcc MDSS_MDP_CLK>; + clock-names = "iface", "bus", "core"; + + #address-cells = <1>; + #interrupt-cells = <1>; + #size-cells = <1>; + + interrupts = ; + interrupt-controller; + iommus = <&mmss_smmu 0>; + + power-domains = <&mmcc MDSS_GDSC>; + ranges; + + display-controller@c901000 { + compatible = "qcom,msm8998-dpu"; + reg = <0x0c901000 0x8f000>, + <0x0c9a8e00 0xf0>, + <0x0c9b0000 0x2008>, + <0x0c9b8000 0x1040>; + reg-names = "mdp", "regdma", "vbif", "vbif_nrt"; + + clocks = <&mmcc MDSS_AHB_CLK>, + <&mmcc MDSS_AXI_CLK>, + <&mmcc MNOC_AHB_CLK>, + <&mmcc MDSS_MDP_CLK>, + <&mmcc MDSS_VSYNC_CLK>; + clock-names = "iface", "bus", "mnoc", "core", "vsync"; + + interrupt-parent = <&mdss>; + interrupts = <0>; + operating-points-v2 = <&mdp_opp_table>; + power-domains = <&rpmpd MSM8998_VDDMX>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dpu_intf1_out: endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; + + port@1 { + reg = <1>; + dpu_intf2_out: endpoint { + remote-endpoint = <&dsi1_in>; + }; + }; + }; + }; + }; +... -- cgit From 06097b13ef97a5e55dd4131a8a05c5af1aad2ad3 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 24 Oct 2022 19:42:23 +0300 Subject: dt-bindings: display/msm: split dpu-qcm2290 into DPU and MDSS parts In order to make the schema more readable, split dpu-qcm2290 into the DPU and MDSS parts, each one describing just a single device binding. Reviewed-by: Rob Herring Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/508383/ Link: https://lore.kernel.org/r/20221024164225.3236654-11-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov --- .../bindings/display/msm/dpu-qcm2290.yaml | 148 --------------------- .../bindings/display/msm/qcom,qcm2290-dpu.yaml | 84 ++++++++++++ .../bindings/display/msm/qcom,qcm2290-mdss.yaml | 117 ++++++++++++++++ 3 files changed, 201 insertions(+), 148 deletions(-) delete mode 100644 Documentation/devicetree/bindings/display/msm/dpu-qcm2290.yaml create mode 100644 Documentation/devicetree/bindings/display/msm/qcom,qcm2290-dpu.yaml create mode 100644 Documentation/devicetree/bindings/display/msm/qcom,qcm2290-mdss.yaml diff --git a/Documentation/devicetree/bindings/display/msm/dpu-qcm2290.yaml b/Documentation/devicetree/bindings/display/msm/dpu-qcm2290.yaml deleted file mode 100644 index 42e676bdda4e..000000000000 --- a/Documentation/devicetree/bindings/display/msm/dpu-qcm2290.yaml +++ /dev/null @@ -1,148 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/display/msm/dpu-qcm2290.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Qualcomm Display DPU dt properties for QCM2290 target - -maintainers: - - Loic Poulain - -description: | - Device tree bindings for MSM Mobile Display Subsystem(MDSS) that encapsulates - sub-blocks like DPU display controller and DSI. Device tree bindings of MDSS - and DPU are mentioned for QCM2290 target. - -$ref: /schemas/display/msm/mdss-common.yaml# - -properties: - compatible: - items: - - const: qcom,qcm2290-mdss - - clocks: - items: - - description: Display AHB clock from gcc - - description: Display AXI clock - - description: Display core clock - - clock-names: - items: - - const: iface - - const: bus - - const: core - - iommus: - maxItems: 2 - - interconnects: - maxItems: 1 - - interconnect-names: - maxItems: 1 - -patternProperties: - "^display-controller@[0-9a-f]+$": - type: object - $ref: /schemas/display/msm/dpu-common.yaml# - description: Node containing the properties of DPU. - unevaluatedProperties: false - - properties: - compatible: - items: - - const: qcom,qcm2290-dpu - - reg: - items: - - description: Address offset and size for mdp register set - - description: Address offset and size for vbif register set - - reg-names: - items: - - const: mdp - - const: vbif - - clocks: - items: - - description: Display AXI clock from gcc - - description: Display AHB clock from dispcc - - description: Display core clock from dispcc - - description: Display lut clock from dispcc - - description: Display vsync clock from dispcc - - clock-names: - items: - - const: bus - - const: iface - - const: core - - const: lut - - const: vsync - -unevaluatedProperties: false - -examples: - - | - #include - #include - #include - #include - #include - - mdss: mdss@5e00000 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "qcom,qcm2290-mdss"; - reg = <0x05e00000 0x1000>; - reg-names = "mdss"; - power-domains = <&dispcc MDSS_GDSC>; - clocks = <&gcc GCC_DISP_AHB_CLK>, - <&gcc GCC_DISP_HF_AXI_CLK>, - <&dispcc DISP_CC_MDSS_MDP_CLK>; - clock-names = "iface", "bus", "core"; - - interrupts = ; - interrupt-controller; - #interrupt-cells = <1>; - - interconnects = <&mmrt_virt MASTER_MDP0 &bimc SLAVE_EBI1>; - interconnect-names = "mdp0-mem"; - - iommus = <&apps_smmu 0x420 0x2>, - <&apps_smmu 0x421 0x0>; - ranges; - - mdss_mdp: display-controller@5e01000 { - compatible = "qcom,qcm2290-dpu"; - reg = <0x05e01000 0x8f000>, - <0x05eb0000 0x2008>; - reg-names = "mdp", "vbif"; - - clocks = <&gcc GCC_DISP_HF_AXI_CLK>, - <&dispcc DISP_CC_MDSS_AHB_CLK>, - <&dispcc DISP_CC_MDSS_MDP_CLK>, - <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>, - <&dispcc DISP_CC_MDSS_VSYNC_CLK>; - clock-names = "bus", "iface", "core", "lut", "vsync"; - - operating-points-v2 = <&mdp_opp_table>; - power-domains = <&rpmpd QCM2290_VDDCX>; - - interrupt-parent = <&mdss>; - interrupts = <0>; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - dpu_intf1_out: endpoint { - remote-endpoint = <&dsi0_in>; - }; - }; - }; - }; - }; -... diff --git a/Documentation/devicetree/bindings/display/msm/qcom,qcm2290-dpu.yaml b/Documentation/devicetree/bindings/display/msm/qcom,qcm2290-dpu.yaml new file mode 100644 index 000000000000..a7b382f01b56 --- /dev/null +++ b/Documentation/devicetree/bindings/display/msm/qcom,qcm2290-dpu.yaml @@ -0,0 +1,84 @@ +# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/msm/qcom,qcm2290-dpu.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Display DPU dt properties for QCM2290 target + +maintainers: + - Loic Poulain + +$ref: /schemas/display/msm/dpu-common.yaml# + +properties: + compatible: + items: + - const: qcom,qcm2290-dpu + + reg: + items: + - description: Address offset and size for mdp register set + - description: Address offset and size for vbif register set + + reg-names: + items: + - const: mdp + - const: vbif + + clocks: + items: + - description: Display AXI clock from gcc + - description: Display AHB clock from dispcc + - description: Display core clock from dispcc + - description: Display lut clock from dispcc + - description: Display vsync clock from dispcc + + clock-names: + items: + - const: bus + - const: iface + - const: core + - const: lut + - const: vsync + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + + display-controller@5e01000 { + compatible = "qcom,qcm2290-dpu"; + reg = <0x05e01000 0x8f000>, + <0x05eb0000 0x2008>; + reg-names = "mdp", "vbif"; + + clocks = <&gcc GCC_DISP_HF_AXI_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>, + <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>, + <&dispcc DISP_CC_MDSS_VSYNC_CLK>; + clock-names = "bus", "iface", "core", "lut", "vsync"; + + operating-points-v2 = <&mdp_opp_table>; + power-domains = <&rpmpd QCM2290_VDDCX>; + + interrupt-parent = <&mdss>; + interrupts = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/display/msm/qcom,qcm2290-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,qcm2290-mdss.yaml new file mode 100644 index 000000000000..419989d6279e --- /dev/null +++ b/Documentation/devicetree/bindings/display/msm/qcom,qcm2290-mdss.yaml @@ -0,0 +1,117 @@ +# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/msm/qcom,qcm2290-mdss.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm QCM220 Display MDSS + +maintainers: + - Loic Poulain + +description: + Device tree bindings for MSM Mobile Display Subsystem(MDSS) that encapsulates + sub-blocks like DPU display controller and DSI. Device tree bindings of MDSS + are mentioned for QCM2290 target. + +$ref: /schemas/display/msm/mdss-common.yaml# + +properties: + compatible: + items: + - const: qcom,qcm2290-mdss + + clocks: + items: + - description: Display AHB clock from gcc + - description: Display AXI clock + - description: Display core clock + + clock-names: + items: + - const: iface + - const: bus + - const: core + + iommus: + maxItems: 2 + + interconnects: + maxItems: 1 + + interconnect-names: + maxItems: 1 + +patternProperties: + "^display-controller@[0-9a-f]+$": + type: object + properties: + compatible: + const: qcom,qcm2290-dpu + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + #include + #include + + mdss@5e00000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "qcom,qcm2290-mdss"; + reg = <0x05e00000 0x1000>; + reg-names = "mdss"; + power-domains = <&dispcc MDSS_GDSC>; + clocks = <&gcc GCC_DISP_AHB_CLK>, + <&gcc GCC_DISP_HF_AXI_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>; + clock-names = "iface", "bus", "core"; + + interrupts = ; + interrupt-controller; + #interrupt-cells = <1>; + + interconnects = <&mmrt_virt MASTER_MDP0 &bimc SLAVE_EBI1>; + interconnect-names = "mdp0-mem"; + + iommus = <&apps_smmu 0x420 0x2>, + <&apps_smmu 0x421 0x0>; + ranges; + + display-controller@5e01000 { + compatible = "qcom,qcm2290-dpu"; + reg = <0x05e01000 0x8f000>, + <0x05eb0000 0x2008>; + reg-names = "mdp", "vbif"; + + clocks = <&gcc GCC_DISP_HF_AXI_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>, + <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>, + <&dispcc DISP_CC_MDSS_VSYNC_CLK>; + clock-names = "bus", "iface", "core", "lut", "vsync"; + + operating-points-v2 = <&mdp_opp_table>; + power-domains = <&rpmpd QCM2290_VDDCX>; + + interrupt-parent = <&mdss>; + interrupts = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dpu_intf1_out: endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; + }; + }; + }; +... -- cgit From 4b32e46638c2969c1e2b50b02dd2a23bf7033052 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 24 Oct 2022 19:42:24 +0300 Subject: dt-bindings: display/msm: add missing device nodes to mdss-* schemas Add missing device nodes (DSI, PHYs, DP/eDP) to the existing MDSS schemas. Reviewed-by: Rob Herring Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/508391/ Link: https://lore.kernel.org/r/20221024164225.3236654-12-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov --- .../bindings/display/msm/qcom,msm8998-mdss.yaml | 153 +++++++++++ .../bindings/display/msm/qcom,qcm2290-mdss.yaml | 81 ++++++ .../bindings/display/msm/qcom,sc7180-mdss.yaml | 179 +++++++++++++ .../bindings/display/msm/qcom,sc7280-mdss.yaml | 292 +++++++++++++++++++++ .../bindings/display/msm/qcom,sdm845-mdss.yaml | 153 +++++++++++ 5 files changed, 858 insertions(+) diff --git a/Documentation/devicetree/bindings/display/msm/qcom,msm8998-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,msm8998-mdss.yaml index 192a832ef808..cf52ff77a41a 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,msm8998-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,msm8998-mdss.yaml @@ -43,11 +43,24 @@ patternProperties: compatible: const: qcom,msm8998-dpu + "^dsi@[0-9a-f]+$": + type: object + properties: + compatible: + const: qcom,mdss-dsi-ctrl + + "^phy@[0-9a-f]+$": + type: object + properties: + compatible: + const: qcom,dsi-phy-10nm-8998 + unevaluatedProperties: false examples: - | #include + #include #include #include @@ -111,5 +124,145 @@ examples: }; }; }; + + dsi@c994000 { + compatible = "qcom,mdss-dsi-ctrl"; + reg = <0x0c994000 0x400>; + reg-names = "dsi_ctrl"; + + interrupt-parent = <&mdss>; + interrupts = <4>; + + clocks = <&mmcc MDSS_BYTE0_CLK>, + <&mmcc MDSS_BYTE0_INTF_CLK>, + <&mmcc MDSS_PCLK0_CLK>, + <&mmcc MDSS_ESC0_CLK>, + <&mmcc MDSS_AHB_CLK>, + <&mmcc MDSS_AXI_CLK>; + clock-names = "byte", + "byte_intf", + "pixel", + "core", + "iface", + "bus"; + assigned-clocks = <&mmcc BYTE0_CLK_SRC>, <&mmcc PCLK0_CLK_SRC>; + assigned-clock-parents = <&dsi0_phy 0>, <&dsi0_phy 1>; + + operating-points-v2 = <&dsi_opp_table>; + power-domains = <&rpmpd MSM8998_VDDCX>; + + phys = <&dsi0_phy>; + phy-names = "dsi"; + + #address-cells = <1>; + #size-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dsi0_in: endpoint { + remote-endpoint = <&dpu_intf1_out>; + }; + }; + + port@1 { + reg = <1>; + dsi0_out: endpoint { + }; + }; + }; + }; + + dsi0_phy: phy@c994400 { + compatible = "qcom,dsi-phy-10nm-8998"; + reg = <0x0c994400 0x200>, + <0x0c994600 0x280>, + <0x0c994a00 0x1e0>; + reg-names = "dsi_phy", + "dsi_phy_lane", + "dsi_pll"; + + #clock-cells = <1>; + #phy-cells = <0>; + + clocks = <&mmcc MDSS_AHB_CLK>, + <&rpmcc RPM_SMD_XO_CLK_SRC>; + clock-names = "iface", "ref"; + + vdds-supply = <&pm8998_l1>; + }; + + dsi@c996000 { + compatible = "qcom,mdss-dsi-ctrl"; + reg = <0x0c996000 0x400>; + reg-names = "dsi_ctrl"; + + interrupt-parent = <&mdss>; + interrupts = <5>; + + clocks = <&mmcc MDSS_BYTE1_CLK>, + <&mmcc MDSS_BYTE1_INTF_CLK>, + <&mmcc MDSS_PCLK1_CLK>, + <&mmcc MDSS_ESC1_CLK>, + <&mmcc MDSS_AHB_CLK>, + <&mmcc MDSS_AXI_CLK>; + clock-names = "byte", + "byte_intf", + "pixel", + "core", + "iface", + "bus"; + assigned-clocks = <&mmcc BYTE1_CLK_SRC>, <&mmcc PCLK1_CLK_SRC>; + assigned-clock-parents = <&dsi1_phy 0>, <&dsi1_phy 1>; + + operating-points-v2 = <&dsi_opp_table>; + power-domains = <&rpmpd MSM8998_VDDCX>; + + phys = <&dsi1_phy>; + phy-names = "dsi"; + + #address-cells = <1>; + #size-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dsi1_in: endpoint { + remote-endpoint = <&dpu_intf2_out>; + }; + }; + + port@1 { + reg = <1>; + dsi1_out: endpoint { + }; + }; + }; + }; + + dsi1_phy: phy@c996400 { + compatible = "qcom,dsi-phy-10nm-8998"; + reg = <0x0c996400 0x200>, + <0x0c996600 0x280>, + <0x0c996a00 0x10e>; + reg-names = "dsi_phy", + "dsi_phy_lane", + "dsi_pll"; + + #clock-cells = <1>; + #phy-cells = <0>; + + clocks = <&mmcc MDSS_AHB_CLK>, + <&rpmcc RPM_SMD_XO_CLK_SRC>; + clock-names = "iface", "ref"; + + vdds-supply = <&pm8998_l1>; + }; }; ... diff --git a/Documentation/devicetree/bindings/display/msm/qcom,qcm2290-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,qcm2290-mdss.yaml index 419989d6279e..d6f043a4b08d 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,qcm2290-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,qcm2290-mdss.yaml @@ -49,12 +49,25 @@ patternProperties: compatible: const: qcom,qcm2290-dpu + "^dsi@[0-9a-f]+$": + type: object + properties: + compatible: + const: qcom,dsi-ctrl-6g-qcm2290 + + "^phy@[0-9a-f]+$": + type: object + properties: + compatible: + const: qcom,dsi-phy-14nm-2290 + unevaluatedProperties: false examples: - | #include #include + #include #include #include #include @@ -113,5 +126,73 @@ examples: }; }; }; + + dsi@5e94000 { + compatible = "qcom,dsi-ctrl-6g-qcm2290"; + reg = <0x05e94000 0x400>; + reg-names = "dsi_ctrl"; + + interrupt-parent = <&mdss>; + interrupts = <4>; + + clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK>, + <&dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>, + <&dispcc DISP_CC_MDSS_PCLK0_CLK>, + <&dispcc DISP_CC_MDSS_ESC0_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&gcc GCC_DISP_HF_AXI_CLK>; + clock-names = "byte", + "byte_intf", + "pixel", + "core", + "iface", + "bus"; + assigned-clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>, <&dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>; + assigned-clock-parents = <&dsi0_phy 0>, <&dsi0_phy 1>; + + operating-points-v2 = <&dsi_opp_table>; + power-domains = <&rpmpd QCM2290_VDDCX>; + + phys = <&dsi0_phy>; + phy-names = "dsi"; + + #address-cells = <1>; + #size-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dsi0_in: endpoint { + remote-endpoint = <&dpu_intf1_out>; + }; + }; + + port@1 { + reg = <1>; + dsi0_out: endpoint { + }; + }; + }; + }; + + dsi0_phy: phy@5e94400 { + compatible = "qcom,dsi-phy-14nm-2290"; + reg = <0x05e94400 0x100>, + <0x05e94500 0x300>, + <0x05e94800 0x188>; + reg-names = "dsi_phy", + "dsi_phy_lane", + "dsi_pll"; + + #clock-cells = <1>; + #phy-cells = <0>; + + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, <&rpmcc RPM_SMD_XO_CLK_SRC>; + clock-names = "iface", "ref"; + vcca-supply = <&vreg_dsi_phy>; + }; }; ... diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sc7180-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sc7180-mdss.yaml index 103cfd60c61b..13e396d61a51 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sc7180-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sc7180-mdss.yaml @@ -49,12 +49,31 @@ patternProperties: compatible: const: qcom,sc7180-dpu + "^displayport-controller@[0-9a-f]+$": + type: object + properties: + compatible: + const: qcom,sc7180-dp + + "^dsi@[0-9a-f]+$": + type: object + properties: + compatible: + const: qcom,mdss-dsi-ctrl + + "^phy@[0-9a-f]+$": + type: object + properties: + compatible: + const: qcom,dsi-phy-10nm + unevaluatedProperties: false examples: - | #include #include + #include #include #include #include @@ -121,5 +140,165 @@ examples: }; }; }; + + dsi@ae94000 { + compatible = "qcom,mdss-dsi-ctrl"; + reg = <0x0ae94000 0x400>; + reg-names = "dsi_ctrl"; + + interrupt-parent = <&mdss>; + interrupts = <4>; + + clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK>, + <&dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>, + <&dispcc DISP_CC_MDSS_PCLK0_CLK>, + <&dispcc DISP_CC_MDSS_ESC0_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&gcc GCC_DISP_HF_AXI_CLK>; + clock-names = "byte", + "byte_intf", + "pixel", + "core", + "iface", + "bus"; + + assigned-clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>, <&dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>; + assigned-clock-parents = <&dsi_phy 0>, <&dsi_phy 1>; + + operating-points-v2 = <&dsi_opp_table>; + power-domains = <&rpmhpd SC7180_CX>; + + phys = <&dsi_phy>; + phy-names = "dsi"; + + #address-cells = <1>; + #size-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dsi0_in: endpoint { + remote-endpoint = <&dpu_intf1_out>; + }; + }; + + port@1 { + reg = <1>; + dsi0_out: endpoint { + }; + }; + }; + + dsi_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-187500000 { + opp-hz = /bits/ 64 <187500000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-358000000 { + opp-hz = /bits/ 64 <358000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + }; + }; + + dsi_phy: phy@ae94400 { + compatible = "qcom,dsi-phy-10nm"; + reg = <0x0ae94400 0x200>, + <0x0ae94600 0x280>, + <0x0ae94a00 0x1e0>; + reg-names = "dsi_phy", + "dsi_phy_lane", + "dsi_pll"; + + #clock-cells = <1>; + #phy-cells = <0>; + + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&rpmhcc RPMH_CXO_CLK>; + clock-names = "iface", "ref"; + vdds-supply = <&vreg_dsi_phy>; + }; + + displayport-controller@ae90000 { + compatible = "qcom,sc7180-dp"; + + reg = <0xae90000 0x200>, + <0xae90200 0x200>, + <0xae90400 0xc00>, + <0xae91000 0x400>, + <0xae91400 0x400>; + + interrupt-parent = <&mdss>; + interrupts = <12>; + + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_DP_AUX_CLK>, + <&dispcc DISP_CC_MDSS_DP_LINK_CLK>, + <&dispcc DISP_CC_MDSS_DP_LINK_INTF_CLK>, + <&dispcc DISP_CC_MDSS_DP_PIXEL_CLK>; + clock-names = "core_iface", "core_aux", "ctrl_link", + "ctrl_link_iface", "stream_pixel"; + assigned-clocks = <&dispcc DISP_CC_MDSS_DP_LINK_CLK_SRC>, + <&dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>; + assigned-clock-parents = <&dp_phy 0>, <&dp_phy 1>; + phys = <&dp_phy>; + phy-names = "dp"; + + operating-points-v2 = <&dp_opp_table>; + power-domains = <&rpmhpd SC7180_CX>; + + #sound-dai-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + dp_in: endpoint { + remote-endpoint = <&dpu_intf0_out>; + }; + }; + + port@1 { + reg = <1>; + dp_out: endpoint { }; + }; + }; + + dp_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-160000000 { + opp-hz = /bits/ 64 <160000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-270000000 { + opp-hz = /bits/ 64 <270000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-540000000 { + opp-hz = /bits/ 64 <540000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-810000000 { + opp-hz = /bits/ 64 <810000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; }; ... diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sc7280-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sc7280-mdss.yaml index d4ac2d5d13fb..a3de1744ba11 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sc7280-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sc7280-mdss.yaml @@ -48,12 +48,39 @@ patternProperties: compatible: const: qcom,sc7280-dpu + "^displayport-controller@[0-9a-f]+$": + type: object + properties: + compatible: + const: qcom,sc7280-dp + + "^dsi@[0-9a-f]+$": + type: object + properties: + compatible: + const: qcom,mdss-dsi-ctrl + + "^edp@[0-9a-f]+$": + type: object + properties: + compatible: + const: qcom,sc7280-edp + + "^phy@[0-9a-f]+$": + type: object + properties: + compatible: + enum: + - qcom,sc7280-dsi-phy-7nm + - qcom,sc7280-edp-phy + unevaluatedProperties: false examples: - | #include #include + #include #include #include #include @@ -124,6 +151,271 @@ examples: remote-endpoint = <&edp_in>; }; }; + + port@2 { + reg = <2>; + dpu_intf0_out: endpoint { + remote-endpoint = <&dp_in>; + }; + }; + }; + }; + + dsi@ae94000 { + compatible = "qcom,mdss-dsi-ctrl"; + reg = <0x0ae94000 0x400>; + reg-names = "dsi_ctrl"; + + interrupt-parent = <&mdss>; + interrupts = <4>; + + clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK>, + <&dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>, + <&dispcc DISP_CC_MDSS_PCLK0_CLK>, + <&dispcc DISP_CC_MDSS_ESC0_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&gcc GCC_DISP_HF_AXI_CLK>; + clock-names = "byte", + "byte_intf", + "pixel", + "core", + "iface", + "bus"; + + assigned-clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>, + <&dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>; + assigned-clock-parents = <&mdss_dsi_phy 0>, <&mdss_dsi_phy 1>; + + operating-points-v2 = <&dsi_opp_table>; + power-domains = <&rpmhpd SC7280_CX>; + + phys = <&mdss_dsi_phy>; + phy-names = "dsi"; + + #address-cells = <1>; + #size-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dsi0_in: endpoint { + remote-endpoint = <&dpu_intf1_out>; + }; + }; + + port@1 { + reg = <1>; + dsi0_out: endpoint { + }; + }; + }; + + dsi_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-187500000 { + opp-hz = /bits/ 64 <187500000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-358000000 { + opp-hz = /bits/ 64 <358000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + }; + }; + + mdss_dsi_phy: phy@ae94400 { + compatible = "qcom,sc7280-dsi-phy-7nm"; + reg = <0x0ae94400 0x200>, + <0x0ae94600 0x280>, + <0x0ae94900 0x280>; + reg-names = "dsi_phy", + "dsi_phy_lane", + "dsi_pll"; + + #clock-cells = <1>; + #phy-cells = <0>; + + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&rpmhcc RPMH_CXO_CLK>; + clock-names = "iface", "ref"; + + vdds-supply = <&vreg_dsi_supply>; + }; + + edp@aea0000 { + compatible = "qcom,sc7280-edp"; + pinctrl-names = "default"; + pinctrl-0 = <&edp_hot_plug_det>; + + reg = <0xaea0000 0x200>, + <0xaea0200 0x200>, + <0xaea0400 0xc00>, + <0xaea1000 0x400>; + + interrupt-parent = <&mdss>; + interrupts = <14>; + + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_EDP_AUX_CLK>, + <&dispcc DISP_CC_MDSS_EDP_LINK_CLK>, + <&dispcc DISP_CC_MDSS_EDP_LINK_INTF_CLK>, + <&dispcc DISP_CC_MDSS_EDP_PIXEL_CLK>; + clock-names = "core_iface", + "core_aux", + "ctrl_link", + "ctrl_link_iface", + "stream_pixel"; + assigned-clocks = <&dispcc DISP_CC_MDSS_EDP_LINK_CLK_SRC>, + <&dispcc DISP_CC_MDSS_EDP_PIXEL_CLK_SRC>; + assigned-clock-parents = <&mdss_edp_phy 0>, <&mdss_edp_phy 1>; + + phys = <&mdss_edp_phy>; + phy-names = "dp"; + + operating-points-v2 = <&edp_opp_table>; + power-domains = <&rpmhpd SC7280_CX>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + edp_in: endpoint { + remote-endpoint = <&dpu_intf5_out>; + }; + }; + + port@1 { + reg = <1>; + mdss_edp_out: endpoint { }; + }; + }; + + edp_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-160000000 { + opp-hz = /bits/ 64 <160000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-270000000 { + opp-hz = /bits/ 64 <270000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-540000000 { + opp-hz = /bits/ 64 <540000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + + opp-810000000 { + opp-hz = /bits/ 64 <810000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + mdss_edp_phy: phy@aec2a00 { + compatible = "qcom,sc7280-edp-phy"; + + reg = <0xaec2a00 0x19c>, + <0xaec2200 0xa0>, + <0xaec2600 0xa0>, + <0xaec2000 0x1c0>; + + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&gcc GCC_EDP_CLKREF_EN>; + clock-names = "aux", + "cfg_ahb"; + + #clock-cells = <1>; + #phy-cells = <0>; + }; + + displayport-controller@ae90000 { + compatible = "qcom,sc7280-dp"; + + reg = <0xae90000 0x200>, + <0xae90200 0x200>, + <0xae90400 0xc00>, + <0xae91000 0x400>, + <0xae91400 0x400>; + + interrupt-parent = <&mdss>; + interrupts = <12>; + + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_DP_AUX_CLK>, + <&dispcc DISP_CC_MDSS_DP_LINK_CLK>, + <&dispcc DISP_CC_MDSS_DP_LINK_INTF_CLK>, + <&dispcc DISP_CC_MDSS_DP_PIXEL_CLK>; + clock-names = "core_iface", + "core_aux", + "ctrl_link", + "ctrl_link_iface", + "stream_pixel"; + assigned-clocks = <&dispcc DISP_CC_MDSS_DP_LINK_CLK_SRC>, + <&dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>; + assigned-clock-parents = <&dp_phy 0>, <&dp_phy 1>; + phys = <&dp_phy>; + phy-names = "dp"; + + operating-points-v2 = <&dp_opp_table>; + power-domains = <&rpmhpd SC7280_CX>; + + #sound-dai-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dp_in: endpoint { + remote-endpoint = <&dpu_intf0_out>; + }; + }; + + port@1 { + reg = <1>; + dp_out: endpoint { }; + }; + }; + + dp_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-160000000 { + opp-hz = /bits/ 64 <160000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-270000000 { + opp-hz = /bits/ 64 <270000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-540000000 { + opp-hz = /bits/ 64 <540000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-810000000 { + opp-hz = /bits/ 64 <810000000>; + required-opps = <&rpmhpd_opp_nom>; + }; }; }; }; diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sdm845-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sdm845-mdss.yaml index 47fe66f4da54..31ca6f99fc22 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sdm845-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sdm845-mdss.yaml @@ -47,12 +47,25 @@ patternProperties: compatible: const: qcom,sdm845-dpu + "^dsi@[0-9a-f]+$": + type: object + properties: + compatible: + const: qcom,mdss-dsi-ctrl + + "^phy@[0-9a-f]+$": + type: object + properties: + compatible: + const: qcom,dsi-phy-10nm + unevaluatedProperties: false examples: - | #include #include + #include #include #include @@ -113,5 +126,145 @@ examples: }; }; }; + + dsi@ae94000 { + compatible = "qcom,mdss-dsi-ctrl"; + reg = <0x0ae94000 0x400>; + reg-names = "dsi_ctrl"; + + interrupt-parent = <&mdss>; + interrupts = <4>; + + clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK>, + <&dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>, + <&dispcc DISP_CC_MDSS_PCLK0_CLK>, + <&dispcc DISP_CC_MDSS_ESC0_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_AXI_CLK>; + clock-names = "byte", + "byte_intf", + "pixel", + "core", + "iface", + "bus"; + assigned-clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>, + <&dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>; + assigned-clock-parents = <&dsi0_phy 0>, <&dsi0_phy 1>; + + operating-points-v2 = <&dsi_opp_table>; + power-domains = <&rpmhpd SDM845_CX>; + + phys = <&dsi0_phy>; + phy-names = "dsi"; + + #address-cells = <1>; + #size-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dsi0_in: endpoint { + remote-endpoint = <&dpu_intf1_out>; + }; + }; + + port@1 { + reg = <1>; + dsi0_out: endpoint { + }; + }; + }; + }; + + dsi0_phy: phy@ae94400 { + compatible = "qcom,dsi-phy-10nm"; + reg = <0x0ae94400 0x200>, + <0x0ae94600 0x280>, + <0x0ae94a00 0x1e0>; + reg-names = "dsi_phy", + "dsi_phy_lane", + "dsi_pll"; + + #clock-cells = <1>; + #phy-cells = <0>; + + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&rpmhcc RPMH_CXO_CLK>; + clock-names = "iface", "ref"; + vdds-supply = <&vreg_dsi_phy>; + }; + + dsi@ae96000 { + compatible = "qcom,mdss-dsi-ctrl"; + reg = <0x0ae96000 0x400>; + reg-names = "dsi_ctrl"; + + interrupt-parent = <&mdss>; + interrupts = <5>; + + clocks = <&dispcc DISP_CC_MDSS_BYTE1_CLK>, + <&dispcc DISP_CC_MDSS_BYTE1_INTF_CLK>, + <&dispcc DISP_CC_MDSS_PCLK1_CLK>, + <&dispcc DISP_CC_MDSS_ESC1_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_AXI_CLK>; + clock-names = "byte", + "byte_intf", + "pixel", + "core", + "iface", + "bus"; + assigned-clocks = <&dispcc DISP_CC_MDSS_BYTE1_CLK_SRC>, + <&dispcc DISP_CC_MDSS_PCLK1_CLK_SRC>; + assigned-clock-parents = <&dsi1_phy 0>, <&dsi1_phy 1>; + + operating-points-v2 = <&dsi_opp_table>; + power-domains = <&rpmhpd SDM845_CX>; + + phys = <&dsi1_phy>; + phy-names = "dsi"; + + #address-cells = <1>; + #size-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dsi1_in: endpoint { + remote-endpoint = <&dpu_intf2_out>; + }; + }; + + port@1 { + reg = <1>; + dsi1_out: endpoint { + }; + }; + }; + }; + + dsi1_phy: phy@ae96400 { + compatible = "qcom,dsi-phy-10nm"; + reg = <0x0ae96400 0x200>, + <0x0ae96600 0x280>, + <0x0ae96a00 0x10e>; + reg-names = "dsi_phy", + "dsi_phy_lane", + "dsi_pll"; + + #clock-cells = <1>; + #phy-cells = <0>; + + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&rpmhcc RPMH_CXO_CLK>; + clock-names = "iface", "ref"; + vdds-supply = <&vreg_dsi_phy>; + }; }; ... -- cgit From 4e78a58ad34e8d7c7fbd26205056d3baaf0b5e98 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 24 Oct 2022 19:42:25 +0300 Subject: dt-bindings: display/msm: add support for the display on SM8250 Add DPU and MDSS schemas to describe MDSS and DPU blocks on the Qualcomm SM8250 platform. Reviewed-by: Rob Herring Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/508397/ Link: https://lore.kernel.org/r/20221024164225.3236654-13-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov --- .../bindings/display/msm/mdss-common.yaml | 4 +- .../bindings/display/msm/qcom,sm8250-dpu.yaml | 92 ++++++ .../bindings/display/msm/qcom,sm8250-mdss.yaml | 330 +++++++++++++++++++++ 3 files changed, 424 insertions(+), 2 deletions(-) create mode 100644 Documentation/devicetree/bindings/display/msm/qcom,sm8250-dpu.yaml create mode 100644 Documentation/devicetree/bindings/display/msm/qcom,sm8250-mdss.yaml diff --git a/Documentation/devicetree/bindings/display/msm/mdss-common.yaml b/Documentation/devicetree/bindings/display/msm/mdss-common.yaml index 2a476bd0215e..27d7242657b2 100644 --- a/Documentation/devicetree/bindings/display/msm/mdss-common.yaml +++ b/Documentation/devicetree/bindings/display/msm/mdss-common.yaml @@ -27,11 +27,11 @@ properties: clocks: minItems: 2 - maxItems: 3 + maxItems: 4 clock-names: minItems: 2 - maxItems: 3 + maxItems: 4 interrupts: maxItems: 1 diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm8250-dpu.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm8250-dpu.yaml new file mode 100644 index 000000000000..9ff8a265c85f --- /dev/null +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm8250-dpu.yaml @@ -0,0 +1,92 @@ +# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/msm/qcom,sm8250-dpu.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm SM8250 Display DPU + +maintainers: + - Dmitry Baryshkov + +$ref: /schemas/display/msm/dpu-common.yaml# + +properties: + compatible: + const: qcom,sm8250-dpu + + reg: + items: + - description: Address offset and size for mdp register set + - description: Address offset and size for vbif register set + + reg-names: + items: + - const: mdp + - const: vbif + + clocks: + items: + - description: Display ahb clock + - description: Display hf axi clock + - description: Display core clock + - description: Display vsync clock + + clock-names: + items: + - const: iface + - const: bus + - const: core + - const: vsync + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + #include + #include + + display-controller@ae01000 { + compatible = "qcom,sm8250-dpu"; + reg = <0x0ae01000 0x8f000>, + <0x0aeb0000 0x2008>; + reg-names = "mdp", "vbif"; + + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&gcc GCC_DISP_HF_AXI_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>, + <&dispcc DISP_CC_MDSS_VSYNC_CLK>; + clock-names = "iface", "bus", "core", "vsync"; + + assigned-clocks = <&dispcc DISP_CC_MDSS_VSYNC_CLK>; + assigned-clock-rates = <19200000>; + + operating-points-v2 = <&mdp_opp_table>; + power-domains = <&rpmhpd SM8250_MMCX>; + + interrupt-parent = <&mdss>; + interrupts = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; + + port@1 { + reg = <1>; + endpoint { + remote-endpoint = <&dsi1_in>; + }; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm8250-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm8250-mdss.yaml new file mode 100644 index 000000000000..0d3be5386b3f --- /dev/null +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm8250-mdss.yaml @@ -0,0 +1,330 @@ +# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/msm/qcom,sm8250-mdss.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm SM8250 Display MDSS + +maintainers: + - Dmitry Baryshkov + +description: + Device tree bindings for MSM Mobile Display Subsystem(MDSS) that encapsulates + sub-blocks like DPU display controller, DSI and DP interfaces etc. Device tree + bindings of MDSS are mentioned for SM8250 target. + +$ref: /schemas/display/msm/mdss-common.yaml# + +properties: + compatible: + items: + - const: qcom,sm8250-mdss + + clocks: + items: + - description: Display AHB clock from gcc + - description: Display hf axi clock + - description: Display sf axi clock + - description: Display core clock + + clock-names: + items: + - const: iface + - const: bus + - const: nrt_bus + - const: core + + iommus: + maxItems: 1 + + interconnects: + maxItems: 2 + + interconnect-names: + maxItems: 2 + +patternProperties: + "^display-controller@[0-9a-f]+$": + type: object + properties: + compatible: + const: qcom,sm8250-dpu + + "^dsi@[0-9a-f]+$": + type: object + properties: + compatible: + const: qcom,mdss-dsi-ctrl + + "^phy@[0-9a-f]+$": + type: object + properties: + compatible: + const: qcom,dsi-phy-7nm + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + #include + #include + #include + + display-subsystem@ae00000 { + compatible = "qcom,sm8250-mdss"; + reg = <0x0ae00000 0x1000>; + reg-names = "mdss"; + + interconnects = <&mmss_noc MASTER_MDP_PORT0 &mc_virt SLAVE_EBI_CH0>, + <&mmss_noc MASTER_MDP_PORT1 &mc_virt SLAVE_EBI_CH0>; + interconnect-names = "mdp0-mem", "mdp1-mem"; + + power-domains = <&dispcc MDSS_GDSC>; + + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&gcc GCC_DISP_HF_AXI_CLK>, + <&gcc GCC_DISP_SF_AXI_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>; + clock-names = "iface", "bus", "nrt_bus", "core"; + + interrupts = ; + interrupt-controller; + #interrupt-cells = <1>; + + iommus = <&apps_smmu 0x820 0x402>; + + #address-cells = <1>; + #size-cells = <1>; + ranges; + + display-controller@ae01000 { + compatible = "qcom,sm8250-dpu"; + reg = <0x0ae01000 0x8f000>, + <0x0aeb0000 0x2008>; + reg-names = "mdp", "vbif"; + + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&gcc GCC_DISP_HF_AXI_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>, + <&dispcc DISP_CC_MDSS_VSYNC_CLK>; + clock-names = "iface", "bus", "core", "vsync"; + + assigned-clocks = <&dispcc DISP_CC_MDSS_VSYNC_CLK>; + assigned-clock-rates = <19200000>; + + operating-points-v2 = <&mdp_opp_table>; + power-domains = <&rpmhpd SM8250_MMCX>; + + interrupt-parent = <&mdss>; + interrupts = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dpu_intf1_out: endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; + + port@1 { + reg = <1>; + dpu_intf2_out: endpoint { + remote-endpoint = <&dsi1_in>; + }; + }; + }; + + mdp_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-345000000 { + opp-hz = /bits/ 64 <345000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-460000000 { + opp-hz = /bits/ 64 <460000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + dsi@ae94000 { + compatible = "qcom,mdss-dsi-ctrl"; + reg = <0x0ae94000 0x400>; + reg-names = "dsi_ctrl"; + + interrupt-parent = <&mdss>; + interrupts = <4>; + + clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK>, + <&dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>, + <&dispcc DISP_CC_MDSS_PCLK0_CLK>, + <&dispcc DISP_CC_MDSS_ESC0_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&gcc GCC_DISP_HF_AXI_CLK>; + clock-names = "byte", + "byte_intf", + "pixel", + "core", + "iface", + "bus"; + + assigned-clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>, + <&dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>; + assigned-clock-parents = <&dsi0_phy 0>, <&dsi0_phy 1>; + + operating-points-v2 = <&dsi_opp_table>; + power-domains = <&rpmhpd SM8250_MMCX>; + + phys = <&dsi0_phy>; + phy-names = "dsi"; + + #address-cells = <1>; + #size-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dsi0_in: endpoint { + remote-endpoint = <&dpu_intf1_out>; + }; + }; + + port@1 { + reg = <1>; + dsi0_out: endpoint { + }; + }; + }; + + dsi_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-187500000 { + opp-hz = /bits/ 64 <187500000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-358000000 { + opp-hz = /bits/ 64 <358000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + }; + }; + + dsi0_phy: phy@ae94400 { + compatible = "qcom,dsi-phy-7nm"; + reg = <0x0ae94400 0x200>, + <0x0ae94600 0x280>, + <0x0ae94900 0x260>; + reg-names = "dsi_phy", + "dsi_phy_lane", + "dsi_pll"; + + #clock-cells = <1>; + #phy-cells = <0>; + + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&rpmhcc RPMH_CXO_CLK>; + clock-names = "iface", "ref"; + vdds-supply = <&vreg_dsi_phy>; + }; + + dsi@ae96000 { + compatible = "qcom,mdss-dsi-ctrl"; + reg = <0x0ae96000 0x400>; + reg-names = "dsi_ctrl"; + + interrupt-parent = <&mdss>; + interrupts = <5>; + + clocks = <&dispcc DISP_CC_MDSS_BYTE1_CLK>, + <&dispcc DISP_CC_MDSS_BYTE1_INTF_CLK>, + <&dispcc DISP_CC_MDSS_PCLK1_CLK>, + <&dispcc DISP_CC_MDSS_ESC1_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&gcc GCC_DISP_HF_AXI_CLK>; + clock-names = "byte", + "byte_intf", + "pixel", + "core", + "iface", + "bus"; + + assigned-clocks = <&dispcc DISP_CC_MDSS_BYTE1_CLK_SRC>, + <&dispcc DISP_CC_MDSS_PCLK1_CLK_SRC>; + assigned-clock-parents = <&dsi1_phy 0>, <&dsi1_phy 1>; + + operating-points-v2 = <&dsi_opp_table>; + power-domains = <&rpmhpd SM8250_MMCX>; + + phys = <&dsi1_phy>; + phy-names = "dsi"; + + #address-cells = <1>; + #size-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dsi1_in: endpoint { + remote-endpoint = <&dpu_intf2_out>; + }; + }; + + port@1 { + reg = <1>; + dsi1_out: endpoint { + }; + }; + }; + }; + + dsi1_phy: phy@ae96400 { + compatible = "qcom,dsi-phy-7nm"; + reg = <0x0ae96400 0x200>, + <0x0ae96600 0x280>, + <0x0ae96900 0x260>; + reg-names = "dsi_phy", + "dsi_phy_lane", + "dsi_pll"; + + #clock-cells = <1>; + #phy-cells = <0>; + + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&rpmhcc RPMH_CXO_CLK>; + clock-names = "iface", "ref"; + vdds-supply = <&vreg_dsi_phy>; + }; + }; +... -- cgit From 1a5b5372e3b0a4cc65a0cbb724b1b0859f4ac63c Mon Sep 17 00:00:00 2001 From: Robert Foss Date: Fri, 28 Oct 2022 14:08:05 +0200 Subject: drm/msm/dpu: Refactor sc7280_pp location The sc7280_pp declaration is not located by the other _pp declarations, but rather hidden around the _merge_3d declarations. Let's fix this to avoid confusion. Signed-off-by: Robert Foss Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/509153/ Link: https://lore.kernel.org/r/20221028120812.339100-3-robert.foss@linaro.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c index bae3cc3adb3f..1ce237e18506 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c @@ -1178,6 +1178,13 @@ static const struct dpu_pingpong_cfg sm8150_pp[] = { -1), }; +static const struct dpu_pingpong_cfg sc7280_pp[] = { + PP_BLK("pingpong_0", PINGPONG_0, 0x59000, 0, sc7280_pp_sblk, -1, -1), + PP_BLK("pingpong_1", PINGPONG_1, 0x6a000, 0, sc7280_pp_sblk, -1, -1), + PP_BLK("pingpong_2", PINGPONG_2, 0x6b000, 0, sc7280_pp_sblk, -1, -1), + PP_BLK("pingpong_3", PINGPONG_3, 0x6c000, 0, sc7280_pp_sblk, -1, -1), +}; + static struct dpu_pingpong_cfg qcm2290_pp[] = { PP_BLK("pingpong_0", PINGPONG_0, 0x70000, 0, sdm845_pp_sblk, DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 8), @@ -1201,13 +1208,6 @@ static const struct dpu_merge_3d_cfg sm8150_merge_3d[] = { MERGE_3D_BLK("merge_3d_2", MERGE_3D_2, 0x83200), }; -static const struct dpu_pingpong_cfg sc7280_pp[] = { - PP_BLK("pingpong_0", PINGPONG_0, 0x59000, 0, sc7280_pp_sblk, -1, -1), - PP_BLK("pingpong_1", PINGPONG_1, 0x6a000, 0, sc7280_pp_sblk, -1, -1), - PP_BLK("pingpong_2", PINGPONG_2, 0x6b000, 0, sc7280_pp_sblk, -1, -1), - PP_BLK("pingpong_3", PINGPONG_3, 0x6c000, 0, sc7280_pp_sblk, -1, -1), -}; - /************************************************************* * DSC sub blocks config *************************************************************/ -- cgit From 0aeec60c76ca2631696b4228f3fc99fe3a80013d Mon Sep 17 00:00:00 2001 From: Niranjana Vishwanathapura Date: Tue, 1 Nov 2022 22:14:16 -0700 Subject: drm/i915: Do not set cache_dirty for DGFX Currently on DG1, which does not have LLC, we hit the below warning while rebinding an userptr invalidated object. WARNING: CPU: 4 PID: 13008 at drivers/gpu/drm/i915/gem/i915_gem_pages.c:34 __i915_gem_object_set_pages+0x296/0x2d0 [i915] ... RIP: 0010:__i915_gem_object_set_pages+0x296/0x2d0 [i915] ... Call Trace: i915_gem_userptr_get_pages+0x175/0x1a0 [i915] ____i915_gem_object_get_pages+0x32/0xb0 [i915] i915_gem_object_userptr_submit_init+0x286/0x470 [i915] eb_lookup_vmas+0x2ff/0xcf0 [i915] ? __intel_wakeref_get_first+0x55/0xb0 [i915] i915_gem_do_execbuffer+0x785/0x21d0 [i915] i915_gem_execbuffer2_ioctl+0xe7/0x3d0 [i915] We shouldn't be setting the obj->cache_dirty for DGFX, fix it. Fixes: d70af57944a1 ("drm/i915/shmem: ensure flush during swap-in on non-LLC") Suggested-by: Matthew Auld Reported-by: Niranjana Vishwanathapura Signed-off-by: Niranjana Vishwanathapura Acked-by: Nirmoy Das Reviewed-by: Matthew Auld Reviewed-by: Andi Shyti Signed-off-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20221102051416.27327-1-niranjana.vishwanathapura@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_shmem.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c index 11125c32dd35..2f7804492cd5 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c @@ -369,14 +369,14 @@ __i915_gem_object_release_shmem(struct drm_i915_gem_object *obj, __start_cpu_write(obj); /* - * On non-LLC platforms, force the flush-on-acquire if this is ever + * On non-LLC igfx platforms, force the flush-on-acquire if this is ever * swapped-in. Our async flush path is not trust worthy enough yet(and * happens in the wrong order), and with some tricks it's conceivable * for userspace to change the cache-level to I915_CACHE_NONE after the * pages are swapped-in, and since execbuf binds the object before doing * the async flush, we have a race window. */ - if (!HAS_LLC(i915)) + if (!HAS_LLC(i915) && !IS_DGFX(i915)) obj->cache_dirty = true; } -- cgit From b964444b2b64ce182495731d830499d1c588ccf6 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 26 Aug 2022 12:39:23 +0300 Subject: drm/msm/hdmi: use devres helper for runtime PM management Use devm_pm_runtime_enable() to enable runtime PM. This way its effect will be reverted on device unbind/destruction. Fixes: 6ed9ed484d04 ("drm/msm/hdmi: Set up runtime PM for HDMI") Signed-off-by: Dmitry Baryshkov Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/499647/ Link: https://lore.kernel.org/r/20220826093927.851597-2-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/hdmi/hdmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index f28fb21e3891..8cd5d50639a5 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -252,7 +252,7 @@ static struct hdmi *msm_hdmi_init(struct platform_device *pdev) if (hdmi->hpd_gpiod) gpiod_set_consumer_name(hdmi->hpd_gpiod, "HDMI_HPD"); - pm_runtime_enable(&pdev->dev); + devm_pm_runtime_enable(&pdev->dev); hdmi->workq = alloc_ordered_workqueue("msm_hdmi", 0); -- cgit From f6cb1430bb32c1daec49fc9067a0bc2f03d02ed4 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 26 Aug 2022 12:39:24 +0300 Subject: drm/msm/hdmi: drop constant resource names from platform config All MSM HDMI devices use "core_physical" and "qfprom_physical" names for register areas. Drop them from the platform config. Signed-off-by: Dmitry Baryshkov Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/499646/ Link: https://lore.kernel.org/r/20220826093927.851597-3-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/hdmi/hdmi.c | 9 +++------ drivers/gpu/drm/msm/hdmi/hdmi.h | 3 --- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index 8cd5d50639a5..6bb237bd3ab8 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -138,7 +138,7 @@ static struct hdmi *msm_hdmi_init(struct platform_device *pdev) if (ret && ret != -ENODEV) goto fail; - hdmi->mmio = msm_ioremap(pdev, config->mmio_name); + hdmi->mmio = msm_ioremap(pdev, "core_physical"); if (IS_ERR(hdmi->mmio)) { ret = PTR_ERR(hdmi->mmio); goto fail; @@ -146,14 +146,14 @@ static struct hdmi *msm_hdmi_init(struct platform_device *pdev) /* HDCP needs physical address of hdmi register */ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - config->mmio_name); + "core_physical"); if (!res) { ret = -EINVAL; goto fail; } hdmi->mmio_phy_addr = res->start; - hdmi->qfprom_mmio = msm_ioremap(pdev, config->qfprom_mmio_name); + hdmi->qfprom_mmio = msm_ioremap(pdev, "qfprom_physical"); if (IS_ERR(hdmi->qfprom_mmio)) { DRM_DEV_INFO(&pdev->dev, "can't find qfprom resource\n"); hdmi->qfprom_mmio = NULL; @@ -529,9 +529,6 @@ static int msm_hdmi_bind(struct device *dev, struct device *master, void *data) return -ENXIO; } - hdmi_cfg->mmio_name = "core_physical"; - hdmi_cfg->qfprom_mmio_name = "qfprom_physical"; - dev->platform_data = hdmi_cfg; hdmi = msm_hdmi_init(to_platform_device(dev)); diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h index 04a74381aaf7..e8dbee50637f 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.h +++ b/drivers/gpu/drm/msm/hdmi/hdmi.h @@ -86,9 +86,6 @@ struct hdmi { /* platform config data (ie. from DT, or pdata) */ struct hdmi_platform_config { - const char *mmio_name; - const char *qfprom_mmio_name; - /* regulators that need to be on for hpd: */ const char **hpd_reg_names; int hpd_reg_cnt; -- cgit From 3236130b5d2a2d868b8273d7e2fff4bbde4be813 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 2 Nov 2022 20:54:48 +0300 Subject: drm/msm: move domain allocation into msm_iommu_new() After the msm_iommu instance is created, the IOMMU domain is completely handled inside the msm_iommu code. Move the iommu_domain_alloc() call into the msm_iommu_new() to simplify callers code. Reported-by: kernel test robot Signed-off-by: Dmitry Baryshkov Reviewed-by: Rob Clark Patchwork: https://patchwork.freedesktop.org/patch/509615/ Link: https://lore.kernel.org/r/20221102175449.452283-2-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 12 +++++------- drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 23 +++++++++++------------ drivers/gpu/drm/msm/adreno/adreno_gpu.c | 25 +++++++++---------------- drivers/gpu/drm/msm/adreno/adreno_gpu.h | 2 -- drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c | 19 ++++++++++--------- drivers/gpu/drm/msm/msm_drv.c | 18 ++++++++---------- drivers/gpu/drm/msm/msm_iommu.c | 20 +++++++++++++++++--- drivers/gpu/drm/msm/msm_mmu.h | 3 ++- 8 files changed, 62 insertions(+), 60 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c index e033d6a67a20..6484b97c5344 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c @@ -1213,19 +1213,17 @@ static int a6xx_gmu_memory_alloc(struct a6xx_gmu *gmu, struct a6xx_gmu_bo *bo, static int a6xx_gmu_memory_probe(struct a6xx_gmu *gmu) { - struct iommu_domain *domain; struct msm_mmu *mmu; - domain = iommu_domain_alloc(&platform_bus_type); - if (!domain) + mmu = msm_iommu_new(gmu->dev, 0); + if (!mmu) return -ENODEV; + if (IS_ERR(mmu)) + return PTR_ERR(mmu); - mmu = msm_iommu_new(gmu->dev, domain); gmu->aspace = msm_gem_address_space_create(mmu, "gmu", 0x0, 0x80000000); - if (IS_ERR(gmu->aspace)) { - iommu_domain_free(domain); + if (IS_ERR(gmu->aspace)) return PTR_ERR(gmu->aspace); - } return 0; } diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c index fdc578016e0b..db4b3a48c708 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c @@ -1786,35 +1786,34 @@ a6xx_create_address_space(struct msm_gpu *gpu, struct platform_device *pdev) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); - struct iommu_domain *iommu; + struct iommu_domain_geometry *geometry; struct msm_mmu *mmu; struct msm_gem_address_space *aspace; u64 start, size; - - iommu = iommu_domain_alloc(&platform_bus_type); - if (!iommu) - return NULL; + unsigned long quirks = 0; /* * This allows GPU to set the bus attributes required to use system * cache on behalf of the iommu page table walker. */ if (!IS_ERR_OR_NULL(a6xx_gpu->htw_llc_slice)) - adreno_set_llc_attributes(iommu); + quirks |= IO_PGTABLE_QUIRK_ARM_OUTER_WBWA; - mmu = msm_iommu_new(&pdev->dev, iommu); - if (IS_ERR(mmu)) { - iommu_domain_free(iommu); + mmu = msm_iommu_new(&pdev->dev, quirks); + if (IS_ERR_OR_NULL(mmu)) return ERR_CAST(mmu); - } + + geometry = msm_iommu_get_geometry(mmu); + if (IS_ERR(geometry)) + return ERR_CAST(geometry); /* * Use the aperture start or SZ_16M, whichever is greater. This will * ensure that we align with the allocated pagetable range while still * allowing room in the lower 32 bits for GMEM and whatnot */ - start = max_t(u64, SZ_16M, iommu->geometry.aperture_start); - size = iommu->geometry.aperture_end - start + 1; + start = max_t(u64, SZ_16M, geometry->aperture_start); + size = geometry->aperture_end - start + 1; aspace = msm_gem_address_space_create(mmu, "gpu", start & GENMASK_ULL(48, 0), size); diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 5a0e8491cd3a..fb86ae0f19ad 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -191,37 +191,30 @@ int adreno_zap_shader_load(struct msm_gpu *gpu, u32 pasid) return zap_shader_load_mdt(gpu, adreno_gpu->info->zapfw, pasid); } -void adreno_set_llc_attributes(struct iommu_domain *iommu) -{ - iommu_set_pgtable_quirks(iommu, IO_PGTABLE_QUIRK_ARM_OUTER_WBWA); -} - struct msm_gem_address_space * adreno_iommu_create_address_space(struct msm_gpu *gpu, struct platform_device *pdev) { - struct iommu_domain *iommu; + struct iommu_domain_geometry *geometry; struct msm_mmu *mmu; struct msm_gem_address_space *aspace; u64 start, size; - iommu = iommu_domain_alloc(&platform_bus_type); - if (!iommu) - return NULL; - - mmu = msm_iommu_new(&pdev->dev, iommu); - if (IS_ERR(mmu)) { - iommu_domain_free(iommu); + mmu = msm_iommu_new(&pdev->dev, 0); + if (IS_ERR_OR_NULL(mmu)) return ERR_CAST(mmu); - } + + geometry = msm_iommu_get_geometry(mmu); + if (IS_ERR(geometry)) + return ERR_CAST(geometry); /* * Use the aperture start or SZ_16M, whichever is greater. This will * ensure that we align with the allocated pagetable range while still * allowing room in the lower 32 bits for GMEM and whatnot */ - start = max_t(u64, SZ_16M, iommu->geometry.aperture_start); - size = iommu->geometry.aperture_end - start + 1; + start = max_t(u64, SZ_16M, geometry->aperture_start); + size = geometry->aperture_end - start + 1; aspace = msm_gem_address_space_create(mmu, "gpu", start & GENMASK_ULL(48, 0), size); diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index e7adc5c632d0..707273339969 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -338,8 +338,6 @@ struct msm_gem_address_space * adreno_iommu_create_address_space(struct msm_gpu *gpu, struct platform_device *pdev); -void adreno_set_llc_attributes(struct iommu_domain *iommu); - int adreno_read_speedbin(struct device *dev, u32 *speedbin); /* diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c index 964573d26d26..9a1a0769575d 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c @@ -387,7 +387,7 @@ static int mdp4_kms_init(struct drm_device *dev) struct msm_drm_private *priv = dev->dev_private; struct mdp4_kms *mdp4_kms; struct msm_kms *kms = NULL; - struct iommu_domain *iommu; + struct msm_mmu *mmu; struct msm_gem_address_space *aspace; int irq, ret; u32 major, minor; @@ -499,10 +499,15 @@ static int mdp4_kms_init(struct drm_device *dev) mdp4_disable(mdp4_kms); mdelay(16); - iommu = iommu_domain_alloc(pdev->dev.bus); - if (iommu) { - struct msm_mmu *mmu = msm_iommu_new(&pdev->dev, iommu); - + mmu = msm_iommu_new(&pdev->dev, 0); + if (IS_ERR(mmu)) { + ret = PTR_ERR(mmu); + goto fail; + } else if (!mmu) { + DRM_DEV_INFO(dev->dev, "no iommu, fallback to phys " + "contig buffers for scanout\n"); + aspace = NULL; + } else { aspace = msm_gem_address_space_create(mmu, "mdp4", 0x1000, 0x100000000 - 0x1000); @@ -514,10 +519,6 @@ static int mdp4_kms_init(struct drm_device *dev) } kms->aspace = aspace; - } else { - DRM_DEV_INFO(dev->dev, "no iommu, fallback to phys " - "contig buffers for scanout\n"); - aspace = NULL; } ret = modeset_init(mdp4_kms); diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 862b60a5e886..cffba9ca7ec2 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -277,7 +277,6 @@ static int msm_drm_uninit(struct device *dev) struct msm_gem_address_space *msm_kms_init_aspace(struct drm_device *dev) { - struct iommu_domain *domain; struct msm_gem_address_space *aspace; struct msm_mmu *mmu; struct device *mdp_dev = dev->dev; @@ -293,22 +292,21 @@ struct msm_gem_address_space *msm_kms_init_aspace(struct drm_device *dev) else iommu_dev = mdss_dev; - domain = iommu_domain_alloc(iommu_dev->bus); - if (!domain) { + mmu = msm_iommu_new(iommu_dev, 0); + if (IS_ERR(mmu)) + return ERR_CAST(mmu); + + if (!mmu) { drm_info(dev, "no IOMMU, fallback to phys contig buffers for scanout\n"); return NULL; } - mmu = msm_iommu_new(iommu_dev, domain); - if (IS_ERR(mmu)) { - iommu_domain_free(domain); - return ERR_CAST(mmu); - } - aspace = msm_gem_address_space_create(mmu, "mdp_kms", 0x1000, 0x100000000 - 0x1000); - if (IS_ERR(aspace)) + if (IS_ERR(aspace)) { + dev_err(mdp_dev, "aspace create, error %pe\n", aspace); mmu->funcs->destroy(mmu); + } return aspace; } diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c index 5577cea7c009..c2507582ecf3 100644 --- a/drivers/gpu/drm/msm/msm_iommu.c +++ b/drivers/gpu/drm/msm/msm_iommu.c @@ -186,6 +186,13 @@ int msm_iommu_pagetable_params(struct msm_mmu *mmu, return 0; } +struct iommu_domain_geometry *msm_iommu_get_geometry(struct msm_mmu *mmu) +{ + struct msm_iommu *iommu = to_msm_iommu(mmu); + + return &iommu->domain->geometry; +} + static const struct msm_mmu_funcs pagetable_funcs = { .map = msm_iommu_pagetable_map, .unmap = msm_iommu_pagetable_unmap, @@ -367,17 +374,23 @@ static const struct msm_mmu_funcs funcs = { .resume_translation = msm_iommu_resume_translation, }; -struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain) +struct msm_mmu *msm_iommu_new(struct device *dev, unsigned long quirks) { + struct iommu_domain *domain; struct msm_iommu *iommu; int ret; + domain = iommu_domain_alloc(dev->bus); if (!domain) - return ERR_PTR(-ENODEV); + return NULL; + + iommu_set_pgtable_quirks(domain, quirks); iommu = kzalloc(sizeof(*iommu), GFP_KERNEL); - if (!iommu) + if (!iommu) { + iommu_domain_free(domain); return ERR_PTR(-ENOMEM); + } iommu->domain = domain; msm_mmu_init(&iommu->base, dev, &funcs, MSM_MMU_IOMMU); @@ -386,6 +399,7 @@ struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain) ret = iommu_attach_device(iommu->domain, dev); if (ret) { + iommu_domain_free(domain); kfree(iommu); return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/msm/msm_mmu.h b/drivers/gpu/drm/msm/msm_mmu.h index de158e1bf765..74cd81e701ff 100644 --- a/drivers/gpu/drm/msm/msm_mmu.h +++ b/drivers/gpu/drm/msm/msm_mmu.h @@ -40,7 +40,7 @@ static inline void msm_mmu_init(struct msm_mmu *mmu, struct device *dev, mmu->type = type; } -struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain); +struct msm_mmu *msm_iommu_new(struct device *dev, unsigned long quirks); struct msm_mmu *msm_gpummu_new(struct device *dev, struct msm_gpu *gpu); static inline void msm_mmu_set_fault_handler(struct msm_mmu *mmu, void *arg, @@ -58,5 +58,6 @@ void msm_gpummu_params(struct msm_mmu *mmu, dma_addr_t *pt_base, int msm_iommu_pagetable_params(struct msm_mmu *mmu, phys_addr_t *ttbr, int *asid); +struct iommu_domain_geometry *msm_iommu_get_geometry(struct msm_mmu *mmu); #endif /* __MSM_MMU_H__ */ -- cgit From 822ff993d33dc4bad2bbc05faf4b48790ec8195a Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 2 Nov 2022 20:54:49 +0300 Subject: drm/msm: remove duplicated code from a6xx_create_address_space The function a6xx_create_address_space() is mostly a copy of adreno_iommu_create_address_space() with added quirk setting. Rework these two functions to be a thin wrappers around a common helper. Signed-off-by: Dmitry Baryshkov Reviewed-by: Rob Clark Patchwork: https://patchwork.freedesktop.org/patch/509614/ Link: https://lore.kernel.org/r/20221102175449.452283-3-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/adreno/a3xx_gpu.c | 2 +- drivers/gpu/drm/msm/adreno/a4xx_gpu.c | 2 +- drivers/gpu/drm/msm/adreno/a5xx_gpu.c | 2 +- drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 28 +--------------------------- drivers/gpu/drm/msm/adreno/adreno_gpu.c | 12 ++++++++++-- drivers/gpu/drm/msm/adreno/adreno_gpu.h | 7 ++++++- 6 files changed, 20 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c index 2c8b9899625b..948785ed07bb 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c @@ -500,7 +500,7 @@ static const struct adreno_gpu_funcs funcs = { #endif .gpu_state_get = a3xx_gpu_state_get, .gpu_state_put = adreno_gpu_state_put, - .create_address_space = adreno_iommu_create_address_space, + .create_address_space = adreno_create_address_space, .get_rptr = a3xx_get_rptr, }, }; diff --git a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c index 7cb8d9849c07..2fb32d5552c4 100644 --- a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c @@ -635,7 +635,7 @@ static const struct adreno_gpu_funcs funcs = { #endif .gpu_state_get = a4xx_gpu_state_get, .gpu_state_put = adreno_gpu_state_put, - .create_address_space = adreno_iommu_create_address_space, + .create_address_space = adreno_create_address_space, .get_rptr = a4xx_get_rptr, }, .get_timestamp = a4xx_get_timestamp, diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c index 3dcec7acb384..3c537c0016fa 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c @@ -1705,7 +1705,7 @@ static const struct adreno_gpu_funcs funcs = { .gpu_busy = a5xx_gpu_busy, .gpu_state_get = a5xx_gpu_state_get, .gpu_state_put = a5xx_gpu_state_put, - .create_address_space = adreno_iommu_create_address_space, + .create_address_space = adreno_create_address_space, .get_rptr = a5xx_get_rptr, }, .get_timestamp = a5xx_get_timestamp, diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c index db4b3a48c708..e87196457b9a 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c @@ -1786,10 +1786,6 @@ a6xx_create_address_space(struct msm_gpu *gpu, struct platform_device *pdev) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); - struct iommu_domain_geometry *geometry; - struct msm_mmu *mmu; - struct msm_gem_address_space *aspace; - u64 start, size; unsigned long quirks = 0; /* @@ -1799,29 +1795,7 @@ a6xx_create_address_space(struct msm_gpu *gpu, struct platform_device *pdev) if (!IS_ERR_OR_NULL(a6xx_gpu->htw_llc_slice)) quirks |= IO_PGTABLE_QUIRK_ARM_OUTER_WBWA; - mmu = msm_iommu_new(&pdev->dev, quirks); - if (IS_ERR_OR_NULL(mmu)) - return ERR_CAST(mmu); - - geometry = msm_iommu_get_geometry(mmu); - if (IS_ERR(geometry)) - return ERR_CAST(geometry); - - /* - * Use the aperture start or SZ_16M, whichever is greater. This will - * ensure that we align with the allocated pagetable range while still - * allowing room in the lower 32 bits for GMEM and whatnot - */ - start = max_t(u64, SZ_16M, geometry->aperture_start); - size = geometry->aperture_end - start + 1; - - aspace = msm_gem_address_space_create(mmu, "gpu", - start & GENMASK_ULL(48, 0), size); - - if (IS_ERR(aspace) && !IS_ERR(mmu)) - mmu->funcs->destroy(mmu); - - return aspace; + return adreno_iommu_create_address_space(gpu, pdev, quirks); } static struct msm_gem_address_space * diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index fb86ae0f19ad..57586c794b84 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -191,16 +191,24 @@ int adreno_zap_shader_load(struct msm_gpu *gpu, u32 pasid) return zap_shader_load_mdt(gpu, adreno_gpu->info->zapfw, pasid); } +struct msm_gem_address_space * +adreno_create_address_space(struct msm_gpu *gpu, + struct platform_device *pdev) +{ + return adreno_iommu_create_address_space(gpu, pdev, 0); +} + struct msm_gem_address_space * adreno_iommu_create_address_space(struct msm_gpu *gpu, - struct platform_device *pdev) + struct platform_device *pdev, + unsigned long quirks) { struct iommu_domain_geometry *geometry; struct msm_mmu *mmu; struct msm_gem_address_space *aspace; u64 start, size; - mmu = msm_iommu_new(&pdev->dev, 0); + mmu = msm_iommu_new(&pdev->dev, quirks); if (IS_ERR_OR_NULL(mmu)) return ERR_CAST(mmu); diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index 707273339969..5d4b1c95033f 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -335,8 +335,13 @@ void adreno_show_object(struct drm_printer *p, void **ptr, int len, * attached targets */ struct msm_gem_address_space * +adreno_create_address_space(struct msm_gpu *gpu, + struct platform_device *pdev); + +struct msm_gem_address_space * adreno_iommu_create_address_space(struct msm_gpu *gpu, - struct platform_device *pdev); + struct platform_device *pdev, + unsigned long quirks); int adreno_read_speedbin(struct device *dev, u32 *speedbin); -- cgit From 8f956e9a2c9bdb22ac50c8b7656e2ea29c2e656c Mon Sep 17 00:00:00 2001 From: Gwan-gyeong Mun Date: Sat, 29 Oct 2022 07:42:30 +0300 Subject: drm/i915/hwmon: Fix a build error used with clang compiler Use REG_FIELD_PREP() and a constant value for hwm_field_scale_and_write() If the first argument of FIELD_PREP() is not a compile-time constant value or unsigned long long type, this routine of the __BF_FIELD_CHECK() macro used internally by the FIELD_PREP() macro always returns false. BUILD_BUG_ON_MSG(__bf_cast_unsigned(_mask, _mask) > \ __bf_cast_unsigned(_reg, ~0ull), \ _pfx "type of reg too small for mask"); \ And it returns a build error by the option among the clang compilation options. [-Werror,-Wtautological-constant-out-of-range-compare] Reported build error while using clang compiler: drivers/gpu/drm/i915/i915_hwmon.c:115:16: error: result of comparison of constant 18446744073709551615 with expression of type 'typeof (_Generic((field_msk), char: (unsigned char)0, unsigned char: (unsigned char)0, signed char: (unsigned char)0, unsigned short: (unsigned short)0, short: (unsigned short)0, unsigned int: (unsigned int)0, int: (unsigned int)0, unsigned long: (unsigned long)0, long: (unsigned long)0, unsigned long long: (unsigned long long)0, long long: (unsigned long long)0, default: (field_msk)))' (aka 'unsigned int') is always false [-Werror,-Wtautological-constant-out-of-range-compare] bits_to_set = FIELD_PREP(field_msk, nval); ^~~~~~~~~~~~~~~~~~~~~~~~~~~ ./include/linux/bitfield.h:114:3: note: expanded from macro 'FIELD_PREP' __BF_FIELD_CHECK(_mask, 0ULL, _val, "FIELD_PREP: "); \ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ./include/linux/bitfield.h:71:53: note: expanded from macro '__BF_FIELD_CHECK' BUILD_BUG_ON_MSG(__bf_cast_unsigned(_mask, _mask) > \ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~ ./include/linux/build_bug.h:39:58: note: expanded from macro 'BUILD_BUG_ON_MSG' ~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~ ./include/linux/compiler_types.h:357:22: note: expanded from macro 'compiletime_assert' _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__) ~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ./include/linux/compiler_types.h:345:23: note: expanded from macro '_compiletime_assert' __compiletime_assert(condition, msg, prefix, suffix) ~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ./include/linux/compiler_types.h:337:9: note: expanded from macro '__compiletime_assert' if (!(condition)) \ v2: Use REG_FIELD_PREP() macro instead of FIELD_PREP() (Jani) Fixes: 99f55efb7911 ("drm/i915/hwmon: Power PL1 limit and TDP setting") Cc: Ashutosh Dixit Cc: Anshuman Gupta Cc: Andi Shyti Cc: Jani Nikula Signed-off-by: Gwan-gyeong Mun Reviewed-by: Ashutosh Dixit Acked-by: Jani Nikula [Joonas: Wrapped commit message error line length to be more reasonable] Signed-off-by: Joonas Lahtinen Link: https://patchwork.freedesktop.org/patch/msgid/20221029044230.32128-1-gwan-gyeong.mun@intel.com --- drivers/gpu/drm/i915/i915_hwmon.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_hwmon.c b/drivers/gpu/drm/i915/i915_hwmon.c index 9e9781493025..c588a17f97e9 100644 --- a/drivers/gpu/drm/i915/i915_hwmon.c +++ b/drivers/gpu/drm/i915/i915_hwmon.c @@ -101,21 +101,16 @@ hwm_field_read_and_scale(struct hwm_drvdata *ddat, i915_reg_t rgadr, static void hwm_field_scale_and_write(struct hwm_drvdata *ddat, i915_reg_t rgadr, - u32 field_msk, int nshift, - unsigned int scale_factor, long lval) + int nshift, unsigned int scale_factor, long lval) { u32 nval; - u32 bits_to_clear; - u32 bits_to_set; /* Computation in 64-bits to avoid overflow. Round to nearest. */ nval = DIV_ROUND_CLOSEST_ULL((u64)lval << nshift, scale_factor); - bits_to_clear = field_msk; - bits_to_set = FIELD_PREP(field_msk, nval); - hwm_locked_with_pm_intel_uncore_rmw(ddat, rgadr, - bits_to_clear, bits_to_set); + PKG_PWR_LIM_1, + REG_FIELD_PREP(PKG_PWR_LIM_1, nval)); } /* @@ -406,7 +401,6 @@ hwm_power_write(struct hwm_drvdata *ddat, u32 attr, int chan, long val) case hwmon_power_max: hwm_field_scale_and_write(ddat, hwmon->rg.pkg_rapl_limit, - PKG_PWR_LIM_1, hwmon->scl_shift_power, SF_POWER, val); return 0; -- cgit From 6c4e4d35203301906afb53c6d1e1302d4c793c05 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Wed, 2 Nov 2022 08:52:42 -0700 Subject: drm/meson: Fix return type of meson_encoder_cvbs_mode_valid() With clang's kernel control flow integrity (kCFI, CONFIG_CFI_CLANG), indirect call targets are validated against the expected function pointer prototype to make sure the call target is valid to help mitigate ROP attacks. If they are not identical, there is a failure at run time, which manifests as either a kernel panic or thread getting killed. A proposed warning in clang aims to catch these at compile time, which reveals: drivers/gpu/drm/meson/meson_encoder_cvbs.c:211:16: error: incompatible function pointer types initializing 'enum drm_mode_status (*)(struct drm_bridge *, const struct drm_display_info *, const struct drm_display_mode *)' with an expression of type 'int (struct drm_bridge *, const struct drm_display_info *, const struct drm_display_mode *)' [-Werror,-Wincompatible-function-pointer-types-strict] .mode_valid = meson_encoder_cvbs_mode_valid, ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1 error generated. ->mode_valid() in 'struct drm_bridge_funcs' expects a return type of 'enum drm_mode_status', not 'int'. Adjust the return type of meson_encoder_cvbs_mode_valid() to match the prototype's to resolve the warning and CFI failure. Link: https://github.com/ClangBuiltLinux/linux/issues/1750 Reported-by: Sami Tolvanen Signed-off-by: Nathan Chancellor Reviewed-by: Kees Cook Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20221102155242.1927166-1-nathan@kernel.org --- drivers/gpu/drm/meson/meson_encoder_cvbs.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/meson/meson_encoder_cvbs.c b/drivers/gpu/drm/meson/meson_encoder_cvbs.c index 5675bc2a92cf..3f73b211fa8e 100644 --- a/drivers/gpu/drm/meson/meson_encoder_cvbs.c +++ b/drivers/gpu/drm/meson/meson_encoder_cvbs.c @@ -116,9 +116,10 @@ static int meson_encoder_cvbs_get_modes(struct drm_bridge *bridge, return i; } -static int meson_encoder_cvbs_mode_valid(struct drm_bridge *bridge, - const struct drm_display_info *display_info, - const struct drm_display_mode *mode) +static enum drm_mode_status +meson_encoder_cvbs_mode_valid(struct drm_bridge *bridge, + const struct drm_display_info *display_info, + const struct drm_display_mode *mode) { if (meson_cvbs_get_mode(mode)) return MODE_OK; -- cgit From 639325e4269750fbd3ccc2c4beb7e5cc40e2c4fd Mon Sep 17 00:00:00 2001 From: Vinod Govindapillai Date: Tue, 11 Oct 2022 12:30:48 +0300 Subject: drm/i915: update DSC feature flag handling during device init DSC feature information is no longer part of the DFSM register in some display generations. Bspec:50075 Signed-off-by: Vinod Govindapillai Reviewed-by: Stanislav Lisovskiy Signed-off-by: Stanislav Lisovskiy Link: https://patchwork.freedesktop.org/patch/msgid/20221011093048.447177-1-vinod.govindapillai@intel.com --- drivers/gpu/drm/i915/intel_device_info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_device_info.c b/drivers/gpu/drm/i915/intel_device_info.c index 1dc1fb29a776..e0cc0227b4d7 100644 --- a/drivers/gpu/drm/i915/intel_device_info.c +++ b/drivers/gpu/drm/i915/intel_device_info.c @@ -488,7 +488,7 @@ void intel_device_info_runtime_init(struct drm_i915_private *dev_priv) if (DISPLAY_VER(dev_priv) >= 11 && (dfsm & ICL_DFSM_DMC_DISABLE)) runtime->has_dmc = 0; - if (DISPLAY_VER(dev_priv) >= 10 && + if (IS_DISPLAY_VER(dev_priv, 10, 12) && (dfsm & GLK_DFSM_DISPLAY_DSC_DISABLE)) runtime->has_dsc = 0; } -- cgit From 5345b86c2aafab6c686ce46715f42ddc937cb0b4 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 1 Nov 2022 11:40:49 +0100 Subject: drm/ofdrm: Depend on CONFIG_MMU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a dependency on CONFIG_MMU to ofdrm. The driver uses GEM SHMEM helpers, which require MMU support. A reported error message [1] is shown below. arm-linux-gnueabi-ld: drivers/gpu/drm/drm_gem_shmem_helper.o: in function `drm_gem_shmem_fault': >> drivers/gpu/drm/drm_gem_shmem_helper.c:562: undefined reference to `vmf_insert_pfn' Reported-by: kernel test robot Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Fixes: c8a17756c425 ("drm/ofdrm: Add ofdrm for Open Firmware framebuffers") Cc: Thomas Zimmermann Cc: Javier Martinez Canillas Cc: Sam Ravnborg Cc: Maxime Ripard Cc: "Noralf Trønnes" Cc: Danilo Krummrich Cc: Michal Suchanek Cc: Daniel Vetter Link: https://lore.kernel.org/dri-devel/202210192029.ZFeJvqjv-lkp@intel.com/ # [1] Link: https://patchwork.freedesktop.org/patch/msgid/20221101104049.15601-1-tzimmermann@suse.de --- drivers/gpu/drm/tiny/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tiny/Kconfig b/drivers/gpu/drm/tiny/Kconfig index a300b03a3c7a..f6889f649bc1 100644 --- a/drivers/gpu/drm/tiny/Kconfig +++ b/drivers/gpu/drm/tiny/Kconfig @@ -53,7 +53,7 @@ config DRM_GM12U320 config DRM_OFDRM tristate "Open Firmware display driver" - depends on DRM && OF && (PPC || COMPILE_TEST) + depends on DRM && MMU && OF && (PPC || COMPILE_TEST) select APERTURE_HELPERS select DRM_GEM_SHMEM_HELPER select DRM_KMS_HELPER -- cgit From 6f85403ef4d0034fff11c77ed170aa2130329544 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 2 Nov 2022 16:57:09 +0100 Subject: drm/i915/selftests: Reduce oversaturation of request smoketesting The goal in launching the request smoketest is to have sufficient tasks running across the system such that we are likely to detect concurrency issues. We aim to have 2 tasks using the same engine, gt, device (each level of locking around submission and signaling) running at the same time. While tasks may not be running all the time as they synchronise with the gpu, they will be running most of the time, in which case having many more tasks than cores available is wasteful (and dramatically increases the workload causing excess runtime). Aim to limit the number of tasks such that there is at least 2 running per engine, spreading surplus cores around the engines (rather than running a task per core per engine.) Signed-off-by: Chris Wilson Reviewed-by: Nirmoy Das Tested-by: Nirmoy Das Signed-off-by: Nirmoy Das Reviewed-by: Tvrtko Ursulin Signed-off-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/20221102155709.31717-1-nirmoy.das@intel.com --- drivers/gpu/drm/i915/selftests/i915_request.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/selftests/i915_request.c b/drivers/gpu/drm/i915/selftests/i915_request.c index a46350c37e9d..4380473ceb98 100644 --- a/drivers/gpu/drm/i915/selftests/i915_request.c +++ b/drivers/gpu/drm/i915/selftests/i915_request.c @@ -1710,7 +1710,8 @@ static int live_breadcrumbs_smoketest(void *arg) { struct drm_i915_private *i915 = arg; const unsigned int nengines = num_uabi_engines(i915); - const unsigned int ncpus = num_online_cpus(); + const unsigned int ncpus = /* saturate with nengines * ncpus */ + max_t(int, 2, DIV_ROUND_UP(num_online_cpus(), nengines)); unsigned long num_waits, num_fences; struct intel_engine_cs *engine; struct smoke_thread *threads; @@ -1782,7 +1783,7 @@ static int live_breadcrumbs_smoketest(void *arg) goto out_flush; } /* One ring interleaved between requests from all cpus */ - smoke[idx].max_batch /= num_online_cpus() + 1; + smoke[idx].max_batch /= ncpus + 1; pr_debug("Limiting batches to %d requests on %s\n", smoke[idx].max_batch, engine->name); -- cgit From 4d5230b50dd42afa2dfa6b13c44b0d90ecb78510 Mon Sep 17 00:00:00 2001 From: Christian König Date: Wed, 28 Sep 2022 10:17:40 +0200 Subject: drm/scheduler: add drm_sched_job_add_resv_dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a new function to update job dependencies from a resv obj. Signed-off-by: Christian König Reviewed-by: Luben Tuikov Link: https://patchwork.freedesktop.org/patch/msgid/20221014084641.128280-3-christian.koenig@amd.com --- drivers/gpu/drm/scheduler/sched_main.c | 49 +++++++++++++++++++++++----------- include/drm/gpu_scheduler.h | 5 ++++ 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index d0ff9e11cb69..6e17cdbe27c2 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -773,32 +773,28 @@ int drm_sched_job_add_dependency(struct drm_sched_job *job, EXPORT_SYMBOL(drm_sched_job_add_dependency); /** - * drm_sched_job_add_implicit_dependencies - adds implicit dependencies as job - * dependencies + * drm_sched_job_add_resv_dependencies - add all fences from the resv to the job * @job: scheduler job to add the dependencies to - * @obj: the gem object to add new dependencies from. - * @write: whether the job might write the object (so we need to depend on - * shared fences in the reservation object). + * @resv: the dma_resv object to get the fences from + * @usage: the dma_resv_usage to use to filter the fences * - * This should be called after drm_gem_lock_reservations() on your array of - * GEM objects used in the job but before updating the reservations with your - * own fences. + * This adds all fences matching the given usage from @resv to @job. + * Must be called with the @resv lock held. * * Returns: * 0 on success, or an error on failing to expand the array. */ -int drm_sched_job_add_implicit_dependencies(struct drm_sched_job *job, - struct drm_gem_object *obj, - bool write) +int drm_sched_job_add_resv_dependencies(struct drm_sched_job *job, + struct dma_resv *resv, + enum dma_resv_usage usage) { struct dma_resv_iter cursor; struct dma_fence *fence; int ret; - dma_resv_assert_held(obj->resv); + dma_resv_assert_held(resv); - dma_resv_for_each_fence(&cursor, obj->resv, dma_resv_usage_rw(write), - fence) { + dma_resv_for_each_fence(&cursor, resv, usage, fence) { /* Make sure to grab an additional ref on the added fence */ dma_fence_get(fence); ret = drm_sched_job_add_dependency(job, fence); @@ -809,8 +805,31 @@ int drm_sched_job_add_implicit_dependencies(struct drm_sched_job *job, } return 0; } -EXPORT_SYMBOL(drm_sched_job_add_implicit_dependencies); +EXPORT_SYMBOL(drm_sched_job_add_resv_dependencies); +/** + * drm_sched_job_add_implicit_dependencies - adds implicit dependencies as job + * dependencies + * @job: scheduler job to add the dependencies to + * @obj: the gem object to add new dependencies from. + * @write: whether the job might write the object (so we need to depend on + * shared fences in the reservation object). + * + * This should be called after drm_gem_lock_reservations() on your array of + * GEM objects used in the job but before updating the reservations with your + * own fences. + * + * Returns: + * 0 on success, or an error on failing to expand the array. + */ +int drm_sched_job_add_implicit_dependencies(struct drm_sched_job *job, + struct drm_gem_object *obj, + bool write) +{ + return drm_sched_job_add_resv_dependencies(job, obj->resv, + dma_resv_usage_rw(write)); +} +EXPORT_SYMBOL(drm_sched_job_add_implicit_dependencies); /** * drm_sched_job_cleanup - clean up scheduler job resources diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h index 1f7d9dd1a444..8d1747f3e878 100644 --- a/include/drm/gpu_scheduler.h +++ b/include/drm/gpu_scheduler.h @@ -32,6 +32,8 @@ #define MAX_WAIT_SCHED_ENTITY_Q_EMPTY msecs_to_jiffies(1000) +enum dma_resv_usage; +struct dma_resv; struct drm_gem_object; struct drm_gpu_scheduler; @@ -505,6 +507,9 @@ int drm_sched_job_init(struct drm_sched_job *job, void drm_sched_job_arm(struct drm_sched_job *job); int drm_sched_job_add_dependency(struct drm_sched_job *job, struct dma_fence *fence); +int drm_sched_job_add_resv_dependencies(struct drm_sched_job *job, + struct dma_resv *resv, + enum dma_resv_usage usage); int drm_sched_job_add_implicit_dependencies(struct drm_sched_job *job, struct drm_gem_object *obj, bool write); -- cgit From 4f91790b42ffba72d80434d901548979ab41dc7c Mon Sep 17 00:00:00 2001 From: Christian König Date: Wed, 28 Sep 2022 10:54:41 +0200 Subject: drm/amdgpu: use drm_sched_job_add_resv_dependencies for moves MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the new common scheduler functions to figure out what to wait for. Signed-off-by: Christian König Reviewed-by: Luben Tuikov Link: https://patchwork.freedesktop.org/patch/msgid/20221014084641.128280-4-christian.koenig@amd.com --- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 36066965346f..5aae63891858 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -1966,17 +1966,11 @@ static int amdgpu_ttm_prepare_job(struct amdgpu_device *adev, adev->gart.bo); (*job)->vm_needs_flush = true; } - if (resv) { - r = amdgpu_sync_resv(adev, &(*job)->sync, resv, - AMDGPU_SYNC_ALWAYS, - AMDGPU_FENCE_OWNER_UNDEFINED); - if (r) { - DRM_ERROR("sync failed (%d).\n", r); - amdgpu_job_free(*job); - return r; - } - } - return 0; + if (!resv) + return 0; + + return drm_sched_job_add_resv_dependencies(&(*job)->base, resv, + DMA_RESV_USAGE_BOOKKEEP); } int amdgpu_copy_buffer(struct amdgpu_ring *ring, uint64_t src_offset, -- cgit From c5093cddf56baceb1545028e8a5971d94cf59d25 Mon Sep 17 00:00:00 2001 From: Christian König Date: Wed, 28 Sep 2022 13:21:05 +0200 Subject: drm/amdgpu: drop the fence argument from amdgpu_vmid_grab MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is always the job anyway. Signed-off-by: Christian König Reviewed-by: Luben Tuikov Link: https://patchwork.freedesktop.org/patch/msgid/20221014084641.128280-5-christian.koenig@amd.com --- drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c | 20 ++++++++------------ drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h | 3 +-- drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 4 +--- 3 files changed, 10 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c index 03d115d2b5ed..b76294d4275b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c @@ -244,7 +244,6 @@ static int amdgpu_vmid_grab_idle(struct amdgpu_vm *vm, * @vm: vm to allocate id for * @ring: ring we want to submit job to * @sync: sync object where we add dependencies - * @fence: fence protecting ID from reuse * @job: job who wants to use the VMID * @id: resulting VMID * @@ -253,7 +252,6 @@ static int amdgpu_vmid_grab_idle(struct amdgpu_vm *vm, static int amdgpu_vmid_grab_reserved(struct amdgpu_vm *vm, struct amdgpu_ring *ring, struct amdgpu_sync *sync, - struct dma_fence *fence, struct amdgpu_job *job, struct amdgpu_vmid **id) { @@ -290,7 +288,7 @@ static int amdgpu_vmid_grab_reserved(struct amdgpu_vm *vm, /* Good we can use this VMID. Remember this submission as * user of the VMID. */ - r = amdgpu_sync_fence(&(*id)->active, fence); + r = amdgpu_sync_fence(&(*id)->active, &job->base.s_fence->finished); if (r) return r; @@ -305,7 +303,6 @@ static int amdgpu_vmid_grab_reserved(struct amdgpu_vm *vm, * @vm: vm to allocate id for * @ring: ring we want to submit job to * @sync: sync object where we add dependencies - * @fence: fence protecting ID from reuse * @job: job who wants to use the VMID * @id: resulting VMID * @@ -314,7 +311,6 @@ static int amdgpu_vmid_grab_reserved(struct amdgpu_vm *vm, static int amdgpu_vmid_grab_used(struct amdgpu_vm *vm, struct amdgpu_ring *ring, struct amdgpu_sync *sync, - struct dma_fence *fence, struct amdgpu_job *job, struct amdgpu_vmid **id) { @@ -352,7 +348,8 @@ static int amdgpu_vmid_grab_used(struct amdgpu_vm *vm, /* Good, we can use this VMID. Remember this submission as * user of the VMID. */ - r = amdgpu_sync_fence(&(*id)->active, fence); + r = amdgpu_sync_fence(&(*id)->active, + &job->base.s_fence->finished); if (r) return r; @@ -371,14 +368,12 @@ static int amdgpu_vmid_grab_used(struct amdgpu_vm *vm, * @vm: vm to allocate id for * @ring: ring we want to submit job to * @sync: sync object where we add dependencies - * @fence: fence protecting ID from reuse * @job: job who wants to use the VMID * * Allocate an id for the vm, adding fences to the sync obj as necessary. */ int amdgpu_vmid_grab(struct amdgpu_vm *vm, struct amdgpu_ring *ring, - struct amdgpu_sync *sync, struct dma_fence *fence, - struct amdgpu_job *job) + struct amdgpu_sync *sync, struct amdgpu_job *job) { struct amdgpu_device *adev = ring->adev; unsigned vmhub = ring->funcs->vmhub; @@ -393,11 +388,11 @@ int amdgpu_vmid_grab(struct amdgpu_vm *vm, struct amdgpu_ring *ring, goto error; if (vm->reserved_vmid[vmhub]) { - r = amdgpu_vmid_grab_reserved(vm, ring, sync, fence, job, &id); + r = amdgpu_vmid_grab_reserved(vm, ring, sync, job, &id); if (r || !id) goto error; } else { - r = amdgpu_vmid_grab_used(vm, ring, sync, fence, job, &id); + r = amdgpu_vmid_grab_used(vm, ring, sync, job, &id); if (r) goto error; @@ -406,7 +401,8 @@ int amdgpu_vmid_grab(struct amdgpu_vm *vm, struct amdgpu_ring *ring, id = idle; /* Remember this submission as user of the VMID */ - r = amdgpu_sync_fence(&id->active, fence); + r = amdgpu_sync_fence(&id->active, + &job->base.s_fence->finished); if (r) goto error; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h index 06c8a0034fa5..1b1e7d04655c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h @@ -84,8 +84,7 @@ void amdgpu_vmid_free_reserved(struct amdgpu_device *adev, struct amdgpu_vm *vm, unsigned vmhub); int amdgpu_vmid_grab(struct amdgpu_vm *vm, struct amdgpu_ring *ring, - struct amdgpu_sync *sync, struct dma_fence *fence, - struct amdgpu_job *job); + struct amdgpu_sync *sync, struct amdgpu_job *job); void amdgpu_vmid_reset(struct amdgpu_device *adev, unsigned vmhub, unsigned vmid); void amdgpu_vmid_reset_all(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c index 46c99331d7f1..5aa053acc0b4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c @@ -256,9 +256,7 @@ static struct dma_fence *amdgpu_job_dependency(struct drm_sched_job *sched_job, } while (fence == NULL && vm && !job->vmid) { - r = amdgpu_vmid_grab(vm, ring, &job->sync, - &job->base.s_fence->finished, - job); + r = amdgpu_vmid_grab(vm, ring, &job->sync, job); if (r) DRM_ERROR("Error getting VM ID (%d)\n", r); -- cgit From 940ca22b7ea9db6857ba7c6adb961b84d8cc28ff Mon Sep 17 00:00:00 2001 From: Christian König Date: Wed, 28 Sep 2022 14:00:57 +0200 Subject: drm/amdgpu: drop amdgpu_sync from amdgpu_vmid_grab v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead return the fence directly. Avoids memory allocation to store the fence. v2: cleanup coding style as well Signed-off-by: Christian König Reviewed-by: Luben Tuikov Link: https://patchwork.freedesktop.org/patch/msgid/20221014084641.128280-6-christian.koenig@amd.com --- drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c | 42 +++++++++++++++++---------------- drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 12 ++++------ 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c index b76294d4275b..2a9a2593dc18 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c @@ -170,26 +170,27 @@ bool amdgpu_vmid_had_gpu_reset(struct amdgpu_device *adev, * * @vm: vm to allocate id for * @ring: ring we want to submit job to - * @sync: sync object where we add dependencies * @idle: resulting idle VMID + * @fence: fence to wait for if no id could be grabbed * * Try to find an idle VMID, if none is idle add a fence to wait to the sync * object. Returns -ENOMEM when we are out of memory. */ static int amdgpu_vmid_grab_idle(struct amdgpu_vm *vm, struct amdgpu_ring *ring, - struct amdgpu_sync *sync, - struct amdgpu_vmid **idle) + struct amdgpu_vmid **idle, + struct dma_fence **fence) { struct amdgpu_device *adev = ring->adev; unsigned vmhub = ring->funcs->vmhub; struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub]; struct dma_fence **fences; unsigned i; - int r; - if (!dma_fence_is_signaled(ring->vmid_wait)) - return amdgpu_sync_fence(sync, ring->vmid_wait); + if (!dma_fence_is_signaled(ring->vmid_wait)) { + *fence = dma_fence_get(ring->vmid_wait); + return 0; + } fences = kmalloc_array(id_mgr->num_ids, sizeof(void *), GFP_KERNEL); if (!fences) @@ -228,10 +229,10 @@ static int amdgpu_vmid_grab_idle(struct amdgpu_vm *vm, return -ENOMEM; } - r = amdgpu_sync_fence(sync, &array->base); + *fence = dma_fence_get(&array->base); dma_fence_put(ring->vmid_wait); ring->vmid_wait = &array->base; - return r; + return 0; } kfree(fences); @@ -243,17 +244,17 @@ static int amdgpu_vmid_grab_idle(struct amdgpu_vm *vm, * * @vm: vm to allocate id for * @ring: ring we want to submit job to - * @sync: sync object where we add dependencies * @job: job who wants to use the VMID * @id: resulting VMID + * @fence: fence to wait for if no id could be grabbed * * Try to assign a reserved VMID. */ static int amdgpu_vmid_grab_reserved(struct amdgpu_vm *vm, struct amdgpu_ring *ring, - struct amdgpu_sync *sync, struct amdgpu_job *job, - struct amdgpu_vmid **id) + struct amdgpu_vmid **id, + struct dma_fence **fence) { struct amdgpu_device *adev = ring->adev; unsigned vmhub = ring->funcs->vmhub; @@ -280,7 +281,8 @@ static int amdgpu_vmid_grab_reserved(struct amdgpu_vm *vm, tmp = amdgpu_sync_peek_fence(&(*id)->active, ring); if (tmp) { *id = NULL; - return amdgpu_sync_fence(sync, tmp); + *fence = dma_fence_get(tmp); + return 0; } needs_flush = true; } @@ -302,17 +304,17 @@ static int amdgpu_vmid_grab_reserved(struct amdgpu_vm *vm, * * @vm: vm to allocate id for * @ring: ring we want to submit job to - * @sync: sync object where we add dependencies * @job: job who wants to use the VMID * @id: resulting VMID + * @fence: fence to wait for if no id could be grabbed * * Try to reuse a VMID for this submission. */ static int amdgpu_vmid_grab_used(struct amdgpu_vm *vm, struct amdgpu_ring *ring, - struct amdgpu_sync *sync, struct amdgpu_job *job, - struct amdgpu_vmid **id) + struct amdgpu_vmid **id, + struct dma_fence **fence) { struct amdgpu_device *adev = ring->adev; unsigned vmhub = ring->funcs->vmhub; @@ -367,13 +369,13 @@ static int amdgpu_vmid_grab_used(struct amdgpu_vm *vm, * * @vm: vm to allocate id for * @ring: ring we want to submit job to - * @sync: sync object where we add dependencies * @job: job who wants to use the VMID + * @fence: fence to wait for if no id could be grabbed * * Allocate an id for the vm, adding fences to the sync obj as necessary. */ int amdgpu_vmid_grab(struct amdgpu_vm *vm, struct amdgpu_ring *ring, - struct amdgpu_sync *sync, struct amdgpu_job *job) + struct amdgpu_job *job, struct dma_fence **fence) { struct amdgpu_device *adev = ring->adev; unsigned vmhub = ring->funcs->vmhub; @@ -383,16 +385,16 @@ int amdgpu_vmid_grab(struct amdgpu_vm *vm, struct amdgpu_ring *ring, int r = 0; mutex_lock(&id_mgr->lock); - r = amdgpu_vmid_grab_idle(vm, ring, sync, &idle); + r = amdgpu_vmid_grab_idle(vm, ring, &idle, fence); if (r || !idle) goto error; if (vm->reserved_vmid[vmhub]) { - r = amdgpu_vmid_grab_reserved(vm, ring, sync, job, &id); + r = amdgpu_vmid_grab_reserved(vm, ring, job, &id, fence); if (r || !id) goto error; } else { - r = amdgpu_vmid_grab_used(vm, ring, sync, job, &id); + r = amdgpu_vmid_grab_used(vm, ring, job, &id, fence); if (r) goto error; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h index 1b1e7d04655c..57efe61dceed 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h @@ -84,7 +84,7 @@ void amdgpu_vmid_free_reserved(struct amdgpu_device *adev, struct amdgpu_vm *vm, unsigned vmhub); int amdgpu_vmid_grab(struct amdgpu_vm *vm, struct amdgpu_ring *ring, - struct amdgpu_sync *sync, struct amdgpu_job *job); + struct amdgpu_job *job, struct dma_fence **fence); void amdgpu_vmid_reset(struct amdgpu_device *adev, unsigned vmhub, unsigned vmid); void amdgpu_vmid_reset_all(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c index 5aa053acc0b4..384149a81978 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c @@ -239,12 +239,12 @@ int amdgpu_job_submit_direct(struct amdgpu_job *job, struct amdgpu_ring *ring, return 0; } -static struct dma_fence *amdgpu_job_dependency(struct drm_sched_job *sched_job, - struct drm_sched_entity *s_entity) +static struct dma_fence * +amdgpu_job_dependency(struct drm_sched_job *sched_job, + struct drm_sched_entity *s_entity) { struct amdgpu_ring *ring = to_amdgpu_ring(s_entity->rq->sched); struct amdgpu_job *job = to_amdgpu_job(sched_job); - struct amdgpu_vm *vm = job->vm; struct dma_fence *fence; int r; @@ -255,12 +255,10 @@ static struct dma_fence *amdgpu_job_dependency(struct drm_sched_job *sched_job, DRM_ERROR("Error adding fence (%d)\n", r); } - while (fence == NULL && vm && !job->vmid) { - r = amdgpu_vmid_grab(vm, ring, &job->sync, job); + while (!fence && job->vm && !job->vmid) { + r = amdgpu_vmid_grab(job->vm, ring, job, &fence); if (r) DRM_ERROR("Error getting VM ID (%d)\n", r); - - fence = amdgpu_sync_get_fence(&job->sync); } if (!fence && job->gang_submit) -- cgit From f7d66fb2ea43a3016e78a700a2ca6c77a74579f9 Mon Sep 17 00:00:00 2001 From: Christian König Date: Wed, 28 Sep 2022 20:31:38 +0200 Subject: drm/amdgpu: cleanup scheduler job initialization v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Init the DRM scheduler base class while allocating the job. This makes the whole handling much more cleaner. v2: fix coding style Signed-off-by: Christian König Reviewed-by: Luben Tuikov Link: https://patchwork.freedesktop.org/patch/msgid/20221014084641.128280-7-christian.koenig@amd.com --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 8 +--- drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 44 +++++++++++---------- drivers/gpu/drm/amd/amdgpu/amdgpu_job.h | 14 ++++--- drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c | 7 ++-- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 56 ++++++++++---------------- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 9 ++--- drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c | 13 +++--- drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c | 22 ++++++----- drivers/gpu/drm/amd/amdgpu/amdgpu_vm_sdma.c | 61 +++++++++++++++-------------- drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c | 12 ++---- drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c | 8 ++-- drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c | 12 +++--- drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 17 +++----- 14 files changed, 135 insertions(+), 150 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 03bbfaa51cbc..cf58c1125e60 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -674,7 +674,7 @@ int amdgpu_amdkfd_submit_ib(struct amdgpu_device *adev, goto err; } - ret = amdgpu_job_alloc(adev, 1, &job, NULL); + ret = amdgpu_job_alloc(adev, NULL, NULL, NULL, 1, &job); if (ret) goto err; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 1bbd39b3b0fc..aa6f6c428dbc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -291,12 +291,8 @@ static int amdgpu_cs_pass1(struct amdgpu_cs_parser *p, return -EINVAL; for (i = 0; i < p->gang_size; ++i) { - ret = amdgpu_job_alloc(p->adev, num_ibs[i], &p->jobs[i], vm); - if (ret) - goto free_all_kdata; - - ret = drm_sched_job_init(&p->jobs[i]->base, p->entities[i], - &fpriv->vm); + ret = amdgpu_job_alloc(p->adev, vm, p->entities[i], vm, + num_ibs[i], &p->jobs[i]); if (ret) goto free_all_kdata; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c index 384149a81978..fa60d25dfbd1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c @@ -89,8 +89,9 @@ exit: return DRM_GPU_SCHED_STAT_NOMINAL; } -int amdgpu_job_alloc(struct amdgpu_device *adev, unsigned num_ibs, - struct amdgpu_job **job, struct amdgpu_vm *vm) +int amdgpu_job_alloc(struct amdgpu_device *adev, struct amdgpu_vm *vm, + struct drm_sched_entity *entity, void *owner, + unsigned int num_ibs, struct amdgpu_job **job) { if (num_ibs == 0) return -EINVAL; @@ -111,23 +112,30 @@ int amdgpu_job_alloc(struct amdgpu_device *adev, unsigned num_ibs, (*job)->vram_lost_counter = atomic_read(&adev->vram_lost_counter); (*job)->vm_pd_addr = AMDGPU_BO_INVALID_OFFSET; - return 0; + if (!entity) + return 0; + + return drm_sched_job_init(&(*job)->base, entity, owner); } -int amdgpu_job_alloc_with_ib(struct amdgpu_device *adev, unsigned size, - enum amdgpu_ib_pool_type pool_type, - struct amdgpu_job **job) +int amdgpu_job_alloc_with_ib(struct amdgpu_device *adev, + struct drm_sched_entity *entity, void *owner, + size_t size, enum amdgpu_ib_pool_type pool_type, + struct amdgpu_job **job) { int r; - r = amdgpu_job_alloc(adev, 1, job, NULL); + r = amdgpu_job_alloc(adev, NULL, entity, owner, 1, job); if (r) return r; (*job)->num_ibs = 1; r = amdgpu_ib_get(adev, NULL, size, pool_type, &(*job)->ibs[0]); - if (r) + if (r) { + if (entity) + drm_sched_job_cleanup(&(*job)->base); kfree(*job); + } return r; } @@ -191,6 +199,9 @@ void amdgpu_job_set_gang_leader(struct amdgpu_job *job, void amdgpu_job_free(struct amdgpu_job *job) { + if (job->base.entity) + drm_sched_job_cleanup(&job->base); + amdgpu_job_free_resources(job); amdgpu_sync_free(&job->sync); amdgpu_sync_free(&job->sched_sync); @@ -203,25 +214,16 @@ void amdgpu_job_free(struct amdgpu_job *job) dma_fence_put(&job->hw_fence); } -int amdgpu_job_submit(struct amdgpu_job *job, struct drm_sched_entity *entity, - void *owner, struct dma_fence **f) +struct dma_fence *amdgpu_job_submit(struct amdgpu_job *job) { - int r; - - if (!f) - return -EINVAL; - - r = drm_sched_job_init(&job->base, entity, owner); - if (r) - return r; + struct dma_fence *f; drm_sched_job_arm(&job->base); - - *f = dma_fence_get(&job->base.s_fence->finished); + f = dma_fence_get(&job->base.s_fence->finished); amdgpu_job_free_resources(job); drm_sched_entity_push_job(&job->base); - return 0; + return f; } int amdgpu_job_submit_direct(struct amdgpu_job *job, struct amdgpu_ring *ring, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h index ab7b150e5d50..e2ecab977d0d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h @@ -78,18 +78,20 @@ static inline struct amdgpu_ring *amdgpu_job_ring(struct amdgpu_job *job) return to_amdgpu_ring(job->base.entity->rq->sched); } -int amdgpu_job_alloc(struct amdgpu_device *adev, unsigned num_ibs, - struct amdgpu_job **job, struct amdgpu_vm *vm); -int amdgpu_job_alloc_with_ib(struct amdgpu_device *adev, unsigned size, - enum amdgpu_ib_pool_type pool, struct amdgpu_job **job); +int amdgpu_job_alloc(struct amdgpu_device *adev, struct amdgpu_vm *vm, + struct drm_sched_entity *entity, void *owner, + unsigned int num_ibs, struct amdgpu_job **job); +int amdgpu_job_alloc_with_ib(struct amdgpu_device *adev, + struct drm_sched_entity *entity, void *owner, + size_t size, enum amdgpu_ib_pool_type pool_type, + struct amdgpu_job **job); void amdgpu_job_set_resources(struct amdgpu_job *job, struct amdgpu_bo *gds, struct amdgpu_bo *gws, struct amdgpu_bo *oa); void amdgpu_job_free_resources(struct amdgpu_job *job); void amdgpu_job_set_gang_leader(struct amdgpu_job *job, struct amdgpu_job *leader); void amdgpu_job_free(struct amdgpu_job *job); -int amdgpu_job_submit(struct amdgpu_job *job, struct drm_sched_entity *entity, - void *owner, struct dma_fence **f); +struct dma_fence *amdgpu_job_submit(struct amdgpu_job *job); int amdgpu_job_submit_direct(struct amdgpu_job *job, struct amdgpu_ring *ring, struct dma_fence **fence); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c index 518eb0e40d32..de182bfcf85f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c @@ -150,14 +150,15 @@ static int amdgpu_jpeg_dec_set_reg(struct amdgpu_ring *ring, uint32_t handle, const unsigned ib_size_dw = 16; int i, r; - r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4, - AMDGPU_IB_POOL_DIRECT, &job); + r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL, ib_size_dw * 4, + AMDGPU_IB_POOL_DIRECT, &job); if (r) return r; ib = &job->ibs[0]; - ib->ptr[0] = PACKETJ(adev->jpeg.internal.jpeg_pitch, 0, 0, PACKETJ_TYPE0); + ib->ptr[0] = PACKETJ(adev->jpeg.internal.jpeg_pitch, 0, 0, + PACKETJ_TYPE0); ib->ptr[1] = 0xDEADBEEF; for (i = 2; i < 16; i += 2) { ib->ptr[i] = PACKETJ(0, 0, 0, PACKETJ_TYPE6); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 5aae63891858..9f5c1d86d2ab 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -189,7 +189,6 @@ static int amdgpu_ttm_map_buffer(struct ttm_buffer_object *bo, struct amdgpu_device *adev = ring->adev; unsigned offset, num_pages, num_dw, num_bytes; uint64_t src_addr, dst_addr; - struct dma_fence *fence; struct amdgpu_job *job; void *cpu_addr; uint64_t flags; @@ -229,7 +228,9 @@ static int amdgpu_ttm_map_buffer(struct ttm_buffer_object *bo, num_dw = ALIGN(adev->mman.buffer_funcs->copy_num_dw, 8); num_bytes = num_pages * 8 * AMDGPU_GPU_PAGES_IN_CPU_PAGE; - r = amdgpu_job_alloc_with_ib(adev, num_dw * 4 + num_bytes, + r = amdgpu_job_alloc_with_ib(adev, &adev->mman.entity, + AMDGPU_FENCE_OWNER_UNDEFINED, + num_dw * 4 + num_bytes, AMDGPU_IB_POOL_DELAYED, &job); if (r) return r; @@ -269,18 +270,8 @@ static int amdgpu_ttm_map_buffer(struct ttm_buffer_object *bo, } } - r = amdgpu_job_submit(job, &adev->mman.entity, - AMDGPU_FENCE_OWNER_UNDEFINED, &fence); - if (r) - goto error_free; - - dma_fence_put(fence); - - return r; - -error_free: - amdgpu_job_free(job); - return r; + dma_fence_put(amdgpu_job_submit(job)); + return 0; } /** @@ -1414,7 +1405,8 @@ static void amdgpu_ttm_vram_mm_access(struct amdgpu_device *adev, loff_t pos, } static int amdgpu_ttm_access_memory_sdma(struct ttm_buffer_object *bo, - unsigned long offset, void *buf, int len, int write) + unsigned long offset, void *buf, + int len, int write) { struct amdgpu_bo *abo = ttm_to_amdgpu_bo(bo); struct amdgpu_device *adev = amdgpu_ttm_adev(abo->tbo.bdev); @@ -1438,26 +1430,27 @@ static int amdgpu_ttm_access_memory_sdma(struct ttm_buffer_object *bo, memcpy(adev->mman.sdma_access_ptr, buf, len); num_dw = ALIGN(adev->mman.buffer_funcs->copy_num_dw, 8); - r = amdgpu_job_alloc_with_ib(adev, num_dw * 4, AMDGPU_IB_POOL_DELAYED, &job); + r = amdgpu_job_alloc_with_ib(adev, &adev->mman.entity, + AMDGPU_FENCE_OWNER_UNDEFINED, + num_dw * 4, AMDGPU_IB_POOL_DELAYED, + &job); if (r) goto out; amdgpu_res_first(abo->tbo.resource, offset, len, &src_mm); - src_addr = amdgpu_ttm_domain_start(adev, bo->resource->mem_type) + src_mm.start; + src_addr = amdgpu_ttm_domain_start(adev, bo->resource->mem_type) + + src_mm.start; dst_addr = amdgpu_bo_gpu_offset(adev->mman.sdma_access_bo); if (write) swap(src_addr, dst_addr); - amdgpu_emit_copy_buffer(adev, &job->ibs[0], src_addr, dst_addr, PAGE_SIZE, false); + amdgpu_emit_copy_buffer(adev, &job->ibs[0], src_addr, dst_addr, + PAGE_SIZE, false); amdgpu_ring_pad_ib(adev->mman.buffer_funcs_ring, &job->ibs[0]); WARN_ON(job->ibs[0].length_dw > num_dw); - r = amdgpu_job_submit(job, &adev->mman.entity, AMDGPU_FENCE_OWNER_UNDEFINED, &fence); - if (r) { - amdgpu_job_free(job); - goto out; - } + fence = amdgpu_job_submit(job); if (!dma_fence_wait_timeout(fence, false, adev->sdma_timeout)) r = -ETIMEDOUT; @@ -1956,7 +1949,9 @@ static int amdgpu_ttm_prepare_job(struct amdgpu_device *adev, AMDGPU_IB_POOL_DELAYED; int r; - r = amdgpu_job_alloc_with_ib(adev, num_dw * 4, pool, job); + r = amdgpu_job_alloc_with_ib(adev, &adev->mman.entity, + AMDGPU_FENCE_OWNER_UNDEFINED, + num_dw * 4, pool, job); if (r) return r; @@ -2015,8 +2010,7 @@ int amdgpu_copy_buffer(struct amdgpu_ring *ring, uint64_t src_offset, if (direct_submit) r = amdgpu_job_submit_direct(job, ring, fence); else - r = amdgpu_job_submit(job, &adev->mman.entity, - AMDGPU_FENCE_OWNER_UNDEFINED, fence); + *fence = amdgpu_job_submit(job); if (r) goto error_free; @@ -2061,16 +2055,8 @@ static int amdgpu_ttm_fill_mem(struct amdgpu_ring *ring, uint32_t src_data, amdgpu_ring_pad_ib(ring, &job->ibs[0]); WARN_ON(job->ibs[0].length_dw > num_dw); - r = amdgpu_job_submit(job, &adev->mman.entity, - AMDGPU_FENCE_OWNER_UNDEFINED, fence); - if (r) - goto error_free; - + *fence = amdgpu_job_submit(job); return 0; - -error_free: - amdgpu_job_free(job); - return r; } int amdgpu_fill_buffer(struct amdgpu_bo *bo, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index 6eac649499d3..8baddf79635b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -1132,7 +1132,9 @@ static int amdgpu_uvd_send_msg(struct amdgpu_ring *ring, struct amdgpu_bo *bo, unsigned offset_idx = 0; unsigned offset[3] = { UVD_BASE_SI, 0, 0 }; - r = amdgpu_job_alloc_with_ib(adev, 64, direct ? AMDGPU_IB_POOL_DIRECT : + r = amdgpu_job_alloc_with_ib(ring->adev, &adev->uvd.entity, + AMDGPU_FENCE_OWNER_UNDEFINED, + 64, direct ? AMDGPU_IB_POOL_DIRECT : AMDGPU_IB_POOL_DELAYED, &job); if (r) return r; @@ -1181,10 +1183,7 @@ static int amdgpu_uvd_send_msg(struct amdgpu_ring *ring, struct amdgpu_bo *bo, if (r) goto err_free; - r = amdgpu_job_submit(job, &adev->uvd.entity, - AMDGPU_FENCE_OWNER_UNDEFINED, &f); - if (r) - goto err_free; + f = amdgpu_job_submit(job); } amdgpu_bo_reserve(bo, true); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c index 02cb3a12dd76..b239e874f2d5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c @@ -450,8 +450,10 @@ static int amdgpu_vce_get_create_msg(struct amdgpu_ring *ring, uint32_t handle, uint64_t addr; int i, r; - r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4, - AMDGPU_IB_POOL_DIRECT, &job); + r = amdgpu_job_alloc_with_ib(ring->adev, &ring->adev->vce.entity, + AMDGPU_FENCE_OWNER_UNDEFINED, + ib_size_dw * 4, AMDGPU_IB_POOL_DIRECT, + &job); if (r) return r; @@ -538,7 +540,9 @@ static int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle, struct dma_fence *f = NULL; int i, r; - r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4, + r = amdgpu_job_alloc_with_ib(ring->adev, &ring->adev->vce.entity, + AMDGPU_FENCE_OWNER_UNDEFINED, + ib_size_dw * 4, direct ? AMDGPU_IB_POOL_DIRECT : AMDGPU_IB_POOL_DELAYED, &job); if (r) @@ -570,8 +574,7 @@ static int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle, if (direct) r = amdgpu_job_submit_direct(job, ring, &f); else - r = amdgpu_job_submit(job, &ring->adev->vce.entity, - AMDGPU_FENCE_OWNER_UNDEFINED, &f); + f = amdgpu_job_submit(job); if (r) goto err; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c index 0b52af415b28..3449145ab2bc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c @@ -600,15 +600,16 @@ static int amdgpu_vcn_dec_send_msg(struct amdgpu_ring *ring, struct amdgpu_ib *ib_msg, struct dma_fence **fence) { + u64 addr = AMDGPU_GPU_PAGE_ALIGN(ib_msg->gpu_addr); struct amdgpu_device *adev = ring->adev; struct dma_fence *f = NULL; struct amdgpu_job *job; struct amdgpu_ib *ib; - uint64_t addr = AMDGPU_GPU_PAGE_ALIGN(ib_msg->gpu_addr); int i, r; - r = amdgpu_job_alloc_with_ib(adev, 64, - AMDGPU_IB_POOL_DIRECT, &job); + r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL, + 64, AMDGPU_IB_POOL_DIRECT, + &job); if (r) goto err; @@ -787,8 +788,9 @@ static int amdgpu_vcn_dec_sw_send_msg(struct amdgpu_ring *ring, if (sq) ib_size_dw += 8; - r = amdgpu_job_alloc_with_ib(adev, ib_size_dw * 4, - AMDGPU_IB_POOL_DIRECT, &job); + r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL, + ib_size_dw * 4, AMDGPU_IB_POOL_DIRECT, + &job); if (r) goto err; @@ -916,8 +918,9 @@ static int amdgpu_vcn_enc_get_create_msg(struct amdgpu_ring *ring, uint32_t hand if (sq) ib_size_dw += 8; - r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4, - AMDGPU_IB_POOL_DIRECT, &job); + r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL, + ib_size_dw * 4, AMDGPU_IB_POOL_DIRECT, + &job); if (r) return r; @@ -982,8 +985,9 @@ static int amdgpu_vcn_enc_get_destroy_msg(struct amdgpu_ring *ring, uint32_t han if (sq) ib_size_dw += 8; - r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4, - AMDGPU_IB_POOL_DIRECT, &job); + r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL, + ib_size_dw * 4, AMDGPU_IB_POOL_DIRECT, + &job); if (r) return r; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_sdma.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_sdma.c index 2b0669c464f6..6768af365f3b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_sdma.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_sdma.c @@ -47,6 +47,32 @@ static int amdgpu_vm_sdma_map_table(struct amdgpu_bo_vm *table) return r; } +/* Allocate a new job for @count PTE updates */ +static int amdgpu_vm_sdma_alloc_job(struct amdgpu_vm_update_params *p, + unsigned int count) +{ + enum amdgpu_ib_pool_type pool = p->immediate ? AMDGPU_IB_POOL_IMMEDIATE + : AMDGPU_IB_POOL_DELAYED; + struct drm_sched_entity *entity = p->immediate ? &p->vm->immediate + : &p->vm->delayed; + unsigned int ndw; + int r; + + /* estimate how many dw we need */ + ndw = AMDGPU_VM_SDMA_MIN_NUM_DW; + if (p->pages_addr) + ndw += count * 2; + ndw = min(ndw, AMDGPU_VM_SDMA_MAX_NUM_DW); + + r = amdgpu_job_alloc_with_ib(p->adev, entity, AMDGPU_FENCE_OWNER_VM, + ndw * 4, pool, &p->job); + if (r) + return r; + + p->num_dw_left = ndw; + return 0; +} + /** * amdgpu_vm_sdma_prepare - prepare SDMA command submission * @@ -61,17 +87,12 @@ static int amdgpu_vm_sdma_prepare(struct amdgpu_vm_update_params *p, struct dma_resv *resv, enum amdgpu_sync_mode sync_mode) { - enum amdgpu_ib_pool_type pool = p->immediate ? AMDGPU_IB_POOL_IMMEDIATE - : AMDGPU_IB_POOL_DELAYED; - unsigned int ndw = AMDGPU_VM_SDMA_MIN_NUM_DW; int r; - r = amdgpu_job_alloc_with_ib(p->adev, ndw * 4, pool, &p->job); + r = amdgpu_vm_sdma_alloc_job(p, 0); if (r) return r; - p->num_dw_left = ndw; - if (!resv) return 0; @@ -91,20 +112,16 @@ static int amdgpu_vm_sdma_commit(struct amdgpu_vm_update_params *p, struct dma_fence **fence) { struct amdgpu_ib *ib = p->job->ibs; - struct drm_sched_entity *entity; struct amdgpu_ring *ring; struct dma_fence *f; - int r; - entity = p->immediate ? &p->vm->immediate : &p->vm->delayed; - ring = container_of(entity->rq->sched, struct amdgpu_ring, sched); + ring = container_of(p->vm->delayed.rq->sched, struct amdgpu_ring, + sched); WARN_ON(ib->length_dw == 0); amdgpu_ring_pad_ib(ring, ib); WARN_ON(ib->length_dw > p->num_dw_left); - r = amdgpu_job_submit(p->job, entity, AMDGPU_FENCE_OWNER_VM, &f); - if (r) - goto error; + f = amdgpu_job_submit(p->job); if (p->unlocked) { struct dma_fence *tmp = dma_fence_get(f); @@ -120,10 +137,6 @@ static int amdgpu_vm_sdma_commit(struct amdgpu_vm_update_params *p, swap(*fence, f); dma_fence_put(f); return 0; - -error: - amdgpu_job_free(p->job); - return r; } /** @@ -203,8 +216,6 @@ static int amdgpu_vm_sdma_update(struct amdgpu_vm_update_params *p, uint64_t flags) { struct amdgpu_bo *bo = &vmbo->bo; - enum amdgpu_ib_pool_type pool = p->immediate ? AMDGPU_IB_POOL_IMMEDIATE - : AMDGPU_IB_POOL_DELAYED; struct dma_resv_iter cursor; unsigned int i, ndw, nptes; struct dma_fence *fence; @@ -231,19 +242,9 @@ static int amdgpu_vm_sdma_update(struct amdgpu_vm_update_params *p, if (r) return r; - /* estimate how many dw we need */ - ndw = 32; - if (p->pages_addr) - ndw += count * 2; - ndw = max(ndw, AMDGPU_VM_SDMA_MIN_NUM_DW); - ndw = min(ndw, AMDGPU_VM_SDMA_MAX_NUM_DW); - - r = amdgpu_job_alloc_with_ib(p->adev, ndw * 4, pool, - &p->job); + r = amdgpu_vm_sdma_alloc_job(p, count); if (r) return r; - - p->num_dw_left = ndw; } if (!p->pages_addr) { diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c index f513e2c2e964..657e53708248 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c @@ -371,7 +371,9 @@ static void gmc_v10_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid, * translation. Avoid this by doing the invalidation from the SDMA * itself. */ - r = amdgpu_job_alloc_with_ib(adev, 16 * 4, AMDGPU_IB_POOL_IMMEDIATE, + r = amdgpu_job_alloc_with_ib(ring->adev, &adev->mman.entity, + AMDGPU_FENCE_OWNER_UNDEFINED, + 16 * 4, AMDGPU_IB_POOL_IMMEDIATE, &job); if (r) goto error_alloc; @@ -380,10 +382,7 @@ static void gmc_v10_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid, job->vm_needs_flush = true; job->ibs->ptr[job->ibs->length_dw++] = ring->funcs->nop; amdgpu_ring_pad_ib(ring, &job->ibs[0]); - r = amdgpu_job_submit(job, &adev->mman.entity, - AMDGPU_FENCE_OWNER_UNDEFINED, &fence); - if (r) - goto error_submit; + fence = amdgpu_job_submit(job); mutex_unlock(&adev->mman.gtt_window_lock); @@ -392,9 +391,6 @@ static void gmc_v10_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid, return; -error_submit: - amdgpu_job_free(job); - error_alloc: mutex_unlock(&adev->mman.gtt_window_lock); DRM_ERROR("Error flushing GPU TLB using the SDMA (%d)!\n", r); diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c index 375c440957dc..5fe872f4bea7 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c @@ -216,8 +216,8 @@ static int uvd_v6_0_enc_get_create_msg(struct amdgpu_ring *ring, uint32_t handle uint64_t addr; int i, r; - r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4, - AMDGPU_IB_POOL_DIRECT, &job); + r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL, ib_size_dw * 4, + AMDGPU_IB_POOL_DIRECT, &job); if (r) return r; @@ -280,8 +280,8 @@ static int uvd_v6_0_enc_get_destroy_msg(struct amdgpu_ring *ring, uint64_t addr; int i, r; - r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4, - AMDGPU_IB_POOL_DIRECT, &job); + r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL, ib_size_dw * 4, + AMDGPU_IB_POOL_DIRECT, &job); if (r) return r; diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c index e668b3baa8c6..e407be6cb63c 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c @@ -213,7 +213,7 @@ static int uvd_v7_0_enc_ring_test_ring(struct amdgpu_ring *ring) * * Open up a stream for HW test */ -static int uvd_v7_0_enc_get_create_msg(struct amdgpu_ring *ring, uint32_t handle, +static int uvd_v7_0_enc_get_create_msg(struct amdgpu_ring *ring, u32 handle, struct amdgpu_bo *bo, struct dma_fence **fence) { @@ -224,8 +224,8 @@ static int uvd_v7_0_enc_get_create_msg(struct amdgpu_ring *ring, uint32_t handle uint64_t addr; int i, r; - r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4, - AMDGPU_IB_POOL_DIRECT, &job); + r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL, ib_size_dw * 4, + AMDGPU_IB_POOL_DIRECT, &job); if (r) return r; @@ -276,7 +276,7 @@ err: * * Close up a stream for HW test or if userspace failed to do so */ -static int uvd_v7_0_enc_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle, +static int uvd_v7_0_enc_get_destroy_msg(struct amdgpu_ring *ring, u32 handle, struct amdgpu_bo *bo, struct dma_fence **fence) { @@ -287,8 +287,8 @@ static int uvd_v7_0_enc_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handl uint64_t addr; int i, r; - r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4, - AMDGPU_IB_POOL_DIRECT, &job); + r = amdgpu_job_alloc_with_ib(ring->adev, NULL, NULL, ib_size_dw * 4, + AMDGPU_IB_POOL_DIRECT, &job); if (r) return r; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c index 2797029bd500..79069c485386 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c @@ -65,8 +65,11 @@ svm_migrate_gart_map(struct amdgpu_ring *ring, uint64_t npages, num_dw = ALIGN(adev->mman.buffer_funcs->copy_num_dw, 8); num_bytes = npages * 8; - r = amdgpu_job_alloc_with_ib(adev, num_dw * 4 + num_bytes, - AMDGPU_IB_POOL_DELAYED, &job); + r = amdgpu_job_alloc_with_ib(adev, &adev->mman.entity, + AMDGPU_FENCE_OWNER_UNDEFINED, + num_dw * 4 + num_bytes, + AMDGPU_IB_POOL_DELAYED, + &job); if (r) return r; @@ -89,18 +92,10 @@ svm_migrate_gart_map(struct amdgpu_ring *ring, uint64_t npages, cpu_addr = &job->ibs[0].ptr[num_dw]; amdgpu_gart_map(adev, 0, npages, addr, pte_flags, cpu_addr); - r = amdgpu_job_submit(job, &adev->mman.entity, - AMDGPU_FENCE_OWNER_UNDEFINED, &fence); - if (r) - goto error_free; - + fence = amdgpu_job_submit(job); dma_fence_put(fence); return r; - -error_free: - amdgpu_job_free(job); - return r; } /** -- cgit From 1b2d5eda5ad785d0dd13484141b78d2ac366c169 Mon Sep 17 00:00:00 2001 From: Christian König Date: Thu, 29 Sep 2022 13:05:56 +0200 Subject: drm/amdgpu: move explicit sync check into the CS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This moves the memory allocation out of the critical code path. Signed-off-by: Christian König Reviewed-by: Luben Tuikov Link: https://patchwork.freedesktop.org/patch/msgid/20221014084641.128280-8-christian.koenig@amd.com --- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 13 ++++++++++++- drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 12 +++--------- drivers/gpu/drm/amd/amdgpu/amdgpu_job.h | 2 +- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index aa6f6c428dbc..d45b86bcf7fa 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -449,8 +449,19 @@ static int amdgpu_syncobj_lookup_and_add(struct amdgpu_cs_parser *p, } r = amdgpu_sync_fence(&p->gang_leader->sync, fence); - dma_fence_put(fence); + if (r) + goto error; + + /* + * When we have an explicit dependency it might be necessary to insert a + * pipeline sync to make sure that all caches etc are flushed and the + * next job actually sees the results from the previous one. + */ + if (fence->context == p->gang_leader->base.entity->fence_context) + r = amdgpu_sync_fence(&p->gang_leader->explicit_sync, fence); +error: + dma_fence_put(fence); return r; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c index 258cffe3c06a..774c77bb8f4e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c @@ -182,7 +182,7 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs, need_ctx_switch = ring->current_ctx != fence_ctx; if (ring->funcs->emit_pipeline_sync && job && - ((tmp = amdgpu_sync_get_fence(&job->sched_sync)) || + ((tmp = amdgpu_sync_get_fence(&job->explicit_sync)) || (amdgpu_sriov_vf(adev) && need_ctx_switch) || amdgpu_vm_need_pipeline_sync(ring, job))) { need_pipe_sync = true; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c index fa60d25dfbd1..6c126797d6a4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c @@ -108,7 +108,7 @@ int amdgpu_job_alloc(struct amdgpu_device *adev, struct amdgpu_vm *vm, (*job)->vm = vm; amdgpu_sync_create(&(*job)->sync); - amdgpu_sync_create(&(*job)->sched_sync); + amdgpu_sync_create(&(*job)->explicit_sync); (*job)->vram_lost_counter = atomic_read(&adev->vram_lost_counter); (*job)->vm_pd_addr = AMDGPU_BO_INVALID_OFFSET; @@ -176,7 +176,7 @@ static void amdgpu_job_free_cb(struct drm_sched_job *s_job) drm_sched_job_cleanup(s_job); amdgpu_sync_free(&job->sync); - amdgpu_sync_free(&job->sched_sync); + amdgpu_sync_free(&job->explicit_sync); dma_fence_put(&job->hw_fence); } @@ -204,7 +204,7 @@ void amdgpu_job_free(struct amdgpu_job *job) amdgpu_job_free_resources(job); amdgpu_sync_free(&job->sync); - amdgpu_sync_free(&job->sched_sync); + amdgpu_sync_free(&job->explicit_sync); if (job->gang_submit != &job->base.s_fence->scheduled) dma_fence_put(job->gang_submit); @@ -251,12 +251,6 @@ amdgpu_job_dependency(struct drm_sched_job *sched_job, int r; fence = amdgpu_sync_get_fence(&job->sync); - if (fence && drm_sched_dependency_optimized(fence, s_entity)) { - r = amdgpu_sync_fence(&job->sched_sync, fence); - if (r) - DRM_ERROR("Error adding fence (%d)\n", r); - } - while (!fence && job->vm && !job->vmid) { r = amdgpu_vmid_grab(job->vm, ring, job, &fence); if (r) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h index e2ecab977d0d..ef4bdde7c918 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h @@ -48,7 +48,7 @@ struct amdgpu_job { struct drm_sched_job base; struct amdgpu_vm *vm; struct amdgpu_sync sync; - struct amdgpu_sync sched_sync; + struct amdgpu_sync explicit_sync; struct dma_fence hw_fence; struct dma_fence *gang_submit; uint32_t preamble_status; -- cgit From aab9cf7b6954136f4339136a1a7fc0602a2c4d8b Mon Sep 17 00:00:00 2001 From: Christian König Date: Thu, 29 Sep 2022 13:34:34 +0200 Subject: drm/amdgpu: use scheduler dependencies for VM updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of putting that into the job sync object. Signed-off-by: Christian König Reviewed-by: Luben Tuikov Link: https://patchwork.freedesktop.org/patch/msgid/20221014084641.128280-9-christian.koenig@amd.com --- drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c | 56 +++++++++++++++++++++-------- drivers/gpu/drm/amd/amdgpu/amdgpu_sync.h | 2 ++ drivers/gpu/drm/amd/amdgpu/amdgpu_vm_sdma.c | 10 ++++-- 3 files changed, 52 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c index 090e66a1b284..bac7976975bd 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c @@ -259,6 +259,14 @@ int amdgpu_sync_resv(struct amdgpu_device *adev, struct amdgpu_sync *sync, return 0; } +/* Free the entry back to the slab */ +static void amdgpu_sync_entry_free(struct amdgpu_sync_entry *e) +{ + hash_del(&e->node); + dma_fence_put(e->fence); + kmem_cache_free(amdgpu_sync_slab, e); +} + /** * amdgpu_sync_peek_fence - get the next fence not signaled yet * @@ -280,9 +288,7 @@ struct dma_fence *amdgpu_sync_peek_fence(struct amdgpu_sync *sync, struct drm_sched_fence *s_fence = to_drm_sched_fence(f); if (dma_fence_is_signaled(f)) { - hash_del(&e->node); - dma_fence_put(f); - kmem_cache_free(amdgpu_sync_slab, e); + amdgpu_sync_entry_free(e); continue; } if (ring && s_fence) { @@ -355,15 +361,42 @@ int amdgpu_sync_clone(struct amdgpu_sync *source, struct amdgpu_sync *clone) if (r) return r; } else { - hash_del(&e->node); - dma_fence_put(f); - kmem_cache_free(amdgpu_sync_slab, e); + amdgpu_sync_entry_free(e); } } return 0; } +/** + * amdgpu_sync_push_to_job - push fences into job + * @sync: sync object to get the fences from + * @job: job to push the fences into + * + * Add all unsignaled fences from sync to job. + */ +int amdgpu_sync_push_to_job(struct amdgpu_sync *sync, struct amdgpu_job *job) +{ + struct amdgpu_sync_entry *e; + struct hlist_node *tmp; + struct dma_fence *f; + int i, r; + + hash_for_each_safe(sync->fences, i, tmp, e, node) { + f = e->fence; + if (dma_fence_is_signaled(f)) { + amdgpu_sync_entry_free(e); + continue; + } + + dma_fence_get(f); + r = drm_sched_job_add_dependency(&job->base, f); + if (r) + return r; + } + return 0; +} + int amdgpu_sync_wait(struct amdgpu_sync *sync, bool intr) { struct amdgpu_sync_entry *e; @@ -375,9 +408,7 @@ int amdgpu_sync_wait(struct amdgpu_sync *sync, bool intr) if (r) return r; - hash_del(&e->node); - dma_fence_put(e->fence); - kmem_cache_free(amdgpu_sync_slab, e); + amdgpu_sync_entry_free(e); } return 0; @@ -396,11 +427,8 @@ void amdgpu_sync_free(struct amdgpu_sync *sync) struct hlist_node *tmp; unsigned int i; - hash_for_each_safe(sync->fences, i, tmp, e, node) { - hash_del(&e->node); - dma_fence_put(e->fence); - kmem_cache_free(amdgpu_sync_slab, e); - } + hash_for_each_safe(sync->fences, i, tmp, e, node) + amdgpu_sync_entry_free(e); } /** diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.h index 2d5c613cda10..cf1e9e858efd 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.h @@ -30,6 +30,7 @@ struct dma_fence; struct dma_resv; struct amdgpu_device; struct amdgpu_ring; +struct amdgpu_job; enum amdgpu_sync_mode { AMDGPU_SYNC_ALWAYS, @@ -54,6 +55,7 @@ struct dma_fence *amdgpu_sync_peek_fence(struct amdgpu_sync *sync, struct amdgpu_ring *ring); struct dma_fence *amdgpu_sync_get_fence(struct amdgpu_sync *sync); int amdgpu_sync_clone(struct amdgpu_sync *source, struct amdgpu_sync *clone); +int amdgpu_sync_push_to_job(struct amdgpu_sync *sync, struct amdgpu_job *job); int amdgpu_sync_wait(struct amdgpu_sync *sync, bool intr); void amdgpu_sync_free(struct amdgpu_sync *sync); int amdgpu_sync_init(void); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_sdma.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_sdma.c index 6768af365f3b..df6fd6d6a82c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_sdma.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_sdma.c @@ -87,6 +87,7 @@ static int amdgpu_vm_sdma_prepare(struct amdgpu_vm_update_params *p, struct dma_resv *resv, enum amdgpu_sync_mode sync_mode) { + struct amdgpu_sync sync; int r; r = amdgpu_vm_sdma_alloc_job(p, 0); @@ -96,7 +97,12 @@ static int amdgpu_vm_sdma_prepare(struct amdgpu_vm_update_params *p, if (!resv) return 0; - return amdgpu_sync_resv(p->adev, &p->job->sync, resv, sync_mode, p->vm); + amdgpu_sync_create(&sync); + r = amdgpu_sync_resv(p->adev, &sync, resv, sync_mode, p->vm); + if (!r) + r = amdgpu_sync_push_to_job(&sync, p->job); + amdgpu_sync_free(&sync); + return r; } /** @@ -225,7 +231,7 @@ static int amdgpu_vm_sdma_update(struct amdgpu_vm_update_params *p, /* Wait for PD/PT moves to be completed */ dma_resv_iter_begin(&cursor, bo->tbo.base.resv, DMA_RESV_USAGE_KERNEL); dma_resv_for_each_fence_unlocked(&cursor, fence) { - r = amdgpu_sync_fence(&p->job->sync, fence); + r = drm_sched_job_add_dependency(&p->job->base, fence); if (r) { dma_resv_iter_end(&cursor); return r; -- cgit From 46e0270c71d33e9764dd5c69bfbca7b581cec1c7 Mon Sep 17 00:00:00 2001 From: Christian König Date: Thu, 29 Sep 2022 13:57:34 +0200 Subject: drm/amdgpu: use scheduler dependencies for UVD msgs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of putting that into the job sync object. Signed-off-by: Christian König Reviewed-by: Luben Tuikov Link: https://patchwork.freedesktop.org/patch/msgid/20221014084641.128280-10-christian.koenig@amd.com --- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index 8baddf79635b..e00bb654e24b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -1177,9 +1177,9 @@ static int amdgpu_uvd_send_msg(struct amdgpu_ring *ring, struct amdgpu_bo *bo, if (r) goto err_free; } else { - r = amdgpu_sync_resv(adev, &job->sync, bo->tbo.base.resv, - AMDGPU_SYNC_ALWAYS, - AMDGPU_FENCE_OWNER_UNDEFINED); + r = drm_sched_job_add_resv_dependencies(&job->base, + bo->tbo.base.resv, + DMA_RESV_USAGE_KERNEL); if (r) goto err_free; -- cgit From 1728baa7e4e60054bf13dd9b1212d133cbd53b3f Mon Sep 17 00:00:00 2001 From: Christian König Date: Thu, 29 Sep 2022 14:04:01 +0200 Subject: drm/amdgpu: use scheduler dependencies for CS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Entirely remove the sync obj in the job. Signed-off-by: Christian König Reviewed-by: Luben Tuikov Link: https://patchwork.freedesktop.org/patch/msgid/20221014084641.128280-11-christian.koenig@amd.com --- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 21 ++++++++++----------- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.h | 2 ++ drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 9 +-------- drivers/gpu/drm/amd/amdgpu/amdgpu_job.h | 1 - 4 files changed, 13 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index d45b86bcf7fa..0528c2b1db6e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -426,7 +426,7 @@ static int amdgpu_cs_p2_dependencies(struct amdgpu_cs_parser *p, dma_fence_put(old); } - r = amdgpu_sync_fence(&p->gang_leader->sync, fence); + r = amdgpu_sync_fence(&p->sync, fence); dma_fence_put(fence); if (r) return r; @@ -448,7 +448,7 @@ static int amdgpu_syncobj_lookup_and_add(struct amdgpu_cs_parser *p, return r; } - r = amdgpu_sync_fence(&p->gang_leader->sync, fence); + r = amdgpu_sync_fence(&p->sync, fence); if (r) goto error; @@ -1108,7 +1108,7 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p) if (r) return r; - r = amdgpu_sync_fence(&job->sync, fpriv->prt_va->last_pt_update); + r = amdgpu_sync_fence(&p->sync, fpriv->prt_va->last_pt_update); if (r) return r; @@ -1119,7 +1119,7 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p) if (r) return r; - r = amdgpu_sync_fence(&job->sync, bo_va->last_pt_update); + r = amdgpu_sync_fence(&p->sync, bo_va->last_pt_update); if (r) return r; } @@ -1138,7 +1138,7 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p) if (r) return r; - r = amdgpu_sync_fence(&job->sync, bo_va->last_pt_update); + r = amdgpu_sync_fence(&p->sync, bo_va->last_pt_update); if (r) return r; } @@ -1151,7 +1151,7 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p) if (r) return r; - r = amdgpu_sync_fence(&job->sync, vm->last_update); + r = amdgpu_sync_fence(&p->sync, vm->last_update); if (r) return r; @@ -1183,7 +1183,6 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p) static int amdgpu_cs_sync_rings(struct amdgpu_cs_parser *p) { struct amdgpu_fpriv *fpriv = p->filp->driver_priv; - struct amdgpu_job *leader = p->gang_leader; struct amdgpu_bo_list_entry *e; unsigned int i; int r; @@ -1195,14 +1194,14 @@ static int amdgpu_cs_sync_rings(struct amdgpu_cs_parser *p) sync_mode = amdgpu_bo_explicit_sync(bo) ? AMDGPU_SYNC_EXPLICIT : AMDGPU_SYNC_NE_OWNER; - r = amdgpu_sync_resv(p->adev, &leader->sync, resv, sync_mode, + r = amdgpu_sync_resv(p->adev, &p->sync, resv, sync_mode, &fpriv->vm); if (r) return r; } - for (i = 0; i < p->gang_size - 1; ++i) { - r = amdgpu_sync_clone(&leader->sync, &p->jobs[i]->sync); + for (i = 0; i < p->gang_size; ++i) { + r = amdgpu_sync_push_to_job(&p->sync, p->jobs[i]); if (r) return r; } @@ -1248,7 +1247,7 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, struct dma_fence *fence; fence = &p->jobs[i]->base.s_fence->scheduled; - r = amdgpu_sync_fence(&leader->sync, fence); + r = drm_sched_job_add_dependency(&leader->base, fence); if (r) goto error_cleanup; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.h index cbaa19b2b8a3..207e801c24ed 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.h @@ -75,6 +75,8 @@ struct amdgpu_cs_parser { unsigned num_post_deps; struct amdgpu_cs_post_dep *post_deps; + + struct amdgpu_sync sync; }; int amdgpu_cs_find_mapping(struct amdgpu_cs_parser *parser, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c index 6c126797d6a4..16f7bcc9c654 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c @@ -107,7 +107,6 @@ int amdgpu_job_alloc(struct amdgpu_device *adev, struct amdgpu_vm *vm, (*job)->base.sched = &adev->rings[0]->sched; (*job)->vm = vm; - amdgpu_sync_create(&(*job)->sync); amdgpu_sync_create(&(*job)->explicit_sync); (*job)->vram_lost_counter = atomic_read(&adev->vram_lost_counter); (*job)->vm_pd_addr = AMDGPU_BO_INVALID_OFFSET; @@ -175,9 +174,7 @@ static void amdgpu_job_free_cb(struct drm_sched_job *s_job) drm_sched_job_cleanup(s_job); - amdgpu_sync_free(&job->sync); amdgpu_sync_free(&job->explicit_sync); - dma_fence_put(&job->hw_fence); } @@ -203,7 +200,6 @@ void amdgpu_job_free(struct amdgpu_job *job) drm_sched_job_cleanup(&job->base); amdgpu_job_free_resources(job); - amdgpu_sync_free(&job->sync); amdgpu_sync_free(&job->explicit_sync); if (job->gang_submit != &job->base.s_fence->scheduled) dma_fence_put(job->gang_submit); @@ -247,10 +243,9 @@ amdgpu_job_dependency(struct drm_sched_job *sched_job, { struct amdgpu_ring *ring = to_amdgpu_ring(s_entity->rq->sched); struct amdgpu_job *job = to_amdgpu_job(sched_job); - struct dma_fence *fence; + struct dma_fence *fence = NULL; int r; - fence = amdgpu_sync_get_fence(&job->sync); while (!fence && job->vm && !job->vmid) { r = amdgpu_vmid_grab(job->vm, ring, job, &fence); if (r) @@ -274,8 +269,6 @@ static struct dma_fence *amdgpu_job_run(struct drm_sched_job *sched_job) job = to_amdgpu_job(sched_job); finished = &job->base.s_fence->finished; - BUG_ON(amdgpu_sync_peek_fence(&job->sync, NULL)); - trace_amdgpu_sched_run_job(job); /* Skip job if VRAM is lost and never resubmit gangs */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h index ef4bdde7c918..a372802ea4e0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h @@ -47,7 +47,6 @@ enum amdgpu_ib_pool_type; struct amdgpu_job { struct drm_sched_job base; struct amdgpu_vm *vm; - struct amdgpu_sync sync; struct amdgpu_sync explicit_sync; struct dma_fence hw_fence; struct dma_fence *gang_submit; -- cgit From 2cf9886e281678ae9ee57e24a656749071d543bb Mon Sep 17 00:00:00 2001 From: Christian König Date: Thu, 29 Sep 2022 14:08:13 +0200 Subject: drm/scheduler: remove drm_sched_dependency_optimized MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not used any more. Signed-off-by: Christian König Reviewed-by: Luben Tuikov Link: https://patchwork.freedesktop.org/patch/msgid/20221014084641.128280-12-christian.koenig@amd.com --- drivers/gpu/drm/scheduler/sched_main.c | 26 -------------------------- include/drm/gpu_scheduler.h | 2 -- 2 files changed, 28 deletions(-) diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index 6e17cdbe27c2..6ce04c2e90c0 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -285,32 +285,6 @@ static void drm_sched_job_done_cb(struct dma_fence *f, struct dma_fence_cb *cb) drm_sched_job_done(s_job); } -/** - * drm_sched_dependency_optimized - test if the dependency can be optimized - * - * @fence: the dependency fence - * @entity: the entity which depends on the above fence - * - * Returns true if the dependency can be optimized and false otherwise - */ -bool drm_sched_dependency_optimized(struct dma_fence* fence, - struct drm_sched_entity *entity) -{ - struct drm_gpu_scheduler *sched = entity->rq->sched; - struct drm_sched_fence *s_fence; - - if (!fence || dma_fence_is_signaled(fence)) - return false; - if (fence->context == entity->fence_context) - return true; - s_fence = to_drm_sched_fence(fence); - if (s_fence && s_fence->sched == sched) - return true; - - return false; -} -EXPORT_SYMBOL(drm_sched_dependency_optimized); - /** * drm_sched_start_timeout - start timeout for reset worker * diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h index 8d1747f3e878..09a1e86bb569 100644 --- a/include/drm/gpu_scheduler.h +++ b/include/drm/gpu_scheduler.h @@ -528,8 +528,6 @@ void drm_sched_resubmit_jobs_ext(struct drm_gpu_scheduler *sched, int max); void drm_sched_increase_karma(struct drm_sched_job *bad); void drm_sched_reset_karma(struct drm_sched_job *bad); void drm_sched_increase_karma_ext(struct drm_sched_job *bad, int type); -bool drm_sched_dependency_optimized(struct dma_fence* fence, - struct drm_sched_entity *entity); void drm_sched_fault(struct drm_gpu_scheduler *sched); void drm_sched_job_kickout(struct drm_sched_job *s_job); -- cgit From 2fdb8a8f07c2f1353770a324fd19b8114e4329ac Mon Sep 17 00:00:00 2001 From: Christian König Date: Thu, 29 Sep 2022 14:50:56 +0200 Subject: drm/scheduler: rework entity flush, kill and fini MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This was buggy because when we had to wait for entities which were killed as well we would just deadlock. Instead move all the dependency handling into the callbacks so that will all happen asynchronously. Signed-off-by: Christian König Reviewed-by: Luben Tuikov Link: https://patchwork.freedesktop.org/patch/msgid/20221014084641.128280-13-christian.koenig@amd.com --- drivers/gpu/drm/scheduler/sched_entity.c | 196 ++++++++++++++----------------- 1 file changed, 91 insertions(+), 105 deletions(-) diff --git a/drivers/gpu/drm/scheduler/sched_entity.c b/drivers/gpu/drm/scheduler/sched_entity.c index dac552f0a75b..26ed81acb41e 100644 --- a/drivers/gpu/drm/scheduler/sched_entity.c +++ b/drivers/gpu/drm/scheduler/sched_entity.c @@ -140,6 +140,73 @@ bool drm_sched_entity_is_ready(struct drm_sched_entity *entity) return true; } +static void drm_sched_entity_kill_jobs_work(struct work_struct *wrk) +{ + struct drm_sched_job *job = container_of(wrk, typeof(*job), work); + + drm_sched_fence_finished(job->s_fence); + WARN_ON(job->s_fence->parent); + job->sched->ops->free_job(job); +} + +/* Signal the scheduler finished fence when the entity in question is killed. */ +static void drm_sched_entity_kill_jobs_cb(struct dma_fence *f, + struct dma_fence_cb *cb) +{ + struct drm_sched_job *job = container_of(cb, struct drm_sched_job, + finish_cb); + int r; + + dma_fence_put(f); + + /* Wait for all dependencies to avoid data corruptions */ + while (!xa_empty(&job->dependencies)) { + f = xa_erase(&job->dependencies, job->last_dependency++); + r = dma_fence_add_callback(f, &job->finish_cb, + drm_sched_entity_kill_jobs_cb); + if (!r) + return; + + dma_fence_put(f); + } + + INIT_WORK(&job->work, drm_sched_entity_kill_jobs_work); + schedule_work(&job->work); +} + +/* Remove the entity from the scheduler and kill all pending jobs */ +static void drm_sched_entity_kill(struct drm_sched_entity *entity) +{ + struct drm_sched_job *job; + struct dma_fence *prev; + + if (!entity->rq) + return; + + spin_lock(&entity->rq_lock); + entity->stopped = true; + drm_sched_rq_remove_entity(entity->rq, entity); + spin_unlock(&entity->rq_lock); + + /* Make sure this entity is not used by the scheduler at the moment */ + wait_for_completion(&entity->entity_idle); + + prev = dma_fence_get(entity->last_scheduled); + while ((job = to_drm_sched_job(spsc_queue_pop(&entity->job_queue)))) { + struct drm_sched_fence *s_fence = job->s_fence; + + dma_fence_set_error(&s_fence->finished, -ESRCH); + + dma_fence_get(&s_fence->finished); + if (!prev || dma_fence_add_callback(prev, &job->finish_cb, + drm_sched_entity_kill_jobs_cb)) + drm_sched_entity_kill_jobs_cb(NULL, &job->finish_cb); + + prev = &s_fence->finished; + } + dma_fence_put(prev); +} + /** * drm_sched_entity_flush - Flush a context entity * @@ -180,91 +247,13 @@ long drm_sched_entity_flush(struct drm_sched_entity *entity, long timeout) /* For killed process disable any more IBs enqueue right now */ last_user = cmpxchg(&entity->last_user, current->group_leader, NULL); if ((!last_user || last_user == current->group_leader) && - (current->flags & PF_EXITING) && (current->exit_code == SIGKILL)) { - spin_lock(&entity->rq_lock); - entity->stopped = true; - drm_sched_rq_remove_entity(entity->rq, entity); - spin_unlock(&entity->rq_lock); - } + (current->flags & PF_EXITING) && (current->exit_code == SIGKILL)) + drm_sched_entity_kill(entity); return ret; } EXPORT_SYMBOL(drm_sched_entity_flush); -static void drm_sched_entity_kill_jobs_work(struct work_struct *wrk) -{ - struct drm_sched_job *job = container_of(wrk, typeof(*job), work); - - drm_sched_fence_finished(job->s_fence); - WARN_ON(job->s_fence->parent); - job->sched->ops->free_job(job); -} - - -/* Signal the scheduler finished fence when the entity in question is killed. */ -static void drm_sched_entity_kill_jobs_cb(struct dma_fence *f, - struct dma_fence_cb *cb) -{ - struct drm_sched_job *job = container_of(cb, struct drm_sched_job, - finish_cb); - - dma_fence_put(f); - INIT_WORK(&job->work, drm_sched_entity_kill_jobs_work); - schedule_work(&job->work); -} - -static struct dma_fence * -drm_sched_job_dependency(struct drm_sched_job *job, - struct drm_sched_entity *entity) -{ - if (!xa_empty(&job->dependencies)) - return xa_erase(&job->dependencies, job->last_dependency++); - - if (job->sched->ops->dependency) - return job->sched->ops->dependency(job, entity); - - return NULL; -} - -static void drm_sched_entity_kill_jobs(struct drm_sched_entity *entity) -{ - struct drm_sched_job *job; - struct dma_fence *f; - int r; - - while ((job = to_drm_sched_job(spsc_queue_pop(&entity->job_queue)))) { - struct drm_sched_fence *s_fence = job->s_fence; - - /* Wait for all dependencies to avoid data corruptions */ - while ((f = drm_sched_job_dependency(job, entity))) { - dma_fence_wait(f, false); - dma_fence_put(f); - } - - drm_sched_fence_scheduled(s_fence); - dma_fence_set_error(&s_fence->finished, -ESRCH); - - /* - * When pipe is hanged by older entity, new entity might - * not even have chance to submit it's first job to HW - * and so entity->last_scheduled will remain NULL - */ - if (!entity->last_scheduled) { - drm_sched_entity_kill_jobs_cb(NULL, &job->finish_cb); - continue; - } - - dma_fence_get(entity->last_scheduled); - r = dma_fence_add_callback(entity->last_scheduled, - &job->finish_cb, - drm_sched_entity_kill_jobs_cb); - if (r == -ENOENT) - drm_sched_entity_kill_jobs_cb(NULL, &job->finish_cb); - else if (r) - DRM_ERROR("fence add callback failed (%d)\n", r); - } -} - /** * drm_sched_entity_fini - Destroy a context entity * @@ -278,33 +267,17 @@ static void drm_sched_entity_kill_jobs(struct drm_sched_entity *entity) */ void drm_sched_entity_fini(struct drm_sched_entity *entity) { - struct drm_gpu_scheduler *sched = NULL; - - if (entity->rq) { - sched = entity->rq->sched; - drm_sched_rq_remove_entity(entity->rq, entity); - } - - /* Consumption of existing IBs wasn't completed. Forcefully - * remove them here. + /* + * If consumption of existing IBs wasn't completed. Forcefully remove + * them here. Also makes sure that the scheduler won't touch this entity + * any more. */ - if (spsc_queue_count(&entity->job_queue)) { - if (sched) { - /* - * Wait for thread to idle to make sure it isn't processing - * this entity. - */ - wait_for_completion(&entity->entity_idle); - - } - if (entity->dependency) { - dma_fence_remove_callback(entity->dependency, - &entity->cb); - dma_fence_put(entity->dependency); - entity->dependency = NULL; - } + drm_sched_entity_kill(entity); - drm_sched_entity_kill_jobs(entity); + if (entity->dependency) { + dma_fence_remove_callback(entity->dependency, &entity->cb); + dma_fence_put(entity->dependency); + entity->dependency = NULL; } dma_fence_put(entity->last_scheduled); @@ -416,6 +389,19 @@ static bool drm_sched_entity_add_dependency_cb(struct drm_sched_entity *entity) return false; } +static struct dma_fence * +drm_sched_job_dependency(struct drm_sched_job *job, + struct drm_sched_entity *entity) +{ + if (!xa_empty(&job->dependencies)) + return xa_erase(&job->dependencies, job->last_dependency++); + + if (job->sched->ops->dependency) + return job->sched->ops->dependency(job, entity); + + return NULL; +} + struct drm_sched_job *drm_sched_entity_pop_job(struct drm_sched_entity *entity) { struct drm_sched_job *sched_job; -- cgit From a82f30b04c6aaefe62cbbfd297e1bb23435b6b3a Mon Sep 17 00:00:00 2001 From: Christian König Date: Thu, 29 Sep 2022 15:01:57 +0200 Subject: drm/scheduler: rename dependency callback into prepare_job MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This now matches much better what this is doing. Signed-off-by: Christian König Reviewed-by: Luben Tuikov Link: https://patchwork.freedesktop.org/patch/msgid/20221014084641.128280-14-christian.koenig@amd.com --- drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 4 ++-- drivers/gpu/drm/scheduler/sched_entity.c | 4 ++-- include/drm/gpu_scheduler.h | 13 ++++++------- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c index 16f7bcc9c654..172572cfed36 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c @@ -238,7 +238,7 @@ int amdgpu_job_submit_direct(struct amdgpu_job *job, struct amdgpu_ring *ring, } static struct dma_fence * -amdgpu_job_dependency(struct drm_sched_job *sched_job, +amdgpu_job_prepare_job(struct drm_sched_job *sched_job, struct drm_sched_entity *s_entity) { struct amdgpu_ring *ring = to_amdgpu_ring(s_entity->rq->sched); @@ -327,7 +327,7 @@ void amdgpu_job_stop_all_jobs_on_sched(struct drm_gpu_scheduler *sched) } const struct drm_sched_backend_ops amdgpu_sched_ops = { - .dependency = amdgpu_job_dependency, + .prepare_job = amdgpu_job_prepare_job, .run_job = amdgpu_job_run, .timedout_job = amdgpu_job_timedout, .free_job = amdgpu_job_free_cb diff --git a/drivers/gpu/drm/scheduler/sched_entity.c b/drivers/gpu/drm/scheduler/sched_entity.c index 26ed81acb41e..52bf9056807a 100644 --- a/drivers/gpu/drm/scheduler/sched_entity.c +++ b/drivers/gpu/drm/scheduler/sched_entity.c @@ -396,8 +396,8 @@ drm_sched_job_dependency(struct drm_sched_job *job, if (!xa_empty(&job->dependencies)) return xa_erase(&job->dependencies, job->last_dependency++); - if (job->sched->ops->dependency) - return job->sched->ops->dependency(job, entity); + if (job->sched->ops->prepare_job) + return job->sched->ops->prepare_job(job, entity); return NULL; } diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h index 09a1e86bb569..e40baefadc3a 100644 --- a/include/drm/gpu_scheduler.h +++ b/include/drm/gpu_scheduler.h @@ -320,7 +320,7 @@ struct drm_sched_job { */ union { struct dma_fence_cb finish_cb; - struct work_struct work; + struct work_struct work; }; uint64_t id; @@ -368,18 +368,17 @@ enum drm_gpu_sched_stat { */ struct drm_sched_backend_ops { /** - * @dependency: + * @prepare_job: * * Called when the scheduler is considering scheduling this job next, to * get another struct dma_fence for this job to block on. Once it * returns NULL, run_job() may be called. * - * If a driver exclusively uses drm_sched_job_add_dependency() and - * drm_sched_job_add_implicit_dependencies() this can be ommitted and - * left as NULL. + * Can be NULL if no additional preparation to the dependencies are + * necessary. Skipped when jobs are killed instead of run. */ - struct dma_fence *(*dependency)(struct drm_sched_job *sched_job, - struct drm_sched_entity *s_entity); + struct dma_fence *(*prepare_job)(struct drm_sched_job *sched_job, + struct drm_sched_entity *s_entity); /** * @run_job: Called to execute the job once all of the dependencies -- cgit From b9a2b0944cf77aadbeb82b05c3d1faa472d83778 Mon Sep 17 00:00:00 2001 From: Jouni Högander Date: Wed, 2 Nov 2022 19:45:43 +0200 Subject: drm/i915/psr: Ensure panel granularity aligns with DSC slice height MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not enable psr2 if panel ganularity is not aligned with DSC slice height when DSC is enabled Cc: José Roberto de Souza Cc: Mika Kahola Signed-off-by: Jouni Högander Reviewed-by: José Roberto de Souza Reviewed-by: Manasi Navare Signed-off-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20221102174544.2288205-2-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_psr.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index e11b0592055f..57575b5c6d48 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -779,6 +779,7 @@ static bool psr2_granularity_check(struct intel_dp *intel_dp, struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + const struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config; const int crtc_hdisplay = crtc_state->hw.adjusted_mode.crtc_hdisplay; const int crtc_vdisplay = crtc_state->hw.adjusted_mode.crtc_vdisplay; u16 y_granularity = 0; @@ -809,6 +810,10 @@ static bool psr2_granularity_check(struct intel_dp *intel_dp, if (y_granularity == 0 || crtc_vdisplay % y_granularity) return false; + if (crtc_state->dsc.compression_enable && + vdsc_cfg->slice_height % y_granularity) + return false; + crtc_state->su_y_granularity = y_granularity; return true; } -- cgit From f46e3f5ffc0fff6224a27117126008b2f4d94eba Mon Sep 17 00:00:00 2001 From: Jouni Högander Date: Wed, 2 Nov 2022 19:45:44 +0200 Subject: drm/i915/psr: Remove inappropriate DSC slice alignment warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Selective update area is now aligned with DSC slice height when DSC is enabled. Remove inappropriate warning about missing DSC alignment. Cc: José Roberto de Souza Cc: Mika Kahola Fixes: 47d4ae2192cb ("drm/i915/mtl: Extend PSR support") Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/7212 Signed-off-by: Jouni Högander Signed-off-by: Anshuman Gupta Reviewed-by: Mika Kahola Reviewed-by: José Roberto de Souza Signed-off-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20221102174544.2288205-3-jouni.hogander@intel.com --- drivers/gpu/drm/i915/display/intel_psr.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 57575b5c6d48..a75b37851504 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -1684,9 +1684,6 @@ static void intel_psr2_sel_fetch_pipe_alignment(const struct intel_crtc_state *c pipe_clip->y1 -= pipe_clip->y1 % y_alignment; if (pipe_clip->y2 % y_alignment) pipe_clip->y2 = ((pipe_clip->y2 / y_alignment) + 1) * y_alignment; - - if (IS_ALDERLAKE_P(dev_priv) && crtc_state->dsc.compression_enable) - drm_warn(&dev_priv->drm, "Missing PSR2 sel fetch alignment with DSC\n"); } /* -- cgit From 507d7c17cab274016dd43c8661d4586ba7504972 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 2 Nov 2022 12:08:09 +0200 Subject: drm/i915/gmbus: move GPIO enum to gmbus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The GPIO enum is only used in intel_gmbus.c, hide it there. Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/3c386ce08d7d53a45c14c2e7519e4cc78a8161be.1667383630.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_display.h | 18 ------------------ drivers/gpu/drm/i915/display/intel_gmbus.c | 20 +++++++++++++++++++- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index 918c8f432172..3cc85ef3b111 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -61,24 +61,6 @@ struct intel_remapped_info; struct intel_rotation_info; struct pci_dev; -enum i915_gpio { - GPIOA, - GPIOB, - GPIOC, - GPIOD, - GPIOE, - GPIOF, - GPIOG, - GPIOH, - __GPIOI_UNUSED, - GPIOJ, - GPIOK, - GPIOL, - GPIOM, - GPION, - GPIOO, -}; - /* * Keep the pipe enum values fixed: the code assumes that PIPE_A=0, the * rest have consecutive values and match the enum values of transcoders diff --git a/drivers/gpu/drm/i915/display/intel_gmbus.c b/drivers/gpu/drm/i915/display/intel_gmbus.c index 74443f57f62d..860e0f8b6b19 100644 --- a/drivers/gpu/drm/i915/display/intel_gmbus.c +++ b/drivers/gpu/drm/i915/display/intel_gmbus.c @@ -49,9 +49,27 @@ struct intel_gmbus { struct drm_i915_private *i915; }; +enum gmbus_gpio { + GPIOA, + GPIOB, + GPIOC, + GPIOD, + GPIOE, + GPIOF, + GPIOG, + GPIOH, + __GPIOI_UNUSED, + GPIOJ, + GPIOK, + GPIOL, + GPIOM, + GPION, + GPIOO, +}; + struct gmbus_pin { const char *name; - enum i915_gpio gpio; + enum gmbus_gpio gpio; }; /* Map gmbus pin pairs to names and registers. */ -- cgit From 10b60b56a05b495a5ba0ced173ba995e8a373f39 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 2 Nov 2022 12:08:10 +0200 Subject: drm/i915: reduce includes in intel_connector.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only include what's needed. Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/3aa1e27284e0ac308938978ae7da9ea9fbacad9e.1667383630.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_connector.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_connector.h b/drivers/gpu/drm/i915/display/intel_connector.h index 7d7b588d2286..9d2bc261b204 100644 --- a/drivers/gpu/drm/i915/display/intel_connector.h +++ b/drivers/gpu/drm/i915/display/intel_connector.h @@ -6,7 +6,7 @@ #ifndef __INTEL_CONNECTOR_H__ #define __INTEL_CONNECTOR_H__ -#include "intel_display.h" +#include struct drm_connector; struct edid; -- cgit From 19cfeb414ea3d7d1beba0dadc466618e5671805e Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 2 Nov 2022 12:08:11 +0200 Subject: drm/i915: reduce includes in intel_fifo_underrun.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only include what's needed. Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/29b57e168e8af842baad2626959cea258402a2c1.1667383630.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_fifo_underrun.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fifo_underrun.h b/drivers/gpu/drm/i915/display/intel_fifo_underrun.h index e04f22ac1f49..2e47d7d3c101 100644 --- a/drivers/gpu/drm/i915/display/intel_fifo_underrun.h +++ b/drivers/gpu/drm/i915/display/intel_fifo_underrun.h @@ -8,9 +8,8 @@ #include -#include "intel_display.h" - struct drm_i915_private; +enum pipe; bool intel_set_cpu_fifo_underrun_reporting(struct drm_i915_private *dev_priv, enum pipe pipe, bool enable); -- cgit From d29c410f77fd3f7dc632f5f153f455e6163d5449 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 2 Nov 2022 12:08:12 +0200 Subject: drm/i915: un-inline icl_hdr_plane_mask() to simplify includes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This lets us drop the heavy intel_display.h include from intel_sprite.h. Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/16e13b6f207f52f8810a06f71a08e637f6397dc8.1667383630.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_sprite.h | 9 +-------- drivers/gpu/drm/i915/display/skl_universal_plane.c | 5 +++++ drivers/gpu/drm/i915/display/skl_universal_plane.h | 1 + 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_sprite.h b/drivers/gpu/drm/i915/display/intel_sprite.h index 4f63e4967731..4635c7ad23f9 100644 --- a/drivers/gpu/drm/i915/display/intel_sprite.h +++ b/drivers/gpu/drm/i915/display/intel_sprite.h @@ -8,14 +8,13 @@ #include -#include "intel_display.h" - struct drm_device; struct drm_display_mode; struct drm_file; struct drm_i915_private; struct intel_crtc_state; struct intel_plane_state; +enum pipe; /* * FIXME: We should instead only take spinlocks once for the entire update @@ -34,12 +33,6 @@ int intel_sprite_set_colorkey_ioctl(struct drm_device *dev, void *data, int intel_plane_check_src_coordinates(struct intel_plane_state *plane_state); int chv_plane_check_rotation(const struct intel_plane_state *plane_state); -static inline u8 icl_hdr_plane_mask(void) -{ - return BIT(PLANE_PRIMARY) | - BIT(PLANE_SPRITE0) | BIT(PLANE_SPRITE1); -} - int ivb_plane_min_cdclk(const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state); int hsw_plane_min_cdclk(const struct intel_crtc_state *crtc_state, diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c index 7cb713043408..46e10b369a3d 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane.c +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c @@ -246,6 +246,11 @@ bool icl_is_nv12_y_plane(struct drm_i915_private *dev_priv, icl_nv12_y_plane_mask(dev_priv) & BIT(plane_id); } +u8 icl_hdr_plane_mask(void) +{ + return BIT(PLANE_PRIMARY) | BIT(PLANE_SPRITE0) | BIT(PLANE_SPRITE1); +} + bool icl_is_hdr_plane(struct drm_i915_private *dev_priv, enum plane_id plane_id) { return DISPLAY_VER(dev_priv) >= 11 && diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.h b/drivers/gpu/drm/i915/display/skl_universal_plane.h index 351040b64dc7..be64c201f9b3 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane.h +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.h @@ -30,6 +30,7 @@ int skl_calc_main_surface_offset(const struct intel_plane_state *plane_state, bool icl_is_nv12_y_plane(struct drm_i915_private *dev_priv, enum plane_id plane_id); +u8 icl_hdr_plane_mask(void); bool icl_is_hdr_plane(struct drm_i915_private *dev_priv, enum plane_id plane_id); #endif -- cgit From 2461bdb35e8ac4c7943d8277c118d5bba719d99c Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 2 Nov 2022 12:08:13 +0200 Subject: drm/i915/dpio: un-inline the vlv phy/channel mapping functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify the heavy intel_display_types.h header. Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/943dd3e9812138b1cf3ddcfde896cfec006f3847.1667383630.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 1 + drivers/gpu/drm/i915/display/intel_display_types.h | 45 ---------------------- drivers/gpu/drm/i915/display/intel_dpio_phy.c | 42 ++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_dpio_phy.h | 6 +++ drivers/gpu/drm/i915/display/intel_dpll.c | 1 + drivers/gpu/drm/i915/display/intel_pps.c | 1 + 6 files changed, 51 insertions(+), 45 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 0691b49f38f1..31e91dbaa368 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -90,6 +90,7 @@ #include "intel_display_types.h" #include "intel_dmc.h" #include "intel_dp_link_training.h" +#include "intel_dpio_phy.h" #include "intel_dpt.h" #include "intel_dsb.h" #include "intel_fbc.h" diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 5b38937c6bbd..64314273995d 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1803,51 +1803,6 @@ struct intel_dp_mst_encoder { struct intel_connector *connector; }; -static inline enum dpio_channel -vlv_dig_port_to_channel(struct intel_digital_port *dig_port) -{ - switch (dig_port->base.port) { - default: - MISSING_CASE(dig_port->base.port); - fallthrough; - case PORT_B: - case PORT_D: - return DPIO_CH0; - case PORT_C: - return DPIO_CH1; - } -} - -static inline enum dpio_phy -vlv_dig_port_to_phy(struct intel_digital_port *dig_port) -{ - switch (dig_port->base.port) { - default: - MISSING_CASE(dig_port->base.port); - fallthrough; - case PORT_B: - case PORT_C: - return DPIO_PHY0; - case PORT_D: - return DPIO_PHY1; - } -} - -static inline enum dpio_channel -vlv_pipe_to_channel(enum pipe pipe) -{ - switch (pipe) { - default: - MISSING_CASE(pipe); - fallthrough; - case PIPE_A: - case PIPE_C: - return DPIO_CH0; - case PIPE_B: - return DPIO_CH1; - } -} - struct intel_load_detect_pipe { struct drm_atomic_state *restore_state; }; diff --git a/drivers/gpu/drm/i915/display/intel_dpio_phy.c b/drivers/gpu/drm/i915/display/intel_dpio_phy.c index 8732b8722ed7..6fc5b9e58152 100644 --- a/drivers/gpu/drm/i915/display/intel_dpio_phy.c +++ b/drivers/gpu/drm/i915/display/intel_dpio_phy.c @@ -655,6 +655,48 @@ bxt_ddi_phy_get_lane_lat_optim_mask(struct intel_encoder *encoder) return mask; } +enum dpio_channel vlv_dig_port_to_channel(struct intel_digital_port *dig_port) +{ + switch (dig_port->base.port) { + default: + MISSING_CASE(dig_port->base.port); + fallthrough; + case PORT_B: + case PORT_D: + return DPIO_CH0; + case PORT_C: + return DPIO_CH1; + } +} + +enum dpio_phy vlv_dig_port_to_phy(struct intel_digital_port *dig_port) +{ + switch (dig_port->base.port) { + default: + MISSING_CASE(dig_port->base.port); + fallthrough; + case PORT_B: + case PORT_C: + return DPIO_PHY0; + case PORT_D: + return DPIO_PHY1; + } +} + +enum dpio_channel vlv_pipe_to_channel(enum pipe pipe) +{ + switch (pipe) { + default: + MISSING_CASE(pipe); + fallthrough; + case PIPE_A: + case PIPE_C: + return DPIO_CH0; + case PIPE_B: + return DPIO_CH1; + } +} + void chv_set_phy_signal_level(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state, u32 deemph_reg_value, u32 margin_reg_value, diff --git a/drivers/gpu/drm/i915/display/intel_dpio_phy.h b/drivers/gpu/drm/i915/display/intel_dpio_phy.h index 9c3d008e8e1a..828ad58624d8 100644 --- a/drivers/gpu/drm/i915/display/intel_dpio_phy.h +++ b/drivers/gpu/drm/i915/display/intel_dpio_phy.h @@ -10,9 +10,11 @@ enum dpio_channel; enum dpio_phy; +enum pipe; enum port; struct drm_i915_private; struct intel_crtc_state; +struct intel_digital_port; struct intel_encoder; void bxt_port_to_phy_channel(struct drm_i915_private *dev_priv, enum port port, @@ -30,6 +32,10 @@ void bxt_ddi_phy_set_lane_optim_mask(struct intel_encoder *encoder, u8 lane_lat_optim_mask); u8 bxt_ddi_phy_get_lane_lat_optim_mask(struct intel_encoder *encoder); +enum dpio_channel vlv_dig_port_to_channel(struct intel_digital_port *dig_port); +enum dpio_phy vlv_dig_port_to_phy(struct intel_digital_port *dig_port); +enum dpio_channel vlv_pipe_to_channel(enum pipe pipe); + void chv_set_phy_signal_level(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state, u32 deemph_reg_value, u32 margin_reg_value, diff --git a/drivers/gpu/drm/i915/display/intel_dpll.c b/drivers/gpu/drm/i915/display/intel_dpll.c index b15ba78d64d6..fdc6fa4f2ed9 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll.c +++ b/drivers/gpu/drm/i915/display/intel_dpll.c @@ -10,6 +10,7 @@ #include "intel_de.h" #include "intel_display.h" #include "intel_display_types.h" +#include "intel_dpio_phy.h" #include "intel_dpll.h" #include "intel_lvds.h" #include "intel_panel.h" diff --git a/drivers/gpu/drm/i915/display/intel_pps.c b/drivers/gpu/drm/i915/display/intel_pps.c index 21944f5bf3a8..22f5e08d396b 100644 --- a/drivers/gpu/drm/i915/display/intel_pps.c +++ b/drivers/gpu/drm/i915/display/intel_pps.c @@ -9,6 +9,7 @@ #include "intel_display_power_well.h" #include "intel_display_types.h" #include "intel_dp.h" +#include "intel_dpio_phy.h" #include "intel_dpll.h" #include "intel_lvds.h" #include "intel_pps.h" -- cgit From 99417adb60e0d2fada04f57074358fba98e13c4a Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 2 Nov 2022 12:08:14 +0200 Subject: drm/i915/dpio: move dpio_channel and dpio_phy enums to intel_dpio_phy.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reduce the size of intel_display.h by moving out the dpio_channel and dpio_phy enums. Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/7c3ee7a6482540a0267f7b2974d22cab8188707a.1667383630.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_display.h | 11 ----------- drivers/gpu/drm/i915/display/intel_display_power_well.h | 2 +- drivers/gpu/drm/i915/display/intel_dpio_phy.h | 13 +++++++++++-- drivers/gpu/drm/i915/gvt/display.c | 2 ++ drivers/gpu/drm/i915/gvt/handlers.c | 1 + drivers/gpu/drm/i915/gvt/mmio.c | 1 + drivers/gpu/drm/i915/intel_gvt_mmio_table.c | 1 + drivers/gpu/drm/i915/vlv_sideband.c | 2 ++ 8 files changed, 19 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index 3cc85ef3b111..d9c8b8447f9e 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -261,17 +261,6 @@ enum tc_port_mode { TC_PORT_LEGACY, }; -enum dpio_channel { - DPIO_CH0, - DPIO_CH1 -}; - -enum dpio_phy { - DPIO_PHY0, - DPIO_PHY1, - DPIO_PHY2, -}; - enum aux_ch { AUX_CH_A, AUX_CH_B, diff --git a/drivers/gpu/drm/i915/display/intel_display_power_well.h b/drivers/gpu/drm/i915/display/intel_display_power_well.h index e13b521e322a..ba7cb977e7c7 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power_well.h +++ b/drivers/gpu/drm/i915/display/intel_display_power_well.h @@ -7,8 +7,8 @@ #include -#include "intel_display.h" #include "intel_display_power.h" +#include "intel_dpio_phy.h" struct drm_i915_private; struct i915_power_well; diff --git a/drivers/gpu/drm/i915/display/intel_dpio_phy.h b/drivers/gpu/drm/i915/display/intel_dpio_phy.h index 828ad58624d8..9c7725dacb47 100644 --- a/drivers/gpu/drm/i915/display/intel_dpio_phy.h +++ b/drivers/gpu/drm/i915/display/intel_dpio_phy.h @@ -8,8 +8,6 @@ #include -enum dpio_channel; -enum dpio_phy; enum pipe; enum port; struct drm_i915_private; @@ -17,6 +15,17 @@ struct intel_crtc_state; struct intel_digital_port; struct intel_encoder; +enum dpio_channel { + DPIO_CH0, + DPIO_CH1, +}; + +enum dpio_phy { + DPIO_PHY0, + DPIO_PHY1, + DPIO_PHY2, +}; + void bxt_port_to_phy_channel(struct drm_i915_private *dev_priv, enum port port, enum dpio_phy *phy, enum dpio_channel *ch); void bxt_ddi_phy_set_signal_levels(struct intel_encoder *encoder, diff --git a/drivers/gpu/drm/i915/gvt/display.c b/drivers/gpu/drm/i915/gvt/display.c index c7722c818b4d..c033249e73f4 100644 --- a/drivers/gpu/drm/i915/gvt/display.c +++ b/drivers/gpu/drm/i915/gvt/display.c @@ -36,6 +36,8 @@ #include "i915_reg.h" #include "gvt.h" +#include "display/intel_dpio_phy.h" + static int get_edp_pipe(struct intel_vgpu *vgpu) { u32 data = vgpu_vreg(vgpu, _TRANS_DDI_FUNC_CTL_EDP); diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c index e7e33f95cc51..a2439a009cad 100644 --- a/drivers/gpu/drm/i915/gvt/handlers.c +++ b/drivers/gpu/drm/i915/gvt/handlers.c @@ -43,6 +43,7 @@ #include "intel_mchbar_regs.h" #include "display/intel_display_types.h" #include "display/intel_dmc_regs.h" +#include "display/intel_dpio_phy.h" #include "display/intel_fbc.h" #include "display/vlv_dsi_pll_regs.h" #include "gt/intel_gt_regs.h" diff --git a/drivers/gpu/drm/i915/gvt/mmio.c b/drivers/gpu/drm/i915/gvt/mmio.c index 9acc00505fde..5b5def6ddef7 100644 --- a/drivers/gpu/drm/i915/gvt/mmio.c +++ b/drivers/gpu/drm/i915/gvt/mmio.c @@ -37,6 +37,7 @@ #include "i915_reg.h" #include "gvt.h" +#include "display/intel_dpio_phy.h" #include "gt/intel_gt_regs.h" /** diff --git a/drivers/gpu/drm/i915/intel_gvt_mmio_table.c b/drivers/gpu/drm/i915/intel_gvt_mmio_table.c index e015bc91a26f..26f6418af2f7 100644 --- a/drivers/gpu/drm/i915/intel_gvt_mmio_table.c +++ b/drivers/gpu/drm/i915/intel_gvt_mmio_table.c @@ -6,6 +6,7 @@ #include "display/intel_audio_regs.h" #include "display/intel_backlight_regs.h" #include "display/intel_dmc_regs.h" +#include "display/intel_dpio_phy.h" #include "display/vlv_dsi_pll_regs.h" #include "gt/intel_gt_regs.h" #include "gvt/gvt.h" diff --git a/drivers/gpu/drm/i915/vlv_sideband.c b/drivers/gpu/drm/i915/vlv_sideband.c index c26001300ebd..6eea6e1a99c0 100644 --- a/drivers/gpu/drm/i915/vlv_sideband.c +++ b/drivers/gpu/drm/i915/vlv_sideband.c @@ -8,6 +8,8 @@ #include "i915_reg.h" #include "vlv_sideband.h" +#include "display/intel_dpio_phy.h" + /* * IOSF sideband, see VLV2_SidebandMsg_HAS.docx and * VLV_VLV2_PUNIT_HAS_0.8.docx -- cgit From 50ae1a1c5edee3c6dfa3b7db7379ac0c4466051b Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 2 Nov 2022 12:08:15 +0200 Subject: drm/i915: reduce includes in intel_display_power.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only include what's needed. Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/a7f41cf6d13ee78c0b3a7c5927680bb94edfc5fb.1667383630.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_display_power.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_power.h b/drivers/gpu/drm/i915/display/intel_display_power.h index 7136ea3f233e..1e77e52c87fe 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.h +++ b/drivers/gpu/drm/i915/display/intel_display_power.h @@ -6,11 +6,12 @@ #ifndef __INTEL_DISPLAY_POWER_H__ #define __INTEL_DISPLAY_POWER_H__ -#include "intel_runtime_pm.h" +#include "intel_wakeref.h" enum aux_ch; enum dpio_channel; enum dpio_phy; +enum i915_drm_suspend_mode; enum port; struct drm_i915_private; struct i915_power_well; -- cgit From 356d725d62fe9d60157fcfd482ccc3fc70ee1c6c Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 2 Nov 2022 12:08:16 +0200 Subject: drm/i915/display: reduce the includes in intel_dvo_dev.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only include what's needed. Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/8523aa88daaf2dbf0ce138980142dbcd6d1ae0bc.1667383630.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_dvo_dev.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dvo_dev.h b/drivers/gpu/drm/i915/display/intel_dvo_dev.h index 50205f064d93..ecff7b190856 100644 --- a/drivers/gpu/drm/i915/display/intel_dvo_dev.h +++ b/drivers/gpu/drm/i915/display/intel_dvo_dev.h @@ -23,12 +23,12 @@ #ifndef __INTEL_DVO_DEV_H__ #define __INTEL_DVO_DEV_H__ -#include - -#include - #include "i915_reg_defs.h" +enum drm_connector_status; +struct drm_display_mode; +struct i2c_adapter; + struct intel_dvo_device { const char *name; int type; -- cgit From 22b2c7691cace5928fffef878a0d2d7435abbf51 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 2 Nov 2022 12:08:17 +0200 Subject: drm/i915/display: reduce includes in intel_hdmi.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only include what's needed. Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/5949a57979dae615731b6ff54d5d150b91e34d27.1667383630.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_hdmi.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.h b/drivers/gpu/drm/i915/display/intel_hdmi.h index 93f65a917c36..774dda2376ed 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.h +++ b/drivers/gpu/drm/i915/display/intel_hdmi.h @@ -6,20 +6,20 @@ #ifndef __INTEL_HDMI_H__ #define __INTEL_HDMI_H__ -#include #include +enum hdmi_infoframe_type; +enum port; struct drm_connector; +struct drm_connector_state; struct drm_encoder; struct drm_i915_private; struct intel_connector; +struct intel_crtc_state; struct intel_digital_port; struct intel_encoder; -struct intel_crtc_state; struct intel_hdmi; -struct drm_connector_state; union hdmi_infoframe; -enum port; void intel_hdmi_init_connector(struct intel_digital_port *dig_port, struct intel_connector *intel_connector); -- cgit From 831209ec305ee9984a5036695cf73a9eb3f755bd Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 2 Nov 2022 12:08:18 +0200 Subject: drm/i915/display: reduce includes in g4x_dp.h includes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only include what's needed. Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/e68c71ad1c1c1de7f5bc659edeb208818cddde72.1667383630.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/g4x_dp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/g4x_dp.h b/drivers/gpu/drm/i915/display/g4x_dp.h index e1f50263a725..a38b3e1e01d3 100644 --- a/drivers/gpu/drm/i915/display/g4x_dp.h +++ b/drivers/gpu/drm/i915/display/g4x_dp.h @@ -8,7 +8,7 @@ #include -#include "i915_reg.h" +#include "i915_reg_defs.h" enum pipe; enum port; -- cgit From ad7632ff0ebfacab5936e70a4187c2f0fa789627 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 2 Nov 2022 12:08:19 +0200 Subject: drm/i915/irq: make gen2_irq_init()/gen2_irq_reset() static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The gen2 irq functions aren't used outside of i915_irq.h. Make them static, and remove the useless macro wrappers. Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/b28f45ef4ef69ab7a6f96ffa3fa3118994667332.1667383630.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/i915_irq.c | 10 +++++----- drivers/gpu/drm/i915/i915_irq.h | 9 --------- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index b141001a090a..b232a96478f6 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -248,7 +248,7 @@ void gen3_irq_reset(struct intel_uncore *uncore, i915_reg_t imr, intel_uncore_posting_read(uncore, iir); } -void gen2_irq_reset(struct intel_uncore *uncore) +static void gen2_irq_reset(struct intel_uncore *uncore) { intel_uncore_write16(uncore, GEN2_IMR, 0xffff); intel_uncore_posting_read16(uncore, GEN2_IMR); @@ -309,8 +309,8 @@ void gen3_irq_init(struct intel_uncore *uncore, intel_uncore_posting_read(uncore, imr); } -void gen2_irq_init(struct intel_uncore *uncore, - u32 imr_val, u32 ier_val) +static void gen2_irq_init(struct intel_uncore *uncore, + u32 imr_val, u32 ier_val) { gen2_assert_iir_is_zero(uncore); @@ -3871,7 +3871,7 @@ static void i8xx_irq_reset(struct drm_i915_private *dev_priv) i9xx_pipestat_irq_reset(dev_priv); - GEN2_IRQ_RESET(uncore); + gen2_irq_reset(uncore); dev_priv->irq_mask = ~0u; } @@ -3897,7 +3897,7 @@ static void i8xx_irq_postinstall(struct drm_i915_private *dev_priv) I915_MASTER_ERROR_INTERRUPT | I915_USER_INTERRUPT; - GEN2_IRQ_INIT(uncore, dev_priv->irq_mask, enable_mask); + gen2_irq_init(uncore, dev_priv->irq_mask, enable_mask); /* Interrupt setup is already guaranteed to be single-threaded, this is * just to make the assert_spin_locked check happy. */ diff --git a/drivers/gpu/drm/i915/i915_irq.h b/drivers/gpu/drm/i915/i915_irq.h index 82639d9d7e82..9b004fc3444e 100644 --- a/drivers/gpu/drm/i915/i915_irq.h +++ b/drivers/gpu/drm/i915/i915_irq.h @@ -90,12 +90,9 @@ void i965_disable_vblank(struct drm_crtc *crtc); void ilk_disable_vblank(struct drm_crtc *crtc); void bdw_disable_vblank(struct drm_crtc *crtc); -void gen2_irq_reset(struct intel_uncore *uncore); void gen3_irq_reset(struct intel_uncore *uncore, i915_reg_t imr, i915_reg_t iir, i915_reg_t ier); -void gen2_irq_init(struct intel_uncore *uncore, - u32 imr_val, u32 ier_val); void gen3_irq_init(struct intel_uncore *uncore, i915_reg_t imr, u32 imr_val, i915_reg_t ier, u32 ier_val, @@ -111,9 +108,6 @@ void gen3_irq_init(struct intel_uncore *uncore, #define GEN3_IRQ_RESET(uncore, type) \ gen3_irq_reset((uncore), type##IMR, type##IIR, type##IER) -#define GEN2_IRQ_RESET(uncore) \ - gen2_irq_reset(uncore) - #define GEN8_IRQ_INIT_NDX(uncore, type, which, imr_val, ier_val) \ ({ \ unsigned int which_ = which; \ @@ -129,7 +123,4 @@ void gen3_irq_init(struct intel_uncore *uncore, type##IER, ier_val, \ type##IIR) -#define GEN2_IRQ_INIT(uncore, imr_val, ier_val) \ - gen2_irq_init((uncore), imr_val, ier_val) - #endif /* __I915_IRQ_H__ */ -- cgit From a4df7ac78513131abcaeafd9dc12467e2463f573 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 26 Oct 2022 14:38:56 +0300 Subject: drm/i915: Use sizeof(variable) instead sizeof(type) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use sizeof(variable) instead of sizeof(type) in the hopes of less chance of screwing things up. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221026113906.10551-2-ville.syrjala@linux.intel.com Reviewed-by: Ankit Nautiyal --- drivers/gpu/drm/i915/display/intel_color.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index 4bb113c39f4b..92cc43d5bad6 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -565,7 +565,7 @@ create_linear_lut(struct drm_i915_private *i915, int lut_size) int i; blob = drm_property_create_blob(&i915->drm, - sizeof(struct drm_color_lut) * lut_size, + sizeof(lut[0]) * lut_size, NULL); if (IS_ERR(blob)) return blob; @@ -1895,7 +1895,7 @@ static struct drm_property_blob *i9xx_read_lut_8(struct intel_crtc *crtc) int i; blob = drm_property_create_blob(&dev_priv->drm, - sizeof(struct drm_color_lut) * LEGACY_LUT_LENGTH, + sizeof(lut[0]) * LEGACY_LUT_LENGTH, NULL); if (IS_ERR(blob)) return NULL; @@ -1930,7 +1930,7 @@ static struct drm_property_blob *i965_read_lut_10p6(struct intel_crtc *crtc) struct drm_color_lut *lut; blob = drm_property_create_blob(&dev_priv->drm, - sizeof(struct drm_color_lut) * lut_size, + sizeof(lut[0]) * lut_size, NULL); if (IS_ERR(blob)) return NULL; @@ -1973,7 +1973,7 @@ static struct drm_property_blob *chv_read_cgm_gamma(struct intel_crtc *crtc) struct drm_color_lut *lut; blob = drm_property_create_blob(&dev_priv->drm, - sizeof(struct drm_color_lut) * lut_size, + sizeof(lut[0]) * lut_size, NULL); if (IS_ERR(blob)) return NULL; @@ -2009,7 +2009,7 @@ static struct drm_property_blob *ilk_read_lut_8(struct intel_crtc *crtc) int i; blob = drm_property_create_blob(&dev_priv->drm, - sizeof(struct drm_color_lut) * LEGACY_LUT_LENGTH, + sizeof(lut[0]) * LEGACY_LUT_LENGTH, NULL); if (IS_ERR(blob)) return NULL; @@ -2034,7 +2034,7 @@ static struct drm_property_blob *ilk_read_lut_10(struct intel_crtc *crtc) struct drm_color_lut *lut; blob = drm_property_create_blob(&dev_priv->drm, - sizeof(struct drm_color_lut) * lut_size, + sizeof(lut[0]) * lut_size, NULL); if (IS_ERR(blob)) return NULL; @@ -2087,7 +2087,7 @@ static struct drm_property_blob *bdw_read_lut_10(struct intel_crtc *crtc, drm_WARN_ON(&dev_priv->drm, lut_size != hw_lut_size); blob = drm_property_create_blob(&dev_priv->drm, - sizeof(struct drm_color_lut) * lut_size, + sizeof(lut[0]) * lut_size, NULL); if (IS_ERR(blob)) return NULL; @@ -2138,7 +2138,7 @@ icl_read_lut_multi_segment(struct intel_crtc *crtc) struct drm_color_lut *lut; blob = drm_property_create_blob(&dev_priv->drm, - sizeof(struct drm_color_lut) * lut_size, + sizeof(lut[0]) * lut_size, NULL); if (IS_ERR(blob)) return NULL; -- cgit From 05ca98523481aa687c5a8dce8939fec539632153 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 26 Oct 2022 14:38:57 +0300 Subject: drm/i915: Use _MMIO_PIPE() for SKL_BOTTOM_COLOR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No need to use _MMIO_PIPE2() for SKL_BOTTOM_COLOR since all pipe registers are evenly spread on skl+. Switch to _MMIO_PIPE() and thus avoid the hidden dev_priv. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221026113906.10551-3-ville.syrjala@linux.intel.com Reviewed-by: Ankit Nautiyal --- drivers/gpu/drm/i915/i915_reg.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index c5e180aec344..5a062ee46ed1 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3747,9 +3747,10 @@ /* Skylake+ pipe bottom (background) color */ #define _SKL_BOTTOM_COLOR_A 0x70034 +#define _SKL_BOTTOM_COLOR_B 0x71034 #define SKL_BOTTOM_COLOR_GAMMA_ENABLE REG_BIT(31) #define SKL_BOTTOM_COLOR_CSC_ENABLE REG_BIT(30) -#define SKL_BOTTOM_COLOR(pipe) _MMIO_PIPE2(pipe, _SKL_BOTTOM_COLOR_A) +#define SKL_BOTTOM_COLOR(pipe) _MMIO_PIPE(pipe, _SKL_BOTTOM_COLOR_A, _SKL_BOTTOM_COLOR_B) #define _ICL_PIPE_A_STATUS 0x70058 #define ICL_PIPESTATUS(pipe) _MMIO_PIPE2(pipe, _ICL_PIPE_A_STATUS) -- cgit From c9d4911cab39a7d91c5115c1f8c0414a69d27974 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 26 Oct 2022 14:38:58 +0300 Subject: drm/i915: s/dev_priv/i915/ in intel_color.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switch intel_color.c over to the modern 'i915' variable naming scehme. The only exceptions are the i9xx LUT access functions which still need the magic 'dev_priv' for the register macros. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221026113906.10551-4-ville.syrjala@linux.intel.com Reviewed-by: Ankit Nautiyal --- drivers/gpu/drm/i915/display/intel_color.c | 278 ++++++++++++++--------------- 1 file changed, 139 insertions(+), 139 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index 92cc43d5bad6..415e0a6839a4 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -184,31 +184,31 @@ static void ilk_update_pipe_csc(struct intel_crtc *crtc, const u16 coeff[9], const u16 postoff[3]) { - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); enum pipe pipe = crtc->pipe; - intel_de_write_fw(dev_priv, PIPE_CSC_PREOFF_HI(pipe), preoff[0]); - intel_de_write_fw(dev_priv, PIPE_CSC_PREOFF_ME(pipe), preoff[1]); - intel_de_write_fw(dev_priv, PIPE_CSC_PREOFF_LO(pipe), preoff[2]); + intel_de_write_fw(i915, PIPE_CSC_PREOFF_HI(pipe), preoff[0]); + intel_de_write_fw(i915, PIPE_CSC_PREOFF_ME(pipe), preoff[1]); + intel_de_write_fw(i915, PIPE_CSC_PREOFF_LO(pipe), preoff[2]); - intel_de_write_fw(dev_priv, PIPE_CSC_COEFF_RY_GY(pipe), + intel_de_write_fw(i915, PIPE_CSC_COEFF_RY_GY(pipe), coeff[0] << 16 | coeff[1]); - intel_de_write_fw(dev_priv, PIPE_CSC_COEFF_BY(pipe), coeff[2] << 16); + intel_de_write_fw(i915, PIPE_CSC_COEFF_BY(pipe), coeff[2] << 16); - intel_de_write_fw(dev_priv, PIPE_CSC_COEFF_RU_GU(pipe), + intel_de_write_fw(i915, PIPE_CSC_COEFF_RU_GU(pipe), coeff[3] << 16 | coeff[4]); - intel_de_write_fw(dev_priv, PIPE_CSC_COEFF_BU(pipe), coeff[5] << 16); + intel_de_write_fw(i915, PIPE_CSC_COEFF_BU(pipe), coeff[5] << 16); - intel_de_write_fw(dev_priv, PIPE_CSC_COEFF_RV_GV(pipe), + intel_de_write_fw(i915, PIPE_CSC_COEFF_RV_GV(pipe), coeff[6] << 16 | coeff[7]); - intel_de_write_fw(dev_priv, PIPE_CSC_COEFF_BV(pipe), coeff[8] << 16); + intel_de_write_fw(i915, PIPE_CSC_COEFF_BV(pipe), coeff[8] << 16); - if (DISPLAY_VER(dev_priv) >= 7) { - intel_de_write_fw(dev_priv, PIPE_CSC_POSTOFF_HI(pipe), + if (DISPLAY_VER(i915) >= 7) { + intel_de_write_fw(i915, PIPE_CSC_POSTOFF_HI(pipe), postoff[0]); - intel_de_write_fw(dev_priv, PIPE_CSC_POSTOFF_ME(pipe), + intel_de_write_fw(i915, PIPE_CSC_POSTOFF_ME(pipe), postoff[1]); - intel_de_write_fw(dev_priv, PIPE_CSC_POSTOFF_LO(pipe), + intel_de_write_fw(i915, PIPE_CSC_POSTOFF_LO(pipe), postoff[2]); } } @@ -218,44 +218,44 @@ static void icl_update_output_csc(struct intel_crtc *crtc, const u16 coeff[9], const u16 postoff[3]) { - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); enum pipe pipe = crtc->pipe; - intel_de_write_fw(dev_priv, PIPE_CSC_OUTPUT_PREOFF_HI(pipe), preoff[0]); - intel_de_write_fw(dev_priv, PIPE_CSC_OUTPUT_PREOFF_ME(pipe), preoff[1]); - intel_de_write_fw(dev_priv, PIPE_CSC_OUTPUT_PREOFF_LO(pipe), preoff[2]); + intel_de_write_fw(i915, PIPE_CSC_OUTPUT_PREOFF_HI(pipe), preoff[0]); + intel_de_write_fw(i915, PIPE_CSC_OUTPUT_PREOFF_ME(pipe), preoff[1]); + intel_de_write_fw(i915, PIPE_CSC_OUTPUT_PREOFF_LO(pipe), preoff[2]); - intel_de_write_fw(dev_priv, PIPE_CSC_OUTPUT_COEFF_RY_GY(pipe), + intel_de_write_fw(i915, PIPE_CSC_OUTPUT_COEFF_RY_GY(pipe), coeff[0] << 16 | coeff[1]); - intel_de_write_fw(dev_priv, PIPE_CSC_OUTPUT_COEFF_BY(pipe), + intel_de_write_fw(i915, PIPE_CSC_OUTPUT_COEFF_BY(pipe), coeff[2] << 16); - intel_de_write_fw(dev_priv, PIPE_CSC_OUTPUT_COEFF_RU_GU(pipe), + intel_de_write_fw(i915, PIPE_CSC_OUTPUT_COEFF_RU_GU(pipe), coeff[3] << 16 | coeff[4]); - intel_de_write_fw(dev_priv, PIPE_CSC_OUTPUT_COEFF_BU(pipe), + intel_de_write_fw(i915, PIPE_CSC_OUTPUT_COEFF_BU(pipe), coeff[5] << 16); - intel_de_write_fw(dev_priv, PIPE_CSC_OUTPUT_COEFF_RV_GV(pipe), + intel_de_write_fw(i915, PIPE_CSC_OUTPUT_COEFF_RV_GV(pipe), coeff[6] << 16 | coeff[7]); - intel_de_write_fw(dev_priv, PIPE_CSC_OUTPUT_COEFF_BV(pipe), + intel_de_write_fw(i915, PIPE_CSC_OUTPUT_COEFF_BV(pipe), coeff[8] << 16); - intel_de_write_fw(dev_priv, PIPE_CSC_OUTPUT_POSTOFF_HI(pipe), postoff[0]); - intel_de_write_fw(dev_priv, PIPE_CSC_OUTPUT_POSTOFF_ME(pipe), postoff[1]); - intel_de_write_fw(dev_priv, PIPE_CSC_OUTPUT_POSTOFF_LO(pipe), postoff[2]); + intel_de_write_fw(i915, PIPE_CSC_OUTPUT_POSTOFF_HI(pipe), postoff[0]); + intel_de_write_fw(i915, PIPE_CSC_OUTPUT_POSTOFF_ME(pipe), postoff[1]); + intel_de_write_fw(i915, PIPE_CSC_OUTPUT_POSTOFF_LO(pipe), postoff[2]); } static bool ilk_csc_limited_range(const struct intel_crtc_state *crtc_state) { - struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); /* * FIXME if there's a gamma LUT after the CSC, we should * do the range compression using the gamma LUT instead. */ return crtc_state->limited_color_range && - (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv) || - IS_DISPLAY_VER(dev_priv, 9, 10)); + (IS_HASWELL(i915) || IS_BROADWELL(i915) || + IS_DISPLAY_VER(i915, 9, 10)); } static void ilk_csc_convert_ctm(const struct intel_crtc_state *crtc_state, @@ -313,7 +313,7 @@ static void ilk_csc_convert_ctm(const struct intel_crtc_state *crtc_state, static void ilk_load_csc_matrix(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); bool limited_color_range = ilk_csc_limited_range(crtc_state); if (crtc_state->hw.ctm) { @@ -339,7 +339,7 @@ static void ilk_load_csc_matrix(const struct intel_crtc_state *crtc_state) * LUT is needed but CSC is not we need to load an * identity matrix. */ - drm_WARN_ON(&dev_priv->drm, !IS_GEMINILAKE(dev_priv)); + drm_WARN_ON(&i915->drm, !IS_GEMINILAKE(i915)); ilk_update_pipe_csc(crtc, ilk_csc_off_zero, ilk_csc_coeff_identity, @@ -373,7 +373,7 @@ static void icl_load_csc_matrix(const struct intel_crtc_state *crtc_state) static void chv_load_cgm_csc(struct intel_crtc *crtc, const struct drm_property_blob *blob) { - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); const struct drm_color_ctm *ctm = blob->data; enum pipe pipe = crtc->pipe; u16 coeffs[9]; @@ -397,15 +397,15 @@ static void chv_load_cgm_csc(struct intel_crtc *crtc, coeffs[i] |= (abs_coeff >> 20) & 0xfff; } - intel_de_write_fw(dev_priv, CGM_PIPE_CSC_COEFF01(pipe), + intel_de_write_fw(i915, CGM_PIPE_CSC_COEFF01(pipe), coeffs[1] << 16 | coeffs[0]); - intel_de_write_fw(dev_priv, CGM_PIPE_CSC_COEFF23(pipe), + intel_de_write_fw(i915, CGM_PIPE_CSC_COEFF23(pipe), coeffs[3] << 16 | coeffs[2]); - intel_de_write_fw(dev_priv, CGM_PIPE_CSC_COEFF45(pipe), + intel_de_write_fw(i915, CGM_PIPE_CSC_COEFF45(pipe), coeffs[5] << 16 | coeffs[4]); - intel_de_write_fw(dev_priv, CGM_PIPE_CSC_COEFF67(pipe), + intel_de_write_fw(i915, CGM_PIPE_CSC_COEFF67(pipe), coeffs[7] << 16 | coeffs[6]); - intel_de_write_fw(dev_priv, CGM_PIPE_CSC_COEFF8(pipe), + intel_de_write_fw(i915, CGM_PIPE_CSC_COEFF8(pipe), coeffs[8]); } @@ -511,31 +511,31 @@ static void i9xx_color_commit_arm(const struct intel_crtc_state *crtc_state) static void ilk_color_commit_arm(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); /* update PIPECONF GAMMA_MODE */ ilk_set_pipeconf(crtc_state); - intel_de_write_fw(dev_priv, PIPE_CSC_MODE(crtc->pipe), + intel_de_write_fw(i915, PIPE_CSC_MODE(crtc->pipe), crtc_state->csc_mode); } static void hsw_color_commit_arm(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); - intel_de_write(dev_priv, GAMMA_MODE(crtc->pipe), + intel_de_write(i915, GAMMA_MODE(crtc->pipe), crtc_state->gamma_mode); - intel_de_write_fw(dev_priv, PIPE_CSC_MODE(crtc->pipe), + intel_de_write_fw(i915, PIPE_CSC_MODE(crtc->pipe), crtc_state->csc_mode); } static void skl_color_commit_arm(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); enum pipe pipe = crtc->pipe; u32 val = 0; @@ -548,12 +548,12 @@ static void skl_color_commit_arm(const struct intel_crtc_state *crtc_state) val |= SKL_BOTTOM_COLOR_GAMMA_ENABLE; if (crtc_state->csc_enable) val |= SKL_BOTTOM_COLOR_CSC_ENABLE; - intel_de_write(dev_priv, SKL_BOTTOM_COLOR(pipe), val); + intel_de_write(i915, SKL_BOTTOM_COLOR(pipe), val); - intel_de_write(dev_priv, GAMMA_MODE(crtc->pipe), + intel_de_write(i915, GAMMA_MODE(crtc->pipe), crtc_state->gamma_mode); - intel_de_write_fw(dev_priv, PIPE_CSC_MODE(crtc->pipe), + intel_de_write_fw(i915, PIPE_CSC_MODE(crtc->pipe), crtc_state->csc_mode); } @@ -643,7 +643,7 @@ static void i965_load_luts(const struct intel_crtc_state *crtc_state) static void ilk_load_lut_8(struct intel_crtc *crtc, const struct drm_property_blob *blob) { - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); const struct drm_color_lut *lut; enum pipe pipe = crtc->pipe; int i; @@ -654,20 +654,20 @@ static void ilk_load_lut_8(struct intel_crtc *crtc, lut = blob->data; for (i = 0; i < 256; i++) - intel_de_write_fw(dev_priv, LGC_PALETTE(pipe, i), + intel_de_write_fw(i915, LGC_PALETTE(pipe, i), i9xx_lut_8(&lut[i])); } static void ilk_load_lut_10(struct intel_crtc *crtc, const struct drm_property_blob *blob) { - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); const struct drm_color_lut *lut = blob->data; int i, lut_size = drm_color_lut_size(blob); enum pipe pipe = crtc->pipe; for (i = 0; i < lut_size; i++) - intel_de_write_fw(dev_priv, PREC_PALETTE(pipe, i), + intel_de_write_fw(i915, PREC_PALETTE(pipe, i), ilk_lut_10(&lut[i])); } @@ -708,7 +708,7 @@ static void ivb_load_lut_10(struct intel_crtc *crtc, const struct drm_property_blob *blob, u32 prec_index) { - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); int hw_lut_size = ivb_lut_10_size(prec_index); const struct drm_color_lut *lut = blob->data; int i, lut_size = drm_color_lut_size(blob); @@ -719,8 +719,8 @@ static void ivb_load_lut_10(struct intel_crtc *crtc, const struct drm_color_lut *entry = &lut[i * (lut_size - 1) / (hw_lut_size - 1)]; - intel_de_write_fw(dev_priv, PREC_PAL_INDEX(pipe), prec_index++); - intel_de_write_fw(dev_priv, PREC_PAL_DATA(pipe), + intel_de_write_fw(i915, PREC_PAL_INDEX(pipe), prec_index++); + intel_de_write_fw(i915, PREC_PAL_DATA(pipe), ilk_lut_10(entry)); } @@ -728,7 +728,7 @@ static void ivb_load_lut_10(struct intel_crtc *crtc, * Reset the index, otherwise it prevents the legacy palette to be * written properly. */ - intel_de_write_fw(dev_priv, PREC_PAL_INDEX(pipe), 0); + intel_de_write_fw(i915, PREC_PAL_INDEX(pipe), 0); } /* On BDW+ the index auto increment mode actually works */ @@ -736,13 +736,13 @@ static void bdw_load_lut_10(struct intel_crtc *crtc, const struct drm_property_blob *blob, u32 prec_index) { - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); int hw_lut_size = ivb_lut_10_size(prec_index); const struct drm_color_lut *lut = blob->data; int i, lut_size = drm_color_lut_size(blob); enum pipe pipe = crtc->pipe; - intel_de_write_fw(dev_priv, PREC_PAL_INDEX(pipe), + intel_de_write_fw(i915, PREC_PAL_INDEX(pipe), prec_index | PAL_PREC_AUTO_INCREMENT); for (i = 0; i < hw_lut_size; i++) { @@ -750,7 +750,7 @@ static void bdw_load_lut_10(struct intel_crtc *crtc, const struct drm_color_lut *entry = &lut[i * (lut_size - 1) / (hw_lut_size - 1)]; - intel_de_write_fw(dev_priv, PREC_PAL_DATA(pipe), + intel_de_write_fw(i915, PREC_PAL_DATA(pipe), ilk_lut_10(entry)); } @@ -758,13 +758,13 @@ static void bdw_load_lut_10(struct intel_crtc *crtc, * Reset the index, otherwise it prevents the legacy palette to be * written properly. */ - intel_de_write_fw(dev_priv, PREC_PAL_INDEX(pipe), 0); + intel_de_write_fw(i915, PREC_PAL_INDEX(pipe), 0); } static void ivb_load_lut_ext_max(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); enum pipe pipe = crtc->pipe; /* Program the max register to clamp values > 1.0. */ @@ -777,7 +777,7 @@ static void ivb_load_lut_ext_max(const struct intel_crtc_state *crtc_state) * ToDo: Extend the ABI to be able to program values * from 3.0 to 7.0 */ - if (DISPLAY_VER(dev_priv) >= 10) { + if (DISPLAY_VER(i915) >= 10) { intel_dsb_reg_write(crtc_state, PREC_PAL_EXT2_GC_MAX(pipe, 0), 1 << 16); intel_dsb_reg_write(crtc_state, PREC_PAL_EXT2_GC_MAX(pipe, 1), @@ -858,7 +858,7 @@ static void glk_load_degamma_lut(const struct intel_crtc_state *crtc_state, const struct drm_property_blob *blob) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); const struct drm_color_lut *lut = blob->data; int i, lut_size = drm_color_lut_size(blob); enum pipe pipe = crtc->pipe; @@ -868,8 +868,8 @@ static void glk_load_degamma_lut(const struct intel_crtc_state *crtc_state, * ignore the index bits, so we need to reset it to index 0 * separately. */ - intel_de_write_fw(dev_priv, PRE_CSC_GAMC_INDEX(pipe), 0); - intel_de_write_fw(dev_priv, PRE_CSC_GAMC_INDEX(pipe), + intel_de_write_fw(i915, PRE_CSC_GAMC_INDEX(pipe), 0); + intel_de_write_fw(i915, PRE_CSC_GAMC_INDEX(pipe), PRE_CSC_GAMC_AUTO_INCREMENT); for (i = 0; i < lut_size; i++) { @@ -886,15 +886,15 @@ static void glk_load_degamma_lut(const struct intel_crtc_state *crtc_state, * ToDo: Extend to max 7.0. Enable 32 bit input value * as compared to just 16 to achieve this. */ - intel_de_write_fw(dev_priv, PRE_CSC_GAMC_DATA(pipe), + intel_de_write_fw(i915, PRE_CSC_GAMC_DATA(pipe), lut[i].green); } /* Clamp values > 1.0. */ - while (i++ < glk_degamma_lut_size(dev_priv)) - intel_de_write_fw(dev_priv, PRE_CSC_GAMC_DATA(pipe), 1 << 16); + while (i++ < glk_degamma_lut_size(i915)) + intel_de_write_fw(i915, PRE_CSC_GAMC_DATA(pipe), 1 << 16); - intel_de_write_fw(dev_priv, PRE_CSC_GAMC_INDEX(pipe), 0); + intel_de_write_fw(i915, PRE_CSC_GAMC_INDEX(pipe), 0); } static void glk_load_luts(const struct intel_crtc_state *crtc_state) @@ -1075,15 +1075,15 @@ static u32 chv_cgm_degamma_udw(const struct drm_color_lut *color) static void chv_load_cgm_degamma(struct intel_crtc *crtc, const struct drm_property_blob *blob) { - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); const struct drm_color_lut *lut = blob->data; int i, lut_size = drm_color_lut_size(blob); enum pipe pipe = crtc->pipe; for (i = 0; i < lut_size; i++) { - intel_de_write_fw(dev_priv, CGM_PIPE_DEGAMMA(pipe, i, 0), + intel_de_write_fw(i915, CGM_PIPE_DEGAMMA(pipe, i, 0), chv_cgm_degamma_ldw(&lut[i])); - intel_de_write_fw(dev_priv, CGM_PIPE_DEGAMMA(pipe, i, 1), + intel_de_write_fw(i915, CGM_PIPE_DEGAMMA(pipe, i, 1), chv_cgm_degamma_udw(&lut[i])); } } @@ -1109,15 +1109,15 @@ static void chv_cgm_gamma_pack(struct drm_color_lut *entry, u32 ldw, u32 udw) static void chv_load_cgm_gamma(struct intel_crtc *crtc, const struct drm_property_blob *blob) { - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); const struct drm_color_lut *lut = blob->data; int i, lut_size = drm_color_lut_size(blob); enum pipe pipe = crtc->pipe; for (i = 0; i < lut_size; i++) { - intel_de_write_fw(dev_priv, CGM_PIPE_GAMMA(pipe, i, 0), + intel_de_write_fw(i915, CGM_PIPE_GAMMA(pipe, i, 0), chv_cgm_gamma_ldw(&lut[i])); - intel_de_write_fw(dev_priv, CGM_PIPE_GAMMA(pipe, i, 1), + intel_de_write_fw(i915, CGM_PIPE_GAMMA(pipe, i, 1), chv_cgm_gamma_udw(&lut[i])); } } @@ -1125,7 +1125,7 @@ static void chv_load_cgm_gamma(struct intel_crtc *crtc, static void chv_load_luts(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); const struct drm_property_blob *pre_csc_lut = crtc_state->pre_csc_lut; const struct drm_property_blob *post_csc_lut = crtc_state->post_csc_lut; const struct drm_property_blob *ctm = crtc_state->hw.ctm; @@ -1141,30 +1141,30 @@ static void chv_load_luts(const struct intel_crtc_state *crtc_state) else i965_load_luts(crtc_state); - intel_de_write_fw(dev_priv, CGM_PIPE_MODE(crtc->pipe), + intel_de_write_fw(i915, CGM_PIPE_MODE(crtc->pipe), crtc_state->cgm_mode); } void intel_color_load_luts(const struct intel_crtc_state *crtc_state) { - struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); - dev_priv->display.funcs.color->load_luts(crtc_state); + i915->display.funcs.color->load_luts(crtc_state); } void intel_color_commit_noarm(const struct intel_crtc_state *crtc_state) { - struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); - if (dev_priv->display.funcs.color->color_commit_noarm) - dev_priv->display.funcs.color->color_commit_noarm(crtc_state); + if (i915->display.funcs.color->color_commit_noarm) + i915->display.funcs.color->color_commit_noarm(crtc_state); } void intel_color_commit_arm(const struct intel_crtc_state *crtc_state) { - struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); - dev_priv->display.funcs.color->color_commit_arm(crtc_state); + i915->display.funcs.color->color_commit_arm(crtc_state); } static bool intel_can_preload_luts(const struct intel_crtc_state *new_crtc_state) @@ -1200,23 +1200,23 @@ static bool chv_can_preload_luts(const struct intel_crtc_state *new_crtc_state) int intel_color_check(struct intel_crtc_state *crtc_state) { - struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); - return dev_priv->display.funcs.color->color_check(crtc_state); + return i915->display.funcs.color->color_check(crtc_state); } void intel_color_get_config(struct intel_crtc_state *crtc_state) { - struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); - if (dev_priv->display.funcs.color->read_luts) - dev_priv->display.funcs.color->read_luts(crtc_state); + if (i915->display.funcs.color->read_luts) + i915->display.funcs.color->read_luts(crtc_state); } static bool need_plane_update(struct intel_plane *plane, const struct intel_crtc_state *crtc_state) { - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + struct drm_i915_private *i915 = to_i915(plane->base.dev); /* * On pre-SKL the pipe gamma enable and pipe csc enable for @@ -1224,7 +1224,7 @@ static bool need_plane_update(struct intel_plane *plane, * We have to reconfigure that even if the plane is inactive. */ return crtc_state->active_planes & BIT(plane->id) || - (DISPLAY_VER(dev_priv) < 9 && + (DISPLAY_VER(i915) < 9 && plane->id == PLANE_PRIMARY); } @@ -1232,7 +1232,7 @@ static int intel_color_add_affected_planes(struct intel_crtc_state *new_crtc_state) { struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); struct intel_atomic_state *state = to_intel_atomic_state(new_crtc_state->uapi.state); const struct intel_crtc_state *old_crtc_state = @@ -1247,7 +1247,7 @@ intel_color_add_affected_planes(struct intel_crtc_state *new_crtc_state) new_crtc_state->csc_enable == old_crtc_state->csc_enable) return 0; - for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, plane) { + for_each_intel_plane_on_crtc(&i915->drm, crtc, plane) { struct intel_plane_state *plane_state; if (!need_plane_update(plane, new_crtc_state)) @@ -1260,7 +1260,7 @@ intel_color_add_affected_planes(struct intel_crtc_state *new_crtc_state) new_crtc_state->update_planes |= BIT(plane->id); /* plane control register changes blocked by CxSR */ - if (HAS_GMCH(dev_priv)) + if (HAS_GMCH(i915)) new_crtc_state->disable_cxsr = true; } @@ -1286,7 +1286,7 @@ static int check_lut_size(const struct drm_property_blob *lut, int expected) static int check_luts(const struct intel_crtc_state *crtc_state) { - struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut; const struct drm_property_blob *degamma_lut = crtc_state->hw.degamma_lut; int gamma_length, degamma_length; @@ -1298,15 +1298,15 @@ static int check_luts(const struct intel_crtc_state *crtc_state) /* C8 relies on its palette being stored in the legacy LUT */ if (crtc_state->c8_planes) { - drm_dbg_kms(&dev_priv->drm, + drm_dbg_kms(&i915->drm, "C8 pixelformat requires the legacy LUT\n"); return -EINVAL; } - degamma_length = INTEL_INFO(dev_priv)->display.color.degamma_lut_size; - gamma_length = INTEL_INFO(dev_priv)->display.color.gamma_lut_size; - degamma_tests = INTEL_INFO(dev_priv)->display.color.degamma_lut_tests; - gamma_tests = INTEL_INFO(dev_priv)->display.color.gamma_lut_tests; + degamma_length = INTEL_INFO(i915)->display.color.degamma_lut_size; + gamma_length = INTEL_INFO(i915)->display.color.gamma_lut_size; + degamma_tests = INTEL_INFO(i915)->display.color.degamma_lut_tests; + gamma_tests = INTEL_INFO(i915)->display.color.gamma_lut_tests; if (check_lut_size(degamma_lut, degamma_length) || check_lut_size(gamma_lut, gamma_length)) @@ -1550,7 +1550,7 @@ static u32 ivb_csc_mode(const struct intel_crtc_state *crtc_state) static int ivb_color_check(struct intel_crtc_state *crtc_state) { - struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); bool limited_color_range = ilk_csc_limited_range(crtc_state); int ret; @@ -1560,7 +1560,7 @@ static int ivb_color_check(struct intel_crtc_state *crtc_state) if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB && crtc_state->hw.ctm) { - drm_dbg_kms(&dev_priv->drm, + drm_dbg_kms(&i915->drm, "YCBCR and CTM together are not possible\n"); return -EINVAL; } @@ -1617,7 +1617,7 @@ static void glk_assign_luts(struct intel_crtc_state *crtc_state) static int glk_color_check(struct intel_crtc_state *crtc_state) { - struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); int ret; ret = check_luts(crtc_state); @@ -1626,7 +1626,7 @@ static int glk_color_check(struct intel_crtc_state *crtc_state) if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB && crtc_state->hw.ctm) { - drm_dbg_kms(&dev_priv->drm, + drm_dbg_kms(&i915->drm, "YCBCR and CTM together are not possible\n"); return -EINVAL; } @@ -1798,19 +1798,19 @@ static int icl_gamma_precision(const struct intel_crtc_state *crtc_state) int intel_color_get_gamma_bit_precision(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); - if (HAS_GMCH(dev_priv)) { - if (IS_CHERRYVIEW(dev_priv)) + if (HAS_GMCH(i915)) { + if (IS_CHERRYVIEW(i915)) return chv_gamma_precision(crtc_state); else return i9xx_gamma_precision(crtc_state); } else { - if (DISPLAY_VER(dev_priv) >= 11) + if (DISPLAY_VER(i915) >= 11) return icl_gamma_precision(crtc_state); - else if (DISPLAY_VER(dev_priv) == 10) + else if (DISPLAY_VER(i915) == 10) return glk_gamma_precision(crtc_state); - else if (IS_IRONLAKE(dev_priv)) + else if (IS_IRONLAKE(i915)) return ilk_gamma_precision(crtc_state); } @@ -1966,13 +1966,13 @@ static void i965_read_luts(struct intel_crtc_state *crtc_state) static struct drm_property_blob *chv_read_cgm_gamma(struct intel_crtc *crtc) { - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - int i, lut_size = INTEL_INFO(dev_priv)->display.color.gamma_lut_size; + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + int i, lut_size = INTEL_INFO(i915)->display.color.gamma_lut_size; enum pipe pipe = crtc->pipe; struct drm_property_blob *blob; struct drm_color_lut *lut; - blob = drm_property_create_blob(&dev_priv->drm, + blob = drm_property_create_blob(&i915->drm, sizeof(lut[0]) * lut_size, NULL); if (IS_ERR(blob)) @@ -1981,8 +1981,8 @@ static struct drm_property_blob *chv_read_cgm_gamma(struct intel_crtc *crtc) lut = blob->data; for (i = 0; i < lut_size; i++) { - u32 ldw = intel_de_read_fw(dev_priv, CGM_PIPE_GAMMA(pipe, i, 0)); - u32 udw = intel_de_read_fw(dev_priv, CGM_PIPE_GAMMA(pipe, i, 1)); + u32 ldw = intel_de_read_fw(i915, CGM_PIPE_GAMMA(pipe, i, 0)); + u32 udw = intel_de_read_fw(i915, CGM_PIPE_GAMMA(pipe, i, 1)); chv_cgm_gamma_pack(&lut[i], ldw, udw); } @@ -2002,13 +2002,13 @@ static void chv_read_luts(struct intel_crtc_state *crtc_state) static struct drm_property_blob *ilk_read_lut_8(struct intel_crtc *crtc) { - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); enum pipe pipe = crtc->pipe; struct drm_property_blob *blob; struct drm_color_lut *lut; int i; - blob = drm_property_create_blob(&dev_priv->drm, + blob = drm_property_create_blob(&i915->drm, sizeof(lut[0]) * LEGACY_LUT_LENGTH, NULL); if (IS_ERR(blob)) @@ -2017,7 +2017,7 @@ static struct drm_property_blob *ilk_read_lut_8(struct intel_crtc *crtc) lut = blob->data; for (i = 0; i < LEGACY_LUT_LENGTH; i++) { - u32 val = intel_de_read_fw(dev_priv, LGC_PALETTE(pipe, i)); + u32 val = intel_de_read_fw(i915, LGC_PALETTE(pipe, i)); i9xx_lut_8_pack(&lut[i], val); } @@ -2027,13 +2027,13 @@ static struct drm_property_blob *ilk_read_lut_8(struct intel_crtc *crtc) static struct drm_property_blob *ilk_read_lut_10(struct intel_crtc *crtc) { - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - int i, lut_size = INTEL_INFO(dev_priv)->display.color.gamma_lut_size; + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + int i, lut_size = INTEL_INFO(i915)->display.color.gamma_lut_size; enum pipe pipe = crtc->pipe; struct drm_property_blob *blob; struct drm_color_lut *lut; - blob = drm_property_create_blob(&dev_priv->drm, + blob = drm_property_create_blob(&i915->drm, sizeof(lut[0]) * lut_size, NULL); if (IS_ERR(blob)) @@ -2042,7 +2042,7 @@ static struct drm_property_blob *ilk_read_lut_10(struct intel_crtc *crtc) lut = blob->data; for (i = 0; i < lut_size; i++) { - u32 val = intel_de_read_fw(dev_priv, PREC_PALETTE(pipe, i)); + u32 val = intel_de_read_fw(i915, PREC_PALETTE(pipe, i)); ilk_lut_10_pack(&lut[i], val); } @@ -2077,16 +2077,16 @@ static void ilk_read_luts(struct intel_crtc_state *crtc_state) static struct drm_property_blob *bdw_read_lut_10(struct intel_crtc *crtc, u32 prec_index) { - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); int i, hw_lut_size = ivb_lut_10_size(prec_index); - int lut_size = INTEL_INFO(dev_priv)->display.color.gamma_lut_size; + int lut_size = INTEL_INFO(i915)->display.color.gamma_lut_size; enum pipe pipe = crtc->pipe; struct drm_property_blob *blob; struct drm_color_lut *lut; - drm_WARN_ON(&dev_priv->drm, lut_size != hw_lut_size); + drm_WARN_ON(&i915->drm, lut_size != hw_lut_size); - blob = drm_property_create_blob(&dev_priv->drm, + blob = drm_property_create_blob(&i915->drm, sizeof(lut[0]) * lut_size, NULL); if (IS_ERR(blob)) @@ -2094,16 +2094,16 @@ static struct drm_property_blob *bdw_read_lut_10(struct intel_crtc *crtc, lut = blob->data; - intel_de_write_fw(dev_priv, PREC_PAL_INDEX(pipe), + intel_de_write_fw(i915, PREC_PAL_INDEX(pipe), prec_index | PAL_PREC_AUTO_INCREMENT); for (i = 0; i < lut_size; i++) { - u32 val = intel_de_read_fw(dev_priv, PREC_PAL_DATA(pipe)); + u32 val = intel_de_read_fw(i915, PREC_PAL_DATA(pipe)); ilk_lut_10_pack(&lut[i], val); } - intel_de_write_fw(dev_priv, PREC_PAL_INDEX(pipe), 0); + intel_de_write_fw(i915, PREC_PAL_INDEX(pipe), 0); return blob; } @@ -2131,13 +2131,13 @@ static void glk_read_luts(struct intel_crtc_state *crtc_state) static struct drm_property_blob * icl_read_lut_multi_segment(struct intel_crtc *crtc) { - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - int i, lut_size = INTEL_INFO(dev_priv)->display.color.gamma_lut_size; + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + int i, lut_size = INTEL_INFO(i915)->display.color.gamma_lut_size; enum pipe pipe = crtc->pipe; struct drm_property_blob *blob; struct drm_color_lut *lut; - blob = drm_property_create_blob(&dev_priv->drm, + blob = drm_property_create_blob(&i915->drm, sizeof(lut[0]) * lut_size, NULL); if (IS_ERR(blob)) @@ -2145,17 +2145,17 @@ icl_read_lut_multi_segment(struct intel_crtc *crtc) lut = blob->data; - intel_de_write_fw(dev_priv, PREC_PAL_MULTI_SEG_INDEX(pipe), + intel_de_write_fw(i915, PREC_PAL_MULTI_SEG_INDEX(pipe), PAL_PREC_AUTO_INCREMENT); for (i = 0; i < 9; i++) { - u32 ldw = intel_de_read_fw(dev_priv, PREC_PAL_MULTI_SEG_DATA(pipe)); - u32 udw = intel_de_read_fw(dev_priv, PREC_PAL_MULTI_SEG_DATA(pipe)); + u32 ldw = intel_de_read_fw(i915, PREC_PAL_MULTI_SEG_DATA(pipe)); + u32 udw = intel_de_read_fw(i915, PREC_PAL_MULTI_SEG_DATA(pipe)); icl_lut_multi_seg_pack(&lut[i], ldw, udw); } - intel_de_write_fw(dev_priv, PREC_PAL_MULTI_SEG_INDEX(pipe), 0); + intel_de_write_fw(i915, PREC_PAL_MULTI_SEG_INDEX(pipe), 0); /* * FIXME readouts from PAL_PREC_DATA register aren't giving @@ -2268,15 +2268,15 @@ static const struct intel_color_funcs ilk_color_funcs = { void intel_color_crtc_init(struct intel_crtc *crtc) { - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - bool has_ctm = INTEL_INFO(dev_priv)->display.color.degamma_lut_size != 0; + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + bool has_ctm = INTEL_INFO(i915)->display.color.degamma_lut_size != 0; drm_mode_crtc_set_gamma_size(&crtc->base, 256); drm_crtc_enable_color_mgmt(&crtc->base, - INTEL_INFO(dev_priv)->display.color.degamma_lut_size, + INTEL_INFO(i915)->display.color.degamma_lut_size, has_ctm, - INTEL_INFO(dev_priv)->display.color.gamma_lut_size); + INTEL_INFO(i915)->display.color.gamma_lut_size); } int intel_color_init(struct drm_i915_private *i915) -- cgit From fdaa243adf43d1d305d58f70cbc19e54c966c8e8 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 26 Oct 2022 14:38:59 +0300 Subject: drm/i915: s/icl_load_gcmax/ivb_load_lut_max/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unify icl_load_gcmax() with the rest of the function naming scheme by calling it ivb_load_lut_max() instead. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221026113906.10551-5-ville.syrjala@linux.intel.com Reviewed-by: Ankit Nautiyal --- drivers/gpu/drm/i915/display/intel_color.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index 415e0a6839a4..e73e6ea6f82f 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -935,8 +935,8 @@ static u32 ilk_lut_12p4_ldw(const struct drm_color_lut *color) } static void -icl_load_gcmax(const struct intel_crtc_state *crtc_state, - const struct drm_color_lut *color) +ivb_load_lut_max(const struct intel_crtc_state *crtc_state, + const struct drm_color_lut *color) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); enum pipe pipe = crtc->pipe; @@ -1028,7 +1028,7 @@ icl_program_gamma_multi_segment(const struct intel_crtc_state *crtc_state) /* The last entry in the LUT is to be programmed in GCMAX */ entry = &lut[256 * 8 * 128]; - icl_load_gcmax(crtc_state, entry); + ivb_load_lut_max(crtc_state, entry); ivb_load_lut_ext_max(crtc_state); } -- cgit From 8f079f08833d36d8b756a08f613bccba10e23784 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 26 Oct 2022 14:39:00 +0300 Subject: drm/i915: Split ivb_load_lut_ext_max() into two parts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split the EXT2_MAX register programming into its own function. More in line with the whole "cobble together stuff from small pieces" approach used in this code. The EXT(2)_MAX registers are also not really part of the multi-segment section of the LUT, so hoist the calls to a higher level, just like we do in other gamma modes as well. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221026113906.10551-6-ville.syrjala@linux.intel.com Reviewed-by: Ankit Nautiyal --- drivers/gpu/drm/i915/display/intel_color.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index e73e6ea6f82f..3b78b882e0c0 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -764,27 +764,23 @@ static void bdw_load_lut_10(struct intel_crtc *crtc, static void ivb_load_lut_ext_max(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - struct drm_i915_private *i915 = to_i915(crtc->base.dev); enum pipe pipe = crtc->pipe; /* Program the max register to clamp values > 1.0. */ intel_dsb_reg_write(crtc_state, PREC_PAL_EXT_GC_MAX(pipe, 0), 1 << 16); intel_dsb_reg_write(crtc_state, PREC_PAL_EXT_GC_MAX(pipe, 1), 1 << 16); intel_dsb_reg_write(crtc_state, PREC_PAL_EXT_GC_MAX(pipe, 2), 1 << 16); +} - /* - * Program the gc max 2 register to clamp values > 1.0. - * ToDo: Extend the ABI to be able to program values - * from 3.0 to 7.0 - */ - if (DISPLAY_VER(i915) >= 10) { - intel_dsb_reg_write(crtc_state, PREC_PAL_EXT2_GC_MAX(pipe, 0), - 1 << 16); - intel_dsb_reg_write(crtc_state, PREC_PAL_EXT2_GC_MAX(pipe, 1), - 1 << 16); - intel_dsb_reg_write(crtc_state, PREC_PAL_EXT2_GC_MAX(pipe, 2), - 1 << 16); - } +static void glk_load_lut_ext2_max(const struct intel_crtc_state *crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + enum pipe pipe = crtc->pipe; + + /* Program the max register to clamp values > 1.0. */ + intel_dsb_reg_write(crtc_state, PREC_PAL_EXT2_GC_MAX(pipe, 0), 1 << 16); + intel_dsb_reg_write(crtc_state, PREC_PAL_EXT2_GC_MAX(pipe, 1), 1 << 16); + intel_dsb_reg_write(crtc_state, PREC_PAL_EXT2_GC_MAX(pipe, 2), 1 << 16); } static void ivb_load_luts(const struct intel_crtc_state *crtc_state) @@ -913,6 +909,7 @@ static void glk_load_luts(const struct intel_crtc_state *crtc_state) case GAMMA_MODE_MODE_10BIT: bdw_load_lut_10(crtc, post_csc_lut, PAL_PREC_INDEX_VALUE(0)); ivb_load_lut_ext_max(crtc_state); + glk_load_lut_ext2_max(crtc_state); break; default: MISSING_CASE(crtc_state->gamma_mode); @@ -1029,7 +1026,6 @@ icl_program_gamma_multi_segment(const struct intel_crtc_state *crtc_state) /* The last entry in the LUT is to be programmed in GCMAX */ entry = &lut[256 * 8 * 128]; ivb_load_lut_max(crtc_state, entry); - ivb_load_lut_ext_max(crtc_state); } static void icl_load_luts(const struct intel_crtc_state *crtc_state) @@ -1048,10 +1044,13 @@ static void icl_load_luts(const struct intel_crtc_state *crtc_state) case GAMMA_MODE_MODE_12BIT_MULTI_SEGMENTED: icl_program_gamma_superfine_segment(crtc_state); icl_program_gamma_multi_segment(crtc_state); + ivb_load_lut_ext_max(crtc_state); + glk_load_lut_ext2_max(crtc_state); break; case GAMMA_MODE_MODE_10BIT: bdw_load_lut_10(crtc, post_csc_lut, PAL_PREC_INDEX_VALUE(0)); ivb_load_lut_ext_max(crtc_state); + glk_load_lut_ext2_max(crtc_state); break; default: MISSING_CASE(crtc_state->gamma_mode); -- cgit From 28c9fa7770ea9c818b5a9fdf64e242fd9e4fdc2e Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 26 Oct 2022 14:39:01 +0300 Subject: drm/i915: Deconfuse the ilk+ 12.4 LUT entry functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit s/icl_lut_multi_seg_pack/ilk_lut_12p4_pack/ since that's what it is and group the corresponding "unpack" functions next to it. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221026113906.10551-7-ville.syrjala@linux.intel.com Reviewed-by: Ankit Nautiyal --- drivers/gpu/drm/i915/display/intel_color.c | 38 +++++++++++++++--------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index 3b78b882e0c0..e881c95ee451 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -482,14 +482,28 @@ static void ilk_lut_10_pack(struct drm_color_lut *entry, u32 val) entry->blue = intel_color_lut_pack(REG_FIELD_GET(PREC_PALETTE_BLUE_MASK, val), 10); } -static void icl_lut_multi_seg_pack(struct drm_color_lut *entry, u32 ldw, u32 udw) +/* ilk+ "12.4" interpolated format (high 10 bits) */ +static u32 ilk_lut_12p4_udw(const struct drm_color_lut *color) +{ + return (color->red >> 6) << 20 | (color->green >> 6) << 10 | + (color->blue >> 6); +} + +/* ilk+ "12.4" interpolated format (low 6 bits) */ +static u32 ilk_lut_12p4_ldw(const struct drm_color_lut *color) +{ + return (color->red & 0x3f) << 24 | (color->green & 0x3f) << 14 | + (color->blue & 0x3f) << 4; +} + +static void ilk_lut_12p4_pack(struct drm_color_lut *entry, u32 ldw, u32 udw) { entry->red = REG_FIELD_GET(PAL_PREC_MULTI_SEG_RED_UDW_MASK, udw) << 6 | - REG_FIELD_GET(PAL_PREC_MULTI_SEG_RED_LDW_MASK, ldw); + REG_FIELD_GET(PAL_PREC_MULTI_SEG_RED_LDW_MASK, ldw); entry->green = REG_FIELD_GET(PAL_PREC_MULTI_SEG_GREEN_UDW_MASK, udw) << 6 | - REG_FIELD_GET(PAL_PREC_MULTI_SEG_GREEN_LDW_MASK, ldw); + REG_FIELD_GET(PAL_PREC_MULTI_SEG_GREEN_LDW_MASK, ldw); entry->blue = REG_FIELD_GET(PAL_PREC_MULTI_SEG_BLUE_UDW_MASK, udw) << 6 | - REG_FIELD_GET(PAL_PREC_MULTI_SEG_BLUE_LDW_MASK, ldw); + REG_FIELD_GET(PAL_PREC_MULTI_SEG_BLUE_LDW_MASK, ldw); } static void icl_color_commit_noarm(const struct intel_crtc_state *crtc_state) @@ -917,20 +931,6 @@ static void glk_load_luts(const struct intel_crtc_state *crtc_state) } } -/* ilk+ "12.4" interpolated format (high 10 bits) */ -static u32 ilk_lut_12p4_udw(const struct drm_color_lut *color) -{ - return (color->red >> 6) << 20 | (color->green >> 6) << 10 | - (color->blue >> 6); -} - -/* ilk+ "12.4" interpolated format (low 6 bits) */ -static u32 ilk_lut_12p4_ldw(const struct drm_color_lut *color) -{ - return (color->red & 0x3f) << 24 | (color->green & 0x3f) << 14 | - (color->blue & 0x3f) << 4; -} - static void ivb_load_lut_max(const struct intel_crtc_state *crtc_state, const struct drm_color_lut *color) @@ -2151,7 +2151,7 @@ icl_read_lut_multi_segment(struct intel_crtc *crtc) u32 ldw = intel_de_read_fw(i915, PREC_PAL_MULTI_SEG_DATA(pipe)); u32 udw = intel_de_read_fw(i915, PREC_PAL_MULTI_SEG_DATA(pipe)); - icl_lut_multi_seg_pack(&lut[i], ldw, udw); + ilk_lut_12p4_pack(&lut[i], ldw, udw); } intel_de_write_fw(i915, PREC_PAL_MULTI_SEG_INDEX(pipe), 0); -- cgit From ad105b715e0092b0c4c8534d07d70692adca8516 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 26 Oct 2022 14:39:02 +0300 Subject: drm/i915: Pass limited_range explicitly to ilk_csc_convert_ctm() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since pre-icl vs. icl+ handle the limited range output stuff a bit differently it's probably less confusing if we just pass that information explicitly into ilk_csc_convert_ctm(). Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221026113906.10551-8-ville.syrjala@linux.intel.com Reviewed-by: Ankit Nautiyal --- drivers/gpu/drm/i915/display/intel_color.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index e881c95ee451..946fb767f3e0 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -259,14 +259,14 @@ static bool ilk_csc_limited_range(const struct intel_crtc_state *crtc_state) } static void ilk_csc_convert_ctm(const struct intel_crtc_state *crtc_state, - u16 coeffs[9]) + u16 coeffs[9], bool limited_color_range) { const struct drm_color_ctm *ctm = crtc_state->hw.ctm->data; const u64 *input; u64 temp[9]; int i; - if (ilk_csc_limited_range(crtc_state)) + if (limited_color_range) input = ctm_mult_by_limited(temp, ctm->matrix); else input = ctm->matrix; @@ -319,7 +319,7 @@ static void ilk_load_csc_matrix(const struct intel_crtc_state *crtc_state) if (crtc_state->hw.ctm) { u16 coeff[9]; - ilk_csc_convert_ctm(crtc_state, coeff); + ilk_csc_convert_ctm(crtc_state, coeff, limited_color_range); ilk_update_pipe_csc(crtc, ilk_csc_off_zero, coeff, limited_color_range ? ilk_csc_postoff_limited_range : @@ -354,7 +354,7 @@ static void icl_load_csc_matrix(const struct intel_crtc_state *crtc_state) if (crtc_state->hw.ctm) { u16 coeff[9]; - ilk_csc_convert_ctm(crtc_state, coeff); + ilk_csc_convert_ctm(crtc_state, coeff, false); ilk_update_pipe_csc(crtc, ilk_csc_off_zero, coeff, ilk_csc_off_zero); } -- cgit From 6d5e733f3ac1ad68a6230f44069b14bea2a9bdb3 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 26 Oct 2022 14:39:03 +0300 Subject: drm/i915: Reuse ilk_gamma_mode() on ivb+ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apart from the split gamma mode ivb+ LUTs work just like ilk+ LUTs. So let's handle the special case, and then just fall back to ilk_gamma_mode() to avoid having to duplicate the same logic. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221026113906.10551-9-ville.syrjala@linux.intel.com Reviewed-by: Ankit Nautiyal --- drivers/gpu/drm/i915/display/intel_color.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index 946fb767f3e0..435394cad359 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -1521,14 +1521,10 @@ static int ilk_color_check(struct intel_crtc_state *crtc_state) static u32 ivb_gamma_mode(const struct intel_crtc_state *crtc_state) { - if (!crtc_state->gamma_enable || - crtc_state_is_legacy_gamma(crtc_state)) - return GAMMA_MODE_MODE_8BIT; - else if (crtc_state->hw.gamma_lut && - crtc_state->hw.degamma_lut) + if (crtc_state->hw.degamma_lut && crtc_state->hw.gamma_lut) return GAMMA_MODE_MODE_SPLIT; - else - return GAMMA_MODE_MODE_10BIT; + + return ilk_gamma_mode(crtc_state); } static u32 ivb_csc_mode(const struct intel_crtc_state *crtc_state) -- cgit From 4c0119dd0a7728456a2394c1bc0aa612e1f2c3cb Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 26 Oct 2022 14:39:04 +0300 Subject: drm/i915: Reject YCbCr output with degamma+gamma on pre-icl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the pipe CSC sits between the degamma and gamma LUTs there is no way to make us it for RGB->YCbCr conversion when both LUTs are also active. Simply reject such combos. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221026113906.10551-10-ville.syrjala@linux.intel.com Reviewed-by: Ankit Nautiyal --- drivers/gpu/drm/i915/display/intel_color.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index 435394cad359..926784f266f2 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -1556,7 +1556,14 @@ static int ivb_color_check(struct intel_crtc_state *crtc_state) if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB && crtc_state->hw.ctm) { drm_dbg_kms(&i915->drm, - "YCBCR and CTM together are not possible\n"); + "YCbCr and CTM together are not possible\n"); + return -EINVAL; + } + + if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB && + crtc_state->hw.degamma_lut && crtc_state->hw.gamma_lut) { + drm_dbg_kms(&i915->drm, + "YCbCr and degamma+gamma together are not possible\n"); return -EINVAL; } @@ -1622,7 +1629,14 @@ static int glk_color_check(struct intel_crtc_state *crtc_state) if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB && crtc_state->hw.ctm) { drm_dbg_kms(&i915->drm, - "YCBCR and CTM together are not possible\n"); + "YCbCr and CTM together are not possible\n"); + return -EINVAL; + } + + if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB && + crtc_state->hw.degamma_lut && crtc_state->hw.gamma_lut) { + drm_dbg_kms(&i915->drm, + "YCbCr and degamma+gamma together are not possible\n"); return -EINVAL; } -- cgit From 9034f9c4e284138d5e5646b89285d7a89b840f5e Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 26 Oct 2022 14:39:05 +0300 Subject: drm/i915: Share {csc,gamma}_enable calculation for ilk/snb vs. ivb+ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ilk/snb vs. ivb+ hardware is mostly identical except for the addition of the split gamma mode on ivb. Thus we can share the csc_enable and gamma_enable calculation for both variants. Pull that stuff into a few helpers. Note that this also fills in the missing ctm/degamma stuff into ilk_color_check() pretty much, so for good measure let's also add a few extra checks relating to that, although we still don't expose ctm/degamma to userspace. But now it'll be trivial to do so if we wish. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221026113906.10551-11-ville.syrjala@linux.intel.com Reviewed-by: Ankit Nautiyal --- drivers/gpu/drm/i915/display/intel_color.c | 49 +++++++++++++++++++----------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index 926784f266f2..33871bfacee7 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -1442,6 +1442,20 @@ static int chv_color_check(struct intel_crtc_state *crtc_state) return 0; } +static bool ilk_gamma_enable(const struct intel_crtc_state *crtc_state) +{ + return (crtc_state->hw.gamma_lut || + crtc_state->hw.degamma_lut) && + !crtc_state->c8_planes; +} + +static bool ilk_csc_enable(const struct intel_crtc_state *crtc_state) +{ + return crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB || + ilk_csc_limited_range(crtc_state) || + crtc_state->hw.ctm; +} + static u32 ilk_gamma_mode(const struct intel_crtc_state *crtc_state) { if (!crtc_state->gamma_enable || @@ -1487,22 +1501,29 @@ static void ilk_assign_luts(struct intel_crtc_state *crtc_state) static int ilk_color_check(struct intel_crtc_state *crtc_state) { + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); int ret; ret = check_luts(crtc_state); if (ret) return ret; - crtc_state->gamma_enable = - crtc_state->hw.gamma_lut && - !crtc_state->c8_planes; + if (crtc_state->hw.degamma_lut && crtc_state->hw.gamma_lut) { + drm_dbg_kms(&i915->drm, + "Degamma and gamma together are not possible\n"); + return -EINVAL; + } - /* - * We don't expose the ctm on ilk/snb currently, also RGB - * limited range output is handled by the hw automagically. - */ - crtc_state->csc_enable = - crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB; + if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB && + crtc_state->hw.ctm) { + drm_dbg_kms(&i915->drm, + "YCbCr and CTM together are not possible\n"); + return -EINVAL; + } + + crtc_state->gamma_enable = ilk_gamma_enable(crtc_state); + + crtc_state->csc_enable = ilk_csc_enable(crtc_state); crtc_state->gamma_mode = ilk_gamma_mode(crtc_state); @@ -1546,7 +1567,6 @@ static u32 ivb_csc_mode(const struct intel_crtc_state *crtc_state) static int ivb_color_check(struct intel_crtc_state *crtc_state) { struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); - bool limited_color_range = ilk_csc_limited_range(crtc_state); int ret; ret = check_luts(crtc_state); @@ -1567,14 +1587,9 @@ static int ivb_color_check(struct intel_crtc_state *crtc_state) return -EINVAL; } - crtc_state->gamma_enable = - (crtc_state->hw.gamma_lut || - crtc_state->hw.degamma_lut) && - !crtc_state->c8_planes; + crtc_state->gamma_enable = ilk_gamma_enable(crtc_state); - crtc_state->csc_enable = - crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB || - crtc_state->hw.ctm || limited_color_range; + crtc_state->csc_enable = ilk_csc_enable(crtc_state); crtc_state->gamma_mode = ivb_gamma_mode(crtc_state); -- cgit From 882ecff709b50b36128e07a6b0035f476c769f50 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 31 Oct 2022 23:40:36 +0200 Subject: drm/i915: Use intel_crtc_needs_modeset() more MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prefer our own intel_crtc_needs_modeset() wrapper to drm_atomic_crtc_needs_modeset() whenever we are dealing with the intel_ types instead of drm_ types. Makes things a bit neater in general. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20221031214037.1636-1-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_cdclk.c | 2 +- drivers/gpu/drm/i915/display/intel_color.c | 2 +- drivers/gpu/drm/i915/display/intel_display.c | 2 +- drivers/gpu/drm/i915/display/intel_fbc.c | 2 +- drivers/gpu/drm/i915/display/skl_watermark.c | 2 +- drivers/gpu/drm/i915/intel_pm.c | 11 +++++------ 6 files changed, 10 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index eada931cb1c8..8a9031012d74 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -2755,7 +2755,7 @@ int intel_modeset_calc_cdclk(struct intel_atomic_state *state) if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state); - if (drm_atomic_crtc_needs_modeset(&crtc_state->uapi)) + if (intel_crtc_needs_modeset(crtc_state)) pipe = INVALID_PIPE; } diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index 33871bfacee7..458e69578da6 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -1239,7 +1239,7 @@ intel_color_add_affected_planes(struct intel_crtc_state *new_crtc_state) struct intel_plane *plane; if (!new_crtc_state->hw.active || - drm_atomic_crtc_needs_modeset(&new_crtc_state->uapi)) + intel_crtc_needs_modeset(new_crtc_state)) return 0; if (new_crtc_state->gamma_enable == old_crtc_state->gamma_enable && diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 31e91dbaa368..c4d31db935fe 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -5931,7 +5931,7 @@ int intel_modeset_all_pipes(struct intel_atomic_state *state, return PTR_ERR(crtc_state); if (!crtc_state->hw.active || - drm_atomic_crtc_needs_modeset(&crtc_state->uapi)) + intel_crtc_needs_modeset(crtc_state)) continue; drm_dbg_kms(&dev_priv->drm, "[CRTC:%d:%s] Full modeset due to %s\n", diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c index 3f24f326b989..b5ee5ea0d010 100644 --- a/drivers/gpu/drm/i915/display/intel_fbc.c +++ b/drivers/gpu/drm/i915/display/intel_fbc.c @@ -1183,7 +1183,7 @@ static bool intel_fbc_can_flip_nuke(struct intel_atomic_state *state, const struct drm_framebuffer *old_fb = old_plane_state->hw.fb; const struct drm_framebuffer *new_fb = new_plane_state->hw.fb; - if (drm_atomic_crtc_needs_modeset(&new_crtc_state->uapi)) + if (intel_crtc_needs_modeset(new_crtc_state)) return false; if (!intel_fbc_is_ok(old_plane_state) || diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index d58e667016e4..e0766d1be966 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -2744,7 +2744,7 @@ static int skl_wm_add_affected_planes(struct intel_atomic_state *state, * power well the hardware state will go out of sync * with the software state. */ - if (!drm_atomic_crtc_needs_modeset(&new_crtc_state->uapi) && + if (!intel_crtc_needs_modeset(new_crtc_state) && skl_plane_selected_wm_equals(plane, &old_crtc_state->wm.skl.optimal, &new_crtc_state->wm.skl.optimal)) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index a204a32bce44..016ac568dc87 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1434,7 +1434,7 @@ static int g4x_compute_intermediate_wm(struct intel_atomic_state *state, enum plane_id plane_id; if (!new_crtc_state->hw.active || - drm_atomic_crtc_needs_modeset(&new_crtc_state->uapi)) { + intel_crtc_needs_modeset(new_crtc_state)) { *intermediate = *optimal; intermediate->cxsr = false; @@ -1922,7 +1922,6 @@ static int vlv_compute_pipe_wm(struct intel_atomic_state *state, { struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc); - bool needs_modeset = drm_atomic_crtc_needs_modeset(&crtc_state->uapi); const struct intel_plane_state *old_plane_state; const struct intel_plane_state *new_plane_state; struct intel_plane *plane; @@ -1949,7 +1948,7 @@ static int vlv_compute_pipe_wm(struct intel_atomic_state *state, * FIFO setting we took over from the BIOS even if there * are no active planes on the crtc. */ - if (needs_modeset) + if (intel_crtc_needs_modeset(crtc_state)) dirty = ~0; if (!dirty) @@ -1969,7 +1968,7 @@ static int vlv_compute_pipe_wm(struct intel_atomic_state *state, if (ret) return ret; - if (needs_modeset || + if (intel_crtc_needs_modeset(crtc_state) || memcmp(old_fifo_state, new_fifo_state, sizeof(*new_fifo_state)) != 0) crtc_state->fifo_changed = true; @@ -2092,7 +2091,7 @@ static int vlv_compute_intermediate_wm(struct intel_atomic_state *state, int level; if (!new_crtc_state->hw.active || - drm_atomic_crtc_needs_modeset(&new_crtc_state->uapi)) { + intel_crtc_needs_modeset(new_crtc_state)) { *intermediate = *optimal; intermediate->cxsr = false; @@ -3150,7 +3149,7 @@ static int ilk_compute_intermediate_wm(struct intel_atomic_state *state, */ *a = new_crtc_state->wm.ilk.optimal; if (!new_crtc_state->hw.active || - drm_atomic_crtc_needs_modeset(&new_crtc_state->uapi) || + intel_crtc_needs_modeset(new_crtc_state) || state->skip_intermediate_wm) return 0; -- cgit From 47078311b8efebdefd5b3b2f87e2b02b14f49c66 Mon Sep 17 00:00:00 2001 From: Yuan Can Date: Fri, 4 Nov 2022 06:45:12 +0000 Subject: drm/ingenic: Fix missing platform_driver_unregister() call in ingenic_drm_init() A problem about modprobe ingenic-drm failed is triggered with the following log given: [ 303.561088] Error: Driver 'ingenic-ipu' is already registered, aborting... modprobe: ERROR: could not insert 'ingenic_drm': Device or resource busy The reason is that ingenic_drm_init() returns platform_driver_register() directly without checking its return value, if platform_driver_register() failed, it returns without unregistering ingenic_ipu_driver_ptr, resulting the ingenic-drm can never be installed later. A simple call graph is shown as below: ingenic_drm_init() platform_driver_register() # ingenic_ipu_driver_ptr are registered platform_driver_register() driver_register() bus_add_driver() priv = kzalloc(...) # OOM happened # return without unregister ingenic_ipu_driver_ptr Fixing this problem by checking the return value of platform_driver_register() and do platform_unregister_drivers() if error happened. Fixes: fc1acf317b01 ("drm/ingenic: Add support for the IPU") Signed-off-by: Yuan Can Cc: stable@vger.kernel.org Signed-off-by: Paul Cercueil Link: https://patchwork.freedesktop.org/patch/msgid/20221104064512.8569-1-yuancan@huawei.com --- drivers/gpu/drm/ingenic/ingenic-drm-drv.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c index ab0515d2c420..4499a04f7c13 100644 --- a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c +++ b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c @@ -1629,7 +1629,11 @@ static int ingenic_drm_init(void) return err; } - return platform_driver_register(&ingenic_drm_driver); + err = platform_driver_register(&ingenic_drm_driver); + if (IS_ENABLED(CONFIG_DRM_INGENIC_IPU) && err) + platform_driver_unregister(ingenic_ipu_driver_ptr); + + return err; } module_init(ingenic_drm_init); -- cgit From 69a88d8633ecc577cb6915a4050ec1e7a4099814 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 26 Aug 2022 12:39:25 +0300 Subject: drm/msm/hdmi: move resource allocation to probe function Rather than having all resource allocation happen in the _bind function (resulting in possible EPROBE_DEFER returns and component bind/unbind cycles) allocate and check all resources in _probe function. While we are at it, use platform_get_irq() to get the IRQ rather than going through the irq_of_parse_and_map(). Signed-off-by: Dmitry Baryshkov Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/499649/ Link: https://lore.kernel.org/r/20220826093927.851597-4-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/hdmi/hdmi.c | 304 ++++++++++++++++++---------------------- 1 file changed, 138 insertions(+), 166 deletions(-) diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index 6bb237bd3ab8..416395837b64 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -76,8 +76,6 @@ static void msm_hdmi_destroy(struct hdmi *hdmi) if (hdmi->i2c) msm_hdmi_i2c_destroy(hdmi->i2c); - - platform_set_drvdata(hdmi->pdev, NULL); } static int msm_hdmi_get_phy(struct hdmi *hdmi) @@ -117,142 +115,10 @@ static int msm_hdmi_get_phy(struct hdmi *hdmi) * we are to EPROBE_DEFER we want to do it here, rather than later * at modeset_init() time */ -static struct hdmi *msm_hdmi_init(struct platform_device *pdev) +static int msm_hdmi_init(struct hdmi *hdmi) { - struct hdmi_platform_config *config = pdev->dev.platform_data; - struct hdmi *hdmi = NULL; - struct resource *res; - int i, ret; - - hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL); - if (!hdmi) { - ret = -ENOMEM; - goto fail; - } - - hdmi->pdev = pdev; - hdmi->config = config; - spin_lock_init(&hdmi->reg_lock); - - ret = drm_of_find_panel_or_bridge(pdev->dev.of_node, 1, 0, NULL, &hdmi->next_bridge); - if (ret && ret != -ENODEV) - goto fail; - - hdmi->mmio = msm_ioremap(pdev, "core_physical"); - if (IS_ERR(hdmi->mmio)) { - ret = PTR_ERR(hdmi->mmio); - goto fail; - } - - /* HDCP needs physical address of hdmi register */ - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "core_physical"); - if (!res) { - ret = -EINVAL; - goto fail; - } - hdmi->mmio_phy_addr = res->start; - - hdmi->qfprom_mmio = msm_ioremap(pdev, "qfprom_physical"); - if (IS_ERR(hdmi->qfprom_mmio)) { - DRM_DEV_INFO(&pdev->dev, "can't find qfprom resource\n"); - hdmi->qfprom_mmio = NULL; - } - - hdmi->hpd_regs = devm_kcalloc(&pdev->dev, - config->hpd_reg_cnt, - sizeof(hdmi->hpd_regs[0]), - GFP_KERNEL); - if (!hdmi->hpd_regs) { - ret = -ENOMEM; - goto fail; - } - for (i = 0; i < config->hpd_reg_cnt; i++) - hdmi->hpd_regs[i].supply = config->hpd_reg_names[i]; - - ret = devm_regulator_bulk_get(&pdev->dev, config->hpd_reg_cnt, hdmi->hpd_regs); - if (ret) { - DRM_DEV_ERROR(&pdev->dev, "failed to get hpd regulator: %d\n", ret); - goto fail; - } - - hdmi->pwr_regs = devm_kcalloc(&pdev->dev, - config->pwr_reg_cnt, - sizeof(hdmi->pwr_regs[0]), - GFP_KERNEL); - if (!hdmi->pwr_regs) { - ret = -ENOMEM; - goto fail; - } - - for (i = 0; i < config->pwr_reg_cnt; i++) - hdmi->pwr_regs[i].supply = config->pwr_reg_names[i]; - - ret = devm_regulator_bulk_get(&pdev->dev, config->pwr_reg_cnt, hdmi->pwr_regs); - if (ret) { - DRM_DEV_ERROR(&pdev->dev, "failed to get pwr regulator: %d\n", ret); - goto fail; - } - - hdmi->hpd_clks = devm_kcalloc(&pdev->dev, - config->hpd_clk_cnt, - sizeof(hdmi->hpd_clks[0]), - GFP_KERNEL); - if (!hdmi->hpd_clks) { - ret = -ENOMEM; - goto fail; - } - for (i = 0; i < config->hpd_clk_cnt; i++) { - struct clk *clk; - - clk = msm_clk_get(pdev, config->hpd_clk_names[i]); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - DRM_DEV_ERROR(&pdev->dev, "failed to get hpd clk: %s (%d)\n", - config->hpd_clk_names[i], ret); - goto fail; - } - - hdmi->hpd_clks[i] = clk; - } - - hdmi->pwr_clks = devm_kcalloc(&pdev->dev, - config->pwr_clk_cnt, - sizeof(hdmi->pwr_clks[0]), - GFP_KERNEL); - if (!hdmi->pwr_clks) { - ret = -ENOMEM; - goto fail; - } - for (i = 0; i < config->pwr_clk_cnt; i++) { - struct clk *clk; - - clk = msm_clk_get(pdev, config->pwr_clk_names[i]); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - DRM_DEV_ERROR(&pdev->dev, "failed to get pwr clk: %s (%d)\n", - config->pwr_clk_names[i], ret); - goto fail; - } - - hdmi->pwr_clks[i] = clk; - } - - hdmi->hpd_gpiod = devm_gpiod_get_optional(&pdev->dev, "hpd", GPIOD_IN); - /* This will catch e.g. -EPROBE_DEFER */ - if (IS_ERR(hdmi->hpd_gpiod)) { - ret = PTR_ERR(hdmi->hpd_gpiod); - DRM_DEV_ERROR(&pdev->dev, "failed to get hpd gpio: (%d)\n", ret); - goto fail; - } - - if (!hdmi->hpd_gpiod) - DBG("failed to get HPD gpio"); - - if (hdmi->hpd_gpiod) - gpiod_set_consumer_name(hdmi->hpd_gpiod, "HDMI_HPD"); - - devm_pm_runtime_enable(&pdev->dev); + struct platform_device *pdev = hdmi->pdev; + int ret; hdmi->workq = alloc_ordered_workqueue("msm_hdmi", 0); @@ -276,13 +142,13 @@ static struct hdmi *msm_hdmi_init(struct platform_device *pdev) hdmi->hdcp_ctrl = NULL; } - return hdmi; + return 0; fail: if (hdmi) msm_hdmi_destroy(hdmi); - return ERR_PTR(ret); + return ret; } /* Second part of initialization, the drm/kms level modeset_init, @@ -297,7 +163,6 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi, struct drm_device *dev, struct drm_encoder *encoder) { struct msm_drm_private *priv = dev->dev_private; - struct platform_device *pdev = hdmi->pdev; int ret; if (priv->num_bridges == ARRAY_SIZE(priv->bridges)) { @@ -337,13 +202,6 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi, drm_connector_attach_encoder(hdmi->connector, hdmi->encoder); - hdmi->irq = irq_of_parse_and_map(pdev->dev.of_node, 0); - if (!hdmi->irq) { - ret = -EINVAL; - DRM_DEV_ERROR(dev->dev, "failed to get irq\n"); - goto fail; - } - ret = devm_request_irq(dev->dev, hdmi->irq, msm_hdmi_irq, IRQF_TRIGGER_HIGH, "hdmi_isr", hdmi); @@ -363,8 +221,6 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi, priv->bridges[priv->num_bridges++] = hdmi->bridge; - platform_set_drvdata(pdev, hdmi); - return 0; fail: @@ -392,7 +248,7 @@ fail: static const char *hpd_reg_names_8960[] = {"core-vdda"}; static const char *hpd_clk_names_8960[] = {"core", "master_iface", "slave_iface"}; -static struct hdmi_platform_config hdmi_tx_8960_config = { +static const struct hdmi_platform_config hdmi_tx_8960_config = { HDMI_CFG(hpd_reg, 8960), HDMI_CFG(hpd_clk, 8960), }; @@ -402,7 +258,7 @@ static const char *pwr_clk_names_8x74[] = {"extp", "alt_iface"}; static const char *hpd_clk_names_8x74[] = {"iface", "core", "mdp_core"}; static unsigned long hpd_clk_freq_8x74[] = {0, 19200000, 0}; -static struct hdmi_platform_config hdmi_tx_8974_config = { +static const struct hdmi_platform_config hdmi_tx_8974_config = { HDMI_CFG(pwr_reg, 8x74), HDMI_CFG(pwr_clk, 8x74), HDMI_CFG(hpd_clk, 8x74), @@ -517,23 +373,12 @@ static int msm_hdmi_register_audio_driver(struct hdmi *hdmi, struct device *dev) static int msm_hdmi_bind(struct device *dev, struct device *master, void *data) { struct msm_drm_private *priv = dev_get_drvdata(master); - struct hdmi_platform_config *hdmi_cfg; - struct hdmi *hdmi; - struct device_node *of_node = dev->of_node; + struct hdmi *hdmi = dev_get_drvdata(dev); int err; - hdmi_cfg = (struct hdmi_platform_config *) - of_device_get_match_data(dev); - if (!hdmi_cfg) { - DRM_DEV_ERROR(dev, "unknown hdmi_cfg: %pOFn\n", of_node); - return -ENXIO; - } - - dev->platform_data = hdmi_cfg; - - hdmi = msm_hdmi_init(to_platform_device(dev)); - if (IS_ERR(hdmi)) - return PTR_ERR(hdmi); + err = msm_hdmi_init(hdmi); + if (err) + return err; priv->hdmi = hdmi; err = msm_hdmi_register_audio_driver(hdmi, dev); @@ -566,6 +411,133 @@ static const struct component_ops msm_hdmi_ops = { static int msm_hdmi_dev_probe(struct platform_device *pdev) { + const struct hdmi_platform_config *config; + struct device *dev = &pdev->dev; + struct hdmi *hdmi; + struct resource *res; + int i, ret; + + config = of_device_get_match_data(dev); + if (!config) + return -EINVAL; + + hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL); + if (!hdmi) + return -ENOMEM; + + hdmi->pdev = pdev; + hdmi->config = config; + spin_lock_init(&hdmi->reg_lock); + + ret = drm_of_find_panel_or_bridge(pdev->dev.of_node, 1, 0, NULL, &hdmi->next_bridge); + if (ret && ret != -ENODEV) + return ret; + + hdmi->mmio = msm_ioremap(pdev, "core_physical"); + if (IS_ERR(hdmi->mmio)) + return PTR_ERR(hdmi->mmio); + + /* HDCP needs physical address of hdmi register */ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "core_physical"); + if (!res) + return -EINVAL; + hdmi->mmio_phy_addr = res->start; + + hdmi->qfprom_mmio = msm_ioremap(pdev, "qfprom_physical"); + if (IS_ERR(hdmi->qfprom_mmio)) { + DRM_DEV_INFO(&pdev->dev, "can't find qfprom resource\n"); + hdmi->qfprom_mmio = NULL; + } + + hdmi->irq = platform_get_irq(pdev, 0); + if (hdmi->irq < 0) + return hdmi->irq; + + hdmi->hpd_regs = devm_kcalloc(&pdev->dev, + config->hpd_reg_cnt, + sizeof(hdmi->hpd_regs[0]), + GFP_KERNEL); + if (!hdmi->hpd_regs) + return -ENOMEM; + + for (i = 0; i < config->hpd_reg_cnt; i++) + hdmi->hpd_regs[i].supply = config->hpd_reg_names[i]; + + ret = devm_regulator_bulk_get(&pdev->dev, config->hpd_reg_cnt, hdmi->hpd_regs); + if (ret) + return dev_err_probe(dev, ret, "failed to get hpd regulators\n"); + + hdmi->pwr_regs = devm_kcalloc(&pdev->dev, + config->pwr_reg_cnt, + sizeof(hdmi->pwr_regs[0]), + GFP_KERNEL); + if (!hdmi->pwr_regs) + return -ENOMEM; + + for (i = 0; i < config->pwr_reg_cnt; i++) + hdmi->pwr_regs[i].supply = config->pwr_reg_names[i]; + + ret = devm_regulator_bulk_get(&pdev->dev, config->pwr_reg_cnt, hdmi->pwr_regs); + if (ret) + return dev_err_probe(dev, ret, "failed to get pwr regulators\n"); + + hdmi->hpd_clks = devm_kcalloc(&pdev->dev, + config->hpd_clk_cnt, + sizeof(hdmi->hpd_clks[0]), + GFP_KERNEL); + if (!hdmi->hpd_clks) + return -ENOMEM; + + for (i = 0; i < config->hpd_clk_cnt; i++) { + struct clk *clk; + + clk = msm_clk_get(pdev, config->hpd_clk_names[i]); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), + "failed to get hpd clk: %s\n", + config->hpd_clk_names[i]); + + hdmi->hpd_clks[i] = clk; + } + + hdmi->pwr_clks = devm_kcalloc(&pdev->dev, + config->pwr_clk_cnt, + sizeof(hdmi->pwr_clks[0]), + GFP_KERNEL); + if (!hdmi->pwr_clks) + return -ENOMEM; + + for (i = 0; i < config->pwr_clk_cnt; i++) { + struct clk *clk; + + clk = msm_clk_get(pdev, config->pwr_clk_names[i]); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), + "failed to get pwr clk: %s\n", + config->pwr_clk_names[i]); + + hdmi->pwr_clks[i] = clk; + } + + hdmi->hpd_gpiod = devm_gpiod_get_optional(&pdev->dev, "hpd", GPIOD_IN); + /* This will catch e.g. -EPROBE_DEFER */ + if (IS_ERR(hdmi->hpd_gpiod)) + return dev_err_probe(dev, PTR_ERR(hdmi->hpd_gpiod), + "failed to get hpd gpio\n"); + + if (!hdmi->hpd_gpiod) + DBG("failed to get HPD gpio"); + + if (hdmi->hpd_gpiod) + gpiod_set_consumer_name(hdmi->hpd_gpiod, "HDMI_HPD"); + + ret = devm_pm_runtime_enable(&pdev->dev); + if (ret) + return ret; + + platform_set_drvdata(pdev, hdmi); + return component_add(&pdev->dev, &msm_hdmi_ops); } -- cgit From 248adb815bc138e9d7d73a73c608b87b080d3740 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 26 Aug 2022 12:39:26 +0300 Subject: drm/msm/hdmi: don't take extra reference on PHY device The of_find_device_by_node() already increments the device's usage count, so there is no need to increment it again using get_device(). Drop this extra get_device(). Signed-off-by: Dmitry Baryshkov Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/499648/ Link: https://lore.kernel.org/r/20220826093927.851597-5-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/hdmi/hdmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index 416395837b64..8c83371d40d0 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -106,7 +106,7 @@ static int msm_hdmi_get_phy(struct hdmi *hdmi) return -EPROBE_DEFER; } - hdmi->phy_dev = get_device(&phy_pdev->dev); + hdmi->phy_dev = &phy_pdev->dev; return 0; } -- cgit From 43736546404368c3e4c6fb4326d843965fcc991e Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 26 Aug 2022 12:39:27 +0300 Subject: drm/msm/hdmi: move msm_hdmi_get_phy() to msm_hdmi_dev_probe() To continue the idea of failing the probe() rather than failing the bind(), move the call to msm_hdmi_get_phy() function to msm_hdmi_dev_probe(), so that the driver fails the probe if PHY is not yet available rather than succeeding the probe and then failing the bind() with -EPROBE_DEFER. Signed-off-by: Dmitry Baryshkov Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/499652/ Link: https://lore.kernel.org/r/20220826093927.851597-6-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/hdmi/hdmi.c | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index 8c83371d40d0..7001fabd0977 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -68,14 +68,17 @@ static void msm_hdmi_destroy(struct hdmi *hdmi) destroy_workqueue(hdmi->workq); msm_hdmi_hdcp_destroy(hdmi); + if (hdmi->i2c) + msm_hdmi_i2c_destroy(hdmi->i2c); +} + +static void msm_hdmi_put_phy(struct hdmi *hdmi) +{ if (hdmi->phy_dev) { put_device(hdmi->phy_dev); hdmi->phy = NULL; hdmi->phy_dev = NULL; } - - if (hdmi->i2c) - msm_hdmi_i2c_destroy(hdmi->i2c); } static int msm_hdmi_get_phy(struct hdmi *hdmi) @@ -91,19 +94,15 @@ static int msm_hdmi_get_phy(struct hdmi *hdmi) } phy_pdev = of_find_device_by_node(phy_node); - if (phy_pdev) - hdmi->phy = platform_get_drvdata(phy_pdev); - of_node_put(phy_node); - if (!phy_pdev) { - DRM_DEV_ERROR(&pdev->dev, "phy driver is not ready\n"); - return -EPROBE_DEFER; - } + if (!phy_pdev) + return dev_err_probe(&pdev->dev, -EPROBE_DEFER, "phy driver is not ready\n"); + + hdmi->phy = platform_get_drvdata(phy_pdev); if (!hdmi->phy) { - DRM_DEV_ERROR(&pdev->dev, "phy driver is not ready\n"); put_device(&phy_pdev->dev); - return -EPROBE_DEFER; + return dev_err_probe(&pdev->dev, -EPROBE_DEFER, "phy driver is not ready\n"); } hdmi->phy_dev = &phy_pdev->dev; @@ -130,12 +129,6 @@ static int msm_hdmi_init(struct hdmi *hdmi) goto fail; } - ret = msm_hdmi_get_phy(hdmi); - if (ret) { - DRM_DEV_ERROR(&pdev->dev, "failed to get phy\n"); - goto fail; - } - hdmi->hdcp_ctrl = msm_hdmi_hdcp_init(hdmi); if (IS_ERR(hdmi->hdcp_ctrl)) { dev_warn(&pdev->dev, "failed to init hdcp: disabled\n"); @@ -532,6 +525,12 @@ static int msm_hdmi_dev_probe(struct platform_device *pdev) if (hdmi->hpd_gpiod) gpiod_set_consumer_name(hdmi->hpd_gpiod, "HDMI_HPD"); + ret = msm_hdmi_get_phy(hdmi); + if (ret) { + DRM_DEV_ERROR(&pdev->dev, "failed to get phy\n"); + return ret; + } + ret = devm_pm_runtime_enable(&pdev->dev); if (ret) return ret; @@ -543,7 +542,12 @@ static int msm_hdmi_dev_probe(struct platform_device *pdev) static int msm_hdmi_dev_remove(struct platform_device *pdev) { + struct hdmi *hdmi = dev_get_drvdata(&pdev->dev); + component_del(&pdev->dev, &msm_hdmi_ops); + + msm_hdmi_put_phy(hdmi); + return 0; } -- cgit From e67e865b90b511bf78357ff36fdef99627d829c9 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 3 Nov 2022 11:16:26 +0100 Subject: drm/ofdrm: Convert PCI IDs to CPU endianness for comparing Properties of 32-bit integers are returned from the OF device tree as type __be32. Convert PCI vendor and device IDs from __be32 to host endianness before comparing them to constants. All relevant machines are old, big-endian Macintosh systems; hence the bug never happened in practice. Fixes sparse warnings shown below. drivers/gpu/drm/tiny/ofdrm.c:237:17: warning: restricted __be32 degrades to integer drivers/gpu/drm/tiny/ofdrm.c:238:18: warning: restricted __be32 degrades to integer drivers/gpu/drm/tiny/ofdrm.c:238:54: warning: restricted __be32 degrades to integer See [1] for the bug report. v2: * convert endianness (Alex) Reported-by: kernel test robot Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://lore.kernel.org/dri-devel/202210192208.D888I6X7-lkp@intel.com/ # [1] Link: https://patchwork.freedesktop.org/patch/msgid/20221103101627.32502-2-tzimmermann@suse.de --- drivers/gpu/drm/tiny/ofdrm.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/tiny/ofdrm.c b/drivers/gpu/drm/tiny/ofdrm.c index 0e1cc2369afc..44f13a2b372b 100644 --- a/drivers/gpu/drm/tiny/ofdrm.c +++ b/drivers/gpu/drm/tiny/ofdrm.c @@ -231,7 +231,7 @@ static u64 display_get_address_of(struct drm_device *dev, struct device_node *of return address; } -static bool is_avivo(__be32 vendor, __be32 device) +static bool is_avivo(u32 vendor, u32 device) { /* This will match most R5xx */ return (vendor == PCI_VENDOR_ID_ATI) && @@ -265,8 +265,13 @@ static enum ofdrm_model display_get_model_of(struct drm_device *dev, struct devi of_parent = of_get_parent(of_node); vendor_p = of_get_property(of_parent, "vendor-id", NULL); device_p = of_get_property(of_parent, "device-id", NULL); - if (vendor_p && device_p && is_avivo(*vendor_p, *device_p)) - model = OFDRM_MODEL_AVIVO; + if (vendor_p && device_p) { + u32 vendor = be32_to_cpup(vendor_p); + u32 device = be32_to_cpup(device_p); + + if (is_avivo(vendor, device)) + model = OFDRM_MODEL_AVIVO; + } of_node_put(of_parent); } else if (of_device_is_compatible(of_node, "qemu,std-vga")) { model = OFDRM_MODEL_QEMU; -- cgit From a8300c46385e357079248302722d2f6b48adcba1 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 3 Nov 2022 11:16:27 +0100 Subject: drm/ofdrm: Cast error pointers to void __iomem * Cast error pointers when returning them as void __iomem *. Fixes a number of Sparse warnings, such as the ones shown below. ../drivers/gpu/drm/tiny/ofdrm.c:439:31: warning: incorrect type in return expression (different address spaces) ../drivers/gpu/drm/tiny/ofdrm.c:439:31: expected void [noderef] __iomem * ../drivers/gpu/drm/tiny/ofdrm.c:439:31: got void * ../drivers/gpu/drm/tiny/ofdrm.c:442:31: warning: incorrect type in return expression (different address spaces) ../drivers/gpu/drm/tiny/ofdrm.c:442:31: expected void [noderef] __iomem * ../drivers/gpu/drm/tiny/ofdrm.c:442:31: got void * See [1] for the bug report. v3: * use IOMEM_ERR_PTR() (Javier) Reported-by: kernel test robot Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://lore.kernel.org/dri-devel/202210200016.yiQzPIy0-lkp@intel.com/ # [1] Link: https://patchwork.freedesktop.org/patch/msgid/20221103101627.32502-3-tzimmermann@suse.de --- drivers/gpu/drm/tiny/ofdrm.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/tiny/ofdrm.c b/drivers/gpu/drm/tiny/ofdrm.c index 44f13a2b372b..d7f98dcf2330 100644 --- a/drivers/gpu/drm/tiny/ofdrm.c +++ b/drivers/gpu/drm/tiny/ofdrm.c @@ -438,21 +438,21 @@ static void __iomem *get_cmap_address_of(struct ofdrm_device *odev, struct devic if (!addr_p) addr_p = of_get_address(of_node, bar_no, &max_size, &flags); if (!addr_p) - return ERR_PTR(-ENODEV); + return IOMEM_ERR_PTR(-ENODEV); if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0) - return ERR_PTR(-ENODEV); + return IOMEM_ERR_PTR(-ENODEV); if ((offset + size) >= max_size) - return ERR_PTR(-ENODEV); + return IOMEM_ERR_PTR(-ENODEV); address = of_translate_address(of_node, addr_p); if (address == OF_BAD_ADDR) - return ERR_PTR(-ENODEV); + return IOMEM_ERR_PTR(-ENODEV); mem = devm_ioremap(dev->dev, address + offset, size); if (!mem) - return ERR_PTR(-ENOMEM); + return IOMEM_ERR_PTR(-ENOMEM); return mem; } @@ -470,7 +470,7 @@ static void __iomem *ofdrm_mach64_cmap_ioremap(struct ofdrm_device *odev, cmap_base = devm_ioremap(dev->dev, address, 0x1000); if (!cmap_base) - return ERR_PTR(-ENOMEM); + return IOMEM_ERR_PTR(-ENOMEM); return cmap_base; } @@ -629,11 +629,11 @@ static void __iomem *ofdrm_qemu_cmap_ioremap(struct ofdrm_device *odev, address = of_translate_address(of_node, io_of_addr); if (address == OF_BAD_ADDR) - return ERR_PTR(-ENODEV); + return IOMEM_ERR_PTR(-ENODEV); cmap_base = devm_ioremap(dev->dev, address + 0x3c8, 2); if (!cmap_base) - return ERR_PTR(-ENOMEM); + return IOMEM_ERR_PTR(-ENOMEM); return cmap_base; } -- cgit From 6f7de35b50860c345babf8ed0aa0d75f9315eee4 Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Fri, 28 Oct 2022 14:06:35 +0100 Subject: drm/i915/userptr: restore probe_range behaviour The conversion looks harmless, however the addr value is updated inside the loop with the previous vm_end, which then incorrectly leads to for_each_vma_range() iterating over stuff outside the range we care about. Fix this by storing the end value separately. Also fix the case where the range doesn't intersect with any vma, or if the vma itself doesn't extend the entire range, which must mean we have hole at the end. Both should result in an error, as per the previous behaviour. v2: Fix the cases where the range is empty, or if there's a hole at the end of the range Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/7247 Testcase: igt@gem_userptr_blits@probe Fixes: f683b9d61319 ("i915: use the VMA iterator") Reported-by: kernel test robot Signed-off-by: Matthew Auld Cc: Tvrtko Ursulin Cc: Matthew Wilcox (Oracle) Cc: Liam R. Howlett Cc: Vlastimil Babka Cc: Yu Zhao Reviewed-by: Liam R. Howlett Reviewed-by: Andrzej Hajda Link: https://patchwork.freedesktop.org/patch/msgid/20221028130635.465839-1-matthew.auld@intel.com --- drivers/gpu/drm/i915/gem/i915_gem_userptr.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_userptr.c b/drivers/gpu/drm/i915/gem/i915_gem_userptr.c index 1b1a22716722..ca7a388ba2bf 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_userptr.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_userptr.c @@ -427,9 +427,10 @@ probe_range(struct mm_struct *mm, unsigned long addr, unsigned long len) { VMA_ITERATOR(vmi, mm, addr); struct vm_area_struct *vma; + unsigned long end = addr + len; mmap_read_lock(mm); - for_each_vma_range(vmi, vma, addr + len) { + for_each_vma_range(vmi, vma, end) { /* Check for holes, note that we also update the addr below */ if (vma->vm_start > addr) break; @@ -441,7 +442,7 @@ probe_range(struct mm_struct *mm, unsigned long addr, unsigned long len) } mmap_read_unlock(mm); - if (vma) + if (vma || addr < end) return -EFAULT; return 0; } -- cgit From f94eff09f3f36902a2996f075719b289cb91d758 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 13 Sep 2022 10:53:19 +0200 Subject: drm/msm/dp: drop modeset sanity checks Drop the overly defensive modeset sanity checks of function parameters which have already been checked or used by the callers. Reviewed-by: Dmitry Baryshkov Signed-off-by: Johan Hovold Tested-by: Kuogee Hsieh Reviewed-by: Kuogee Hsieh Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/502674/ Link: https://lore.kernel.org/r/20220913085320.8577-10-johan+linaro@kernel.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/dp/dp_display.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index a49f6dbbe888..44676f0bb3ef 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -1600,20 +1600,10 @@ error: int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev, struct drm_encoder *encoder) { - struct msm_drm_private *priv; + struct msm_drm_private *priv = dev->dev_private; struct dp_display_private *dp_priv; int ret; - if (WARN_ON(!encoder) || WARN_ON(!dp_display) || WARN_ON(!dev)) - return -EINVAL; - - priv = dev->dev_private; - - if (priv->num_bridges == ARRAY_SIZE(priv->bridges)) { - DRM_DEV_ERROR(dev->dev, "too many bridges\n"); - return -ENOSPC; - } - dp_display->drm_dev = dev; dp_priv = container_of(dp_display, struct dp_display_private, dp_display); -- cgit From d3c1a8663d0ddb74eaa51121ccbb8340739a12a8 Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Wed, 26 Oct 2022 20:28:23 +0200 Subject: drm/msm/dpu1: Account for DSC's bits_per_pixel having 4 fractional bits According to the comment this DPU register contains the bits per pixel as a 6.4 fractional value, conveniently matching the contents of bits_per_pixel in struct drm_dsc_config which also uses 4 fractional bits. However, the downstream source this implementation was copy-pasted from has its bpp field stored _without_ fractional part. This makes the entire convoluted math obsolete as it is impossible to pull those 4 fractional bits out of thin air, by somehow trying to reuse the lowest 2 bits of a non-fractional bpp (lsb = bpp % 4??). The rest of the code merely attempts to keep the integer part a multiple of 4, which is rendered useless thanks to data |= dsc->bits_per_pixel << 12; already filling up those bits anyway (but not on downstream). Fixes: c110cfd1753e ("drm/msm/disp/dpu1: Add support for DSC") Signed-off-by: Marijn Suijten Reviewed-by: Abhinav Kumar Reviewed-by: Dmitry Baryshkov Reviewed-by: Vinod Koul Patchwork: https://patchwork.freedesktop.org/patch/508946/ Link: https://lore.kernel.org/r/20221026182824.876933-10-marijn.suijten@somainline.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c index f2ddcfb6f7ee..3662df698dae 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c @@ -42,7 +42,7 @@ static void dpu_hw_dsc_config(struct dpu_hw_dsc *hw_dsc, u32 initial_lines) { struct dpu_hw_blk_reg_map *c = &hw_dsc->hw; - u32 data, lsb, bpp; + u32 data; u32 slice_last_group_size; u32 det_thresh_flatness; bool is_cmd_mode = !(mode & DSC_MODE_VIDEO); @@ -56,14 +56,7 @@ static void dpu_hw_dsc_config(struct dpu_hw_dsc *hw_dsc, data = (initial_lines << 20); data |= ((slice_last_group_size - 1) << 18); /* bpp is 6.4 format, 4 LSBs bits are for fractional part */ - data |= dsc->bits_per_pixel << 12; - lsb = dsc->bits_per_pixel % 4; - bpp = dsc->bits_per_pixel / 4; - bpp *= 4; - bpp <<= 4; - bpp |= lsb; - - data |= bpp << 8; + data |= (dsc->bits_per_pixel << 8); data |= (dsc->block_pred_enable << 7); data |= (dsc->line_buf_depth << 3); data |= (dsc->simple_422 << 2); -- cgit From e512ed607fdac79b25448d4f2a4a8e8b6d546a02 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 13 Sep 2022 10:53:20 +0200 Subject: drm/msm/dsi: drop modeset sanity checks Drop the overly defensive modeset sanity checks of function parameters which have already been checked or used by the callers. Reviewed-by: Dmitry Baryshkov Signed-off-by: Johan Hovold Tested-by: Kuogee Hsieh Reviewed-by: Kuogee Hsieh Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/502678/ Link: https://lore.kernel.org/r/20220913085320.8577-11-johan+linaro@kernel.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/dsi/dsi.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c index 8a95c744972a..31fdee2052be 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.c +++ b/drivers/gpu/drm/msm/dsi/dsi.c @@ -211,14 +211,9 @@ void __exit msm_dsi_unregister(void) int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev, struct drm_encoder *encoder) { - struct msm_drm_private *priv; + struct msm_drm_private *priv = dev->dev_private; int ret; - if (WARN_ON(!encoder) || WARN_ON(!msm_dsi) || WARN_ON(!dev)) - return -EINVAL; - - priv = dev->dev_private; - if (priv->num_bridges == ARRAY_SIZE(priv->bridges)) { DRM_DEV_ERROR(dev->dev, "too many bridges\n"); return -ENOSPC; -- cgit From 2387771f45042ca05eeeeca2e802a65910c499cf Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Sat, 24 Sep 2022 15:18:59 +0300 Subject: dt-bindings: display/msm: Add QCM2290 DSI phy QCM2290 platform uses the 14nm DSI PHY driver. Signed-off-by: Loic Poulain Signed-off-by: Dmitry Baryshkov Acked-by: Rob Herring Patchwork: https://patchwork.freedesktop.org/patch/504579/ Link: https://lore.kernel.org/r/20220924121900.222711-2-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov --- Documentation/devicetree/bindings/display/msm/dsi-phy-14nm.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/display/msm/dsi-phy-14nm.yaml b/Documentation/devicetree/bindings/display/msm/dsi-phy-14nm.yaml index 1342d74ecfe0..819de5ce0bc9 100644 --- a/Documentation/devicetree/bindings/display/msm/dsi-phy-14nm.yaml +++ b/Documentation/devicetree/bindings/display/msm/dsi-phy-14nm.yaml @@ -16,6 +16,7 @@ properties: compatible: enum: - qcom,dsi-phy-14nm + - qcom,dsi-phy-14nm-2290 - qcom,dsi-phy-14nm-660 - qcom,dsi-phy-14nm-8953 -- cgit From 572e9fd6d14a4568ee731c84e54ceaa243c82408 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Sat, 24 Sep 2022 15:19:00 +0300 Subject: drm/msm/dsi: Add phy configuration for QCM2290 The QCM2290 SoC a the 14nm (V2.0) single DSI phy. The platform is not fully compatible with the standard 14nm PHY, so it requires a separate compatible and config entry. Signed-off-by: Loic Poulain [DB: rebased and updated commit msg] Signed-off-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Patchwork: https://patchwork.freedesktop.org/patch/504578/ Link: https://lore.kernel.org/r/20220924121900.222711-3-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/dsi/phy/dsi_phy.c | 2 ++ drivers/gpu/drm/msm/dsi/phy/dsi_phy.h | 1 + drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c | 17 +++++++++++++++++ 3 files changed, 20 insertions(+) diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c index 7fc0975cb869..ee6051367679 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c @@ -549,6 +549,8 @@ static const struct of_device_id dsi_phy_dt_match[] = { #ifdef CONFIG_DRM_MSM_DSI_14NM_PHY { .compatible = "qcom,dsi-phy-14nm", .data = &dsi_phy_14nm_cfgs }, + { .compatible = "qcom,dsi-phy-14nm-2290", + .data = &dsi_phy_14nm_2290_cfgs }, { .compatible = "qcom,dsi-phy-14nm-660", .data = &dsi_phy_14nm_660_cfgs }, { .compatible = "qcom,dsi-phy-14nm-8953", diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h index 60a99c6525b2..1096afedd616 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h @@ -50,6 +50,7 @@ extern const struct msm_dsi_phy_cfg dsi_phy_20nm_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_28nm_8960_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_14nm_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_14nm_660_cfgs; +extern const struct msm_dsi_phy_cfg dsi_phy_14nm_2290_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_14nm_8953_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_10nm_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_10nm_8998_cfgs; diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c index 0f8f4ca46429..9f488adea7f5 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c @@ -1081,3 +1081,20 @@ const struct msm_dsi_phy_cfg dsi_phy_14nm_8953_cfgs = { .io_start = { 0x1a94400, 0x1a96400 }, .num_dsi_phy = 2, }; + +const struct msm_dsi_phy_cfg dsi_phy_14nm_2290_cfgs = { + .has_phy_lane = true, + .regulator_data = dsi_phy_14nm_17mA_regulators, + .num_regulators = ARRAY_SIZE(dsi_phy_14nm_17mA_regulators), + .ops = { + .enable = dsi_14nm_phy_enable, + .disable = dsi_14nm_phy_disable, + .pll_init = dsi_pll_14nm_init, + .save_pll_state = dsi_14nm_pll_save_state, + .restore_pll_state = dsi_14nm_pll_restore_state, + }, + .min_pll_rate = VCO_MIN_RATE, + .max_pll_rate = VCO_MAX_RATE, + .io_start = { 0x5e94400 }, + .num_dsi_phy = 1, +}; -- cgit From 01a907980e0be3310f18c7d4955968f3b28e7147 Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Wed, 26 Oct 2022 20:28:15 +0200 Subject: drm/msm/dsi: Remove useless math in DSC calculations Multiplying a value by 2 and adding 1 to it always results in a value that is uneven, and that 1 gets truncated immediately when performing integer division by 2 again. There is no "rounding" possible here. After that target_bpp_x16 is used to store a multiplication of bits_per_pixel by 16 which is only ever read to immediately be divided by 16 again, and is elided in much the same way. Fixes: b9080324d6ca ("drm/msm/dsi: add support for dsc data") Reviewed-by: Abhinav Kumar Reviewed-by: Dmitry Baryshkov Signed-off-by: Marijn Suijten Patchwork: https://patchwork.freedesktop.org/patch/508932/ Link: https://lore.kernel.org/r/20221026182824.876933-2-marijn.suijten@somainline.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/dsi/dsi_host.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 7fbf391c024f..8026fe65bff6 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -1762,7 +1762,6 @@ static int dsi_populate_dsc_params(struct drm_dsc_config *dsc) int hrd_delay; int pre_num_extra_mux_bits, num_extra_mux_bits; int slice_bits; - int target_bpp_x16; int data; int final_value, final_scale; int i; @@ -1842,14 +1841,7 @@ static int dsi_populate_dsc_params(struct drm_dsc_config *dsc) data = 2048 * (dsc->rc_model_size - dsc->initial_offset + num_extra_mux_bits); dsc->slice_bpg_offset = DIV_ROUND_UP(data, groups_total); - /* bpp * 16 + 0.5 */ - data = dsc->bits_per_pixel * 16; - data *= 2; - data++; - data /= 2; - target_bpp_x16 = data; - - data = (dsc->initial_xmit_delay * target_bpp_x16) / 16; + data = dsc->initial_xmit_delay * dsc->bits_per_pixel; final_value = dsc->rc_model_size - data + num_extra_mux_bits; dsc->final_offset = final_value; -- cgit From 170ffca836dd9f1a0219c4f67554d408fa2b5912 Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Wed, 26 Oct 2022 20:28:16 +0200 Subject: drm/msm/dsi: Remove repeated calculation of slice_per_intf slice_per_intf is already computed for intf_width, which holds the same value as hdisplay. Fixes: 08802f515c3c ("drm/msm/dsi: Add support for DSC configuration") Reviewed-by: Bjorn Andersson Reviewed-by: Konrad Dybcio Reviewed-by: Abhinav Kumar Reviewed-by: Vinod Koul Reviewed-by: Dmitry Baryshkov Signed-off-by: Marijn Suijten Patchwork: https://patchwork.freedesktop.org/patch/508933/ Link: https://lore.kernel.org/r/20221026182824.876933-3-marijn.suijten@somainline.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/dsi/dsi_host.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 8026fe65bff6..d94832504d0f 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -842,7 +842,7 @@ static void dsi_ctrl_config(struct msm_dsi_host *msm_host, bool enable, static void dsi_update_dsc_timing(struct msm_dsi_host *msm_host, bool is_cmd_mode, u32 hdisplay) { struct drm_dsc_config *dsc = msm_host->dsc; - u32 reg, intf_width, reg_ctrl, reg_ctrl2; + u32 reg, reg_ctrl, reg_ctrl2; u32 slice_per_intf, total_bytes_per_intf; u32 pkt_per_line; u32 bytes_in_slice; @@ -851,8 +851,7 @@ static void dsi_update_dsc_timing(struct msm_dsi_host *msm_host, bool is_cmd_mod /* first calculate dsc parameters and then program * compress mode registers */ - intf_width = hdisplay; - slice_per_intf = DIV_ROUND_UP(intf_width, dsc->slice_width); + slice_per_intf = DIV_ROUND_UP(hdisplay, dsc->slice_width); /* If slice_per_pkt is greater than slice_per_intf * then default to 1. This can happen during partial @@ -861,7 +860,6 @@ static void dsi_update_dsc_timing(struct msm_dsi_host *msm_host, bool is_cmd_mod if (slice_per_intf > dsc->slice_count) dsc->slice_count = 1; - slice_per_intf = DIV_ROUND_UP(hdisplay, dsc->slice_width); bytes_in_slice = DIV_ROUND_UP(dsc->slice_width * dsc->bits_per_pixel, 8); dsc->slice_chunk_size = bytes_in_slice; -- cgit From 1e8196103bd02a396b45c8f6188541634a47fce2 Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Wed, 26 Oct 2022 20:28:17 +0200 Subject: drm/msm/dsi: Use DIV_ROUND_UP instead of conditional increment on modulo This exact same math is used to compute bytes_in_slice above in dsi_update_dsc_timing(), also used to fill slice_chunk_size. Fixes: b9080324d6ca ("drm/msm/dsi: add support for dsc data") Reviewed-by: Abhinav Kumar Reviewed-by: Dmitry Baryshkov Signed-off-by: Marijn Suijten Patchwork: https://patchwork.freedesktop.org/patch/508935/ Link: https://lore.kernel.org/r/20221026182824.876933-4-marijn.suijten@somainline.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/dsi/dsi_host.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index d94832504d0f..88c8aa5c6b80 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -1807,9 +1807,7 @@ static int dsi_populate_dsc_params(struct drm_dsc_config *dsc) * params are calculated */ groups_per_line = DIV_ROUND_UP(dsc->slice_width, 3); - dsc->slice_chunk_size = dsc->slice_width * dsc->bits_per_pixel / 8; - if ((dsc->slice_width * dsc->bits_per_pixel) % 8) - dsc->slice_chunk_size++; + dsc->slice_chunk_size = DIV_ROUND_UP(dsc->slice_width * dsc->bits_per_pixel, 8); /* rbs-min */ min_rate_buffer_size = dsc->rc_model_size - dsc->initial_offset + -- cgit From e443459e2e6b8e0d3187dd0d09ef7fcea87531d2 Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Wed, 26 Oct 2022 20:28:18 +0200 Subject: drm/msm/dsi: Reuse earlier computed dsc->slice_chunk_size dsi_populate_dsc_params() is called prior to dsi_update_dsc_timing() and already computes a value for slice_chunk_size, whose value doesn't need to be recomputed and re-set here. Fixes: 08802f515c3c ("drm/msm/dsi: Add support for DSC configuration") Reviewed-by: Abhinav Kumar Reviewed-by: Dmitry Baryshkov Signed-off-by: Marijn Suijten Patchwork: https://patchwork.freedesktop.org/patch/508934/ Link: https://lore.kernel.org/r/20221026182824.876933-5-marijn.suijten@somainline.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/dsi/dsi_host.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 88c8aa5c6b80..c3156e9066f5 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -845,7 +845,6 @@ static void dsi_update_dsc_timing(struct msm_dsi_host *msm_host, bool is_cmd_mod u32 reg, reg_ctrl, reg_ctrl2; u32 slice_per_intf, total_bytes_per_intf; u32 pkt_per_line; - u32 bytes_in_slice; u32 eol_byte_num; /* first calculate dsc parameters and then program @@ -860,11 +859,7 @@ static void dsi_update_dsc_timing(struct msm_dsi_host *msm_host, bool is_cmd_mod if (slice_per_intf > dsc->slice_count) dsc->slice_count = 1; - bytes_in_slice = DIV_ROUND_UP(dsc->slice_width * dsc->bits_per_pixel, 8); - - dsc->slice_chunk_size = bytes_in_slice; - - total_bytes_per_intf = bytes_in_slice * slice_per_intf; + total_bytes_per_intf = dsc->slice_chunk_size * slice_per_intf; eol_byte_num = total_bytes_per_intf % 3; pkt_per_line = slice_per_intf / dsc->slice_count; @@ -890,7 +885,7 @@ static void dsi_update_dsc_timing(struct msm_dsi_host *msm_host, bool is_cmd_mod reg_ctrl |= reg; reg_ctrl2 &= ~DSI_COMMAND_COMPRESSION_MODE_CTRL2_STREAM0_SLICE_WIDTH__MASK; - reg_ctrl2 |= DSI_COMMAND_COMPRESSION_MODE_CTRL2_STREAM0_SLICE_WIDTH(bytes_in_slice); + reg_ctrl2 |= DSI_COMMAND_COMPRESSION_MODE_CTRL2_STREAM0_SLICE_WIDTH(dsc->slice_chunk_size); dsi_write(msm_host, REG_DSI_COMMAND_COMPRESSION_MODE_CTRL, reg_ctrl); dsi_write(msm_host, REG_DSI_COMMAND_COMPRESSION_MODE_CTRL2, reg_ctrl2); -- cgit From 0ca870ca304d3449b2ccdc3f0bad9843ff1519f0 Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Wed, 26 Oct 2022 20:28:19 +0200 Subject: drm/msm/dsi: Appropriately set dsc->mux_word_size based on bpc This field is currently unread but will come into effect when duplicated code below is migrated to call drm_dsc_compute_rc_parameters(), which uses the bpc-dependent value of the local variable mux_words_size in much the same way. The hardcoded constant seems to be a remnant from the `/* bpc 8 */` comment right above, indicating that this group of field assignments is applicable to bpc = 8 exclusively and should probably bail out on different bpc values, until constants for other bpc values are added (or the current ones are confirmed to be correct across multiple bpc's). Fixes: b9080324d6ca ("drm/msm/dsi: add support for dsc data") Reviewed-by: Abhinav Kumar Reviewed-by: Dmitry Baryshkov Signed-off-by: Marijn Suijten Patchwork: https://patchwork.freedesktop.org/patch/508943/ Link: https://lore.kernel.org/r/20221026182824.876933-6-marijn.suijten@somainline.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/dsi/dsi_host.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index c3156e9066f5..906ee38133c1 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -1786,6 +1786,7 @@ static int dsi_populate_dsc_params(struct drm_dsc_config *dsc) if (dsc->bits_per_component == 12) mux_words_size = 64; + dsc->mux_word_size = mux_words_size; dsc->initial_xmit_delay = 512; dsc->initial_scale_value = 32; dsc->first_line_bpg_offset = 12; @@ -1796,7 +1797,6 @@ static int dsi_populate_dsc_params(struct drm_dsc_config *dsc) dsc->flatness_max_qp = 12; dsc->rc_quant_incr_limit0 = 11; dsc->rc_quant_incr_limit1 = 11; - dsc->mux_word_size = DSC_MUX_WORD_SIZE_8_10_BPC; /* FIXME: need to call drm_dsc_compute_rc_parameters() so that rest of * params are calculated -- cgit From c3a1aabce2d4087255de90100c3dad492e7d925c Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Wed, 26 Oct 2022 20:28:20 +0200 Subject: drm/msm/dsi: Migrate to drm_dsc_compute_rc_parameters() As per the FIXME this code is entirely duplicate with what is already provided inside drm_dsc_compute_rc_parameters(), supposedly because that function was yielding "incorrect" results while in reality the panel driver(s?) used for testing were providing incorrect parameters. For example, this code from downstream assumed dsc->bits_per_pixel to contain an integer value, whereas the upstream drm_dsc_config struct stores it with 4 fractional bits. drm_dsc_compute_rc_parameters() already accounts for this feat while the panel driver used for testing [1] wasn't, hence making drm_dsc_compute_rc_parameters() seem like it was returning an incorrect result. Other users of dsc->bits_per_pixel inside dsi_populate_dsc_params() also treat it in the same erroneous way, and will be addressed in a separate patch. In the end, using drm_dsc_compute_rc_parameters() spares both a lot of duplicate code and erratic behaviour. [1]: https://git.linaro.org/people/vinod.koul/kernel.git/commit/?h=topic/pixel3_5.18-rc1&id=1d7d98ad564f1ec69e7525e07418918d90f247a1 Fixes: b9080324d6ca ("drm/msm/dsi: add support for dsc data") Reviewed-by: Abhinav Kumar Signed-off-by: Marijn Suijten Reviewed-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/508939/ Link: https://lore.kernel.org/r/20221026182824.876933-7-marijn.suijten@somainline.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/dsi/dsi_host.c | 64 ++++---------------------------------- 1 file changed, 6 insertions(+), 58 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 906ee38133c1..36d42f17331d 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -21,6 +21,7 @@ #include