From 39c21b81112321cbe1267b02c77ecd2161ce19aa Mon Sep 17 00:00:00 2001 From: YuBiao Wang Date: Wed, 12 Nov 2025 15:16:27 +0800 Subject: [PATCH 01/69] drm/amdgpu: Skip loading SDMA_RS64 in VF VFs use the PF SDMA ucode and are unable to load SDMA_RS64. Signed-off-by: YuBiao Wang Signed-off-by: Victor Skvortsov Reviewed-by: Gavin Wan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c index f8eac92a2b36..f01f38509108 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c @@ -1262,6 +1262,7 @@ bool amdgpu_virt_fw_load_skip_check(struct amdgpu_device *adev, uint32_t ucode_i || ucode_id == AMDGPU_UCODE_ID_SDMA5 || ucode_id == AMDGPU_UCODE_ID_SDMA6 || ucode_id == AMDGPU_UCODE_ID_SDMA7 + || ucode_id == AMDGPU_UCODE_ID_SDMA_RS64 || ucode_id == AMDGPU_UCODE_ID_RLC_G || ucode_id == AMDGPU_UCODE_ID_RLC_RESTORE_LIST_CNTL || ucode_id == AMDGPU_UCODE_ID_RLC_RESTORE_LIST_GPM_MEM From ca5d4db8db843be7ed35fc9334737490c2b58d32 Mon Sep 17 00:00:00 2001 From: Xiaogang Chen Date: Thu, 8 Jan 2026 09:50:36 -0600 Subject: [PATCH 02/69] drm/amdgpu: Use correct address to setup gart page table for vram access Use dst input parameter to setup gart page table entries instead of using fixed location. Fixes: 237d623ae659 ("drm/amdgpu/gart: Add helper to bind VRAM pages (v2)") Signed-off-by: Xiaogang Chen Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c index 16c3b78e50cb..ec911dce345f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c @@ -375,7 +375,7 @@ void amdgpu_gart_map(struct amdgpu_device *adev, uint64_t offset, * @start_page: first page to map in the GART aperture * @num_pages: number of pages to be mapped * @flags: page table entry flags - * @dst: CPU address of the GART table + * @dst: valid CPU address of GART table, cannot be null * * Binds a BO that is allocated in VRAM to the GART page table * (all ASICs). @@ -396,7 +396,7 @@ void amdgpu_gart_map_vram_range(struct amdgpu_device *adev, uint64_t pa, return; for (i = 0; i < num_pages; ++i) { - amdgpu_gmc_set_pte_pde(adev, adev->gart.ptr, + amdgpu_gmc_set_pte_pde(adev, dst, start_page + i, pa + AMDGPU_GPU_PAGE_SIZE * i, flags); } From 4f379370a49ccb747d8d87f2d8ee9bba965e1897 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Tue, 16 Dec 2025 11:20:54 +0530 Subject: [PATCH 03/69] drm/amd/pm: Add smu message control block Add message control block to abstract PMFW message protocol. Message control block primarily carries message config which is set of register addresses and message ops which abstracts the protocol of sending messages. Signed-off-by: Lijo Lazar Reviewed-by: Asad Kamal Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 70 ++++ drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 359 ++++++++++++++++++ drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h | 4 + 3 files changed, 433 insertions(+) diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h index 99dd0f4d399a..842ae201a8ca 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h @@ -551,6 +551,73 @@ struct cmn2asic_mapping { int map_to; }; +#define SMU_MSG_MAX_ARGS 4 + +/* Message flags for smu_msg_args */ +#define SMU_MSG_FLAG_NO_WAIT BIT(0) /* Skip post-poll (for split send/wait) */ + +struct smu_msg_ctl; +/** + * struct smu_msg_config - IP-level register configuration + * @msg_reg: Message register offset + * @resp_reg: Response register offset + * @arg_regs: Argument register offsets (up to SMU_MSG_MAX_ARGS) + * @num_arg_regs: Number of argument registers available + */ +struct smu_msg_config { + u32 msg_reg; + u32 resp_reg; + u32 arg_regs[SMU_MSG_MAX_ARGS]; + int num_arg_regs; +}; + +/** + * struct smu_msg_args - Per-call message arguments + * @msg: Common message type (enum smu_message_type) + * @args: Input arguments + * @num_args: Number of input arguments + * @out_args: Output arguments (filled after successful send) + * @num_out_args: Number of output arguments to read + * @flags: Message flags (SMU_MSG_FLAG_*) + * @timeout: Per-message timeout in us (0 = use default) + */ +struct smu_msg_args { + enum smu_message_type msg; + u32 args[SMU_MSG_MAX_ARGS]; + int num_args; + u32 out_args[SMU_MSG_MAX_ARGS]; + int num_out_args; + u32 flags; + u32 timeout; +}; + +/** + * struct smu_msg_ops - IP-level protocol operations + * @send_msg: send message protocol + * @wait_response: wait for response (for split send/wait cases) + * @decode_response: Convert response register value to errno + */ +struct smu_msg_ops { + int (*send_msg)(struct smu_msg_ctl *ctl, struct smu_msg_args *args); + int (*wait_response)(struct smu_msg_ctl *ctl, u32 timeout_us); + int (*decode_response)(u32 resp); +}; + +/** + * struct smu_msg_ctl - Per-device message control block + * This is a standalone control block that encapsulates everything + * needed for SMU messaging. The ops->send_msg implements the complete + * protocol including all filtering and error handling. + */ +struct smu_msg_ctl { + struct smu_context *smu; + struct mutex lock; + struct smu_msg_config config; + const struct smu_msg_ops *ops; + const struct cmn2asic_msg_mapping *message_map; + u32 default_timeout; +}; + struct stb_context { uint32_t stb_buf_size; bool enabled; @@ -691,6 +758,9 @@ struct smu_context { bool wbrf_supported; struct notifier_block wbrf_notifier; struct delayed_work wbrf_delayed_work; + + /* SMU message control block */ + struct smu_msg_ctl msg_ctl; }; struct i2c_adapter; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c index ef5aa4e42a17..de4b7f423a76 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c @@ -53,6 +53,9 @@ static const char * const __smu_message_names[] = { -ENOTSUPP) : \ -EINVAL) +#define SMU_MSG_V1_DEFAULT_RATELIMIT_INTERVAL (5 * HZ) +#define SMU_MSG_V1_DEFAULT_RATELIMIT_BURST 10 + static const char *smu_get_message_name(struct smu_context *smu, enum smu_message_type type) { @@ -515,6 +518,362 @@ int smu_cmn_send_debug_smc_msg_with_param(struct smu_context *smu, return __smu_cmn_send_debug_msg(smu, msg, param); } +static int smu_msg_v1_decode_response(u32 resp) +{ + int res; + + switch (resp) { + case SMU_RESP_NONE: + /* The SMU is busy--still executing your command. + */ + res = -ETIME; + break; + case SMU_RESP_OK: + res = 0; + break; + case SMU_RESP_CMD_FAIL: + /* Command completed successfully, but the command + * status was failure. + */ + res = -EIO; + break; + case SMU_RESP_CMD_UNKNOWN: + /* Unknown command--ignored by the SMU. + */ + res = -EOPNOTSUPP; + break; + case SMU_RESP_CMD_BAD_PREREQ: + /* Valid command--bad prerequisites. + */ + res = -EINVAL; + break; + case SMU_RESP_BUSY_OTHER: + /* The SMU is busy with other commands. The client + * should retry in 10 us. + */ + res = -EBUSY; + break; + default: + /* Unknown or debug response from the SMU. + */ + res = -EREMOTEIO; + break; + } + + return res; +} + +static u32 __smu_msg_v1_poll_stat(struct smu_msg_ctl *ctl, u32 timeout_us) +{ + struct amdgpu_device *adev = ctl->smu->adev; + struct smu_msg_config *cfg = &ctl->config; + u32 timeout = timeout_us ? timeout_us : ctl->default_timeout; + u32 reg; + + for (; timeout > 0; timeout--) { + reg = RREG32(cfg->resp_reg); + if ((reg & MP1_C2PMSG_90__CONTENT_MASK) != 0) + break; + udelay(1); + } + + return reg; +} + +static void __smu_msg_v1_send(struct smu_msg_ctl *ctl, u16 index, + struct smu_msg_args *args) +{ + struct amdgpu_device *adev = ctl->smu->adev; + struct smu_msg_config *cfg = &ctl->config; + int i; + + WREG32(cfg->resp_reg, 0); + for (i = 0; i < args->num_args; i++) + WREG32(cfg->arg_regs[i], args->args[i]); + WREG32(cfg->msg_reg, index); +} + +static void __smu_msg_v1_read_out_args(struct smu_msg_ctl *ctl, + struct smu_msg_args *args) +{ + struct amdgpu_device *adev = ctl->smu->adev; + int i; + + for (i = 0; i < args->num_out_args; i++) + args->out_args[i] = RREG32(ctl->config.arg_regs[i]); +} + +static void __smu_msg_v1_print_err_limited(struct smu_msg_ctl *ctl, + struct smu_msg_args *args, + char *err_msg) +{ + static DEFINE_RATELIMIT_STATE(_rs, + SMU_MSG_V1_DEFAULT_RATELIMIT_INTERVAL, + SMU_MSG_V1_DEFAULT_RATELIMIT_BURST); + struct smu_context *smu = ctl->smu; + struct amdgpu_device *adev = smu->adev; + + if (__ratelimit(&_rs)) { + u32 in[SMU_MSG_MAX_ARGS]; + int i; + + dev_err(adev->dev, "%s msg_reg: %x resp_reg: %x", err_msg, + RREG32(ctl->config.msg_reg), + RREG32(ctl->config.resp_reg)); + if (args->num_args > 0) { + for (i = 0; i < args->num_args; i++) + in[i] = RREG32(ctl->config.arg_regs[i]); + print_hex_dump(KERN_ERR, "in params:", DUMP_PREFIX_NONE, + 16, 4, in, args->num_args * sizeof(u32), + false); + } + } +} + +static void __smu_msg_v1_print_error(struct smu_msg_ctl *ctl, + u32 resp, + struct smu_msg_args *args) +{ + struct smu_context *smu = ctl->smu; + struct amdgpu_device *adev = smu->adev; + int index = ctl->message_map[args->msg].map_to; + + switch (resp) { + case SMU_RESP_NONE: + __smu_msg_v1_print_err_limited(ctl, args, "SMU: No response"); + break; + case SMU_RESP_OK: + break; + case SMU_RESP_CMD_FAIL: + break; + case SMU_RESP_CMD_UNKNOWN: + __smu_msg_v1_print_err_limited(ctl, args, + "SMU: unknown command"); + break; + case SMU_RESP_CMD_BAD_PREREQ: + __smu_msg_v1_print_err_limited( + ctl, args, "SMU: valid command, bad prerequisites"); + break; + case SMU_RESP_BUSY_OTHER: + if (args->msg != SMU_MSG_GetBadPageCount) + __smu_msg_v1_print_err_limited(ctl, args, + "SMU: I'm very busy"); + break; + case SMU_RESP_DEBUG_END: + __smu_msg_v1_print_err_limited(ctl, args, "SMU: Debug Err"); + break; + case SMU_RESP_UNEXP: + if (amdgpu_device_bus_status_check(adev)) { + dev_err(adev->dev, + "SMU: bus error for message: %s(%d) response:0x%08X ", + smu_get_message_name(smu, args->msg), index, + resp); + if (args->num_args > 0) + print_hex_dump(KERN_ERR, + "in params:", DUMP_PREFIX_NONE, + 16, 4, args->args, + args->num_args * sizeof(u32), + false); + } + break; + default: + __smu_msg_v1_print_err_limited(ctl, args, + "SMU: unknown response"); + break; + } +} + +static int __smu_msg_v1_ras_filter(struct smu_msg_ctl *ctl, + enum smu_message_type msg, u32 msg_flags, + bool *skip_pre_poll) +{ + struct smu_context *smu = ctl->smu; + struct amdgpu_device *adev = smu->adev; + bool fed_status; + u32 reg; + + if (!(smu->smc_fw_caps & SMU_FW_CAP_RAS_PRI)) + return 0; + + fed_status = amdgpu_ras_get_fed_status(adev); + + /* Block non-RAS-priority messages during RAS error */ + if (fed_status && !(msg_flags & SMU_MSG_RAS_PRI)) { + dev_dbg(adev->dev, "RAS error detected, skip sending %s", + smu_get_message_name(smu, msg)); + return -EACCES; + } + + /* Skip pre-poll for priority messages or during RAS error */ + if ((msg_flags & SMU_MSG_NO_PRECHECK) || fed_status) { + reg = RREG32(ctl->config.resp_reg); + dev_dbg(adev->dev, + "Sending priority message %s response status: %x", + smu_get_message_name(smu, msg), reg); + if (reg == 0) + *skip_pre_poll = true; + } + + return 0; +} + +/** + * smu_msg_proto_v1_send_msg - Complete V1 protocol with all filtering + * @ctl: Message control block + * @args: Message arguments + * + * Return: 0 on success, negative errno on failure + */ +static int smu_msg_v1_send_msg(struct smu_msg_ctl *ctl, + struct smu_msg_args *args) +{ + struct smu_context *smu = ctl->smu; + struct amdgpu_device *adev = smu->adev; + const struct cmn2asic_msg_mapping *mapping; + u32 reg, msg_flags; + int ret, index; + bool skip_pre_poll = false; + + /* Early exit if no HW access */ + if (adev->no_hw_access) + return 0; + + /* Message index translation */ + if (args->msg >= SMU_MSG_MAX_COUNT || !ctl->message_map) + return -EINVAL; + + if (args->num_args > ctl->config.num_arg_regs || + args->num_out_args > ctl->config.num_arg_regs) + return -EINVAL; + + mapping = &ctl->message_map[args->msg]; + if (!mapping->valid_mapping) + return -EINVAL; + + msg_flags = mapping->flags; + index = mapping->map_to; + + /* VF filter - skip messages not valid for VF */ + if (amdgpu_sriov_vf(adev) && !(msg_flags & SMU_MSG_VF_FLAG)) + return 0; + + mutex_lock(&ctl->lock); + + /* RAS priority filter */ + ret = __smu_msg_v1_ras_filter(ctl, args->msg, msg_flags, + &skip_pre_poll); + if (ret) + goto out; + + /* FW state checks */ + if (smu->smc_fw_state == SMU_FW_HANG) { + dev_err(adev->dev, + "SMU is in hanged state, failed to send smu message!\n"); + ret = -EREMOTEIO; + goto out; + } else if (smu->smc_fw_state == SMU_FW_INIT) { + skip_pre_poll = true; + smu->smc_fw_state = SMU_FW_RUNTIME; + } + + /* Pre-poll: ensure previous message completed */ + if (!skip_pre_poll) { + reg = __smu_msg_v1_poll_stat(ctl, args->timeout); + ret = smu_msg_v1_decode_response(reg); + if (reg == SMU_RESP_NONE || ret == -EREMOTEIO) { + __smu_msg_v1_print_error(ctl, reg, args); + goto out; + } + } + + /* Send message */ + __smu_msg_v1_send(ctl, (u16)index, args); + + /* Post-poll (skip if NO_WAIT) */ + if (args->flags & SMU_MSG_FLAG_NO_WAIT) { + ret = 0; + goto out; + } + + reg = __smu_msg_v1_poll_stat(ctl, args->timeout); + ret = smu_msg_v1_decode_response(reg); + + /* FW state update on fatal error */ + if (ret == -EREMOTEIO) { + smu->smc_fw_state = SMU_FW_HANG; + __smu_msg_v1_print_error(ctl, reg, args); + } else if (ret != 0) { + __smu_msg_v1_print_error(ctl, reg, args); + } + + /* Read output args */ + if (ret == 0 && args->num_out_args > 0) { + __smu_msg_v1_read_out_args(ctl, args); + dev_dbg(adev->dev, "smu send message: %s(%d) resp : 0x%08x", + smu_get_message_name(smu, args->msg), index, reg); + if (args->num_args > 0) + print_hex_dump_debug("in params:", DUMP_PREFIX_NONE, 16, + 4, args->args, + args->num_args * sizeof(u32), + false); + print_hex_dump_debug("out params:", DUMP_PREFIX_NONE, 16, 4, + args->out_args, + args->num_out_args * sizeof(u32), false); + } else { + dev_dbg(adev->dev, "smu send message: %s(%d), resp: 0x%08x\n", + smu_get_message_name(smu, args->msg), index, reg); + if (args->num_args > 0) + print_hex_dump_debug("in params:", DUMP_PREFIX_NONE, 16, + 4, args->args, + args->num_args * sizeof(u32), + false); + } + +out: + /* Debug halt on error */ + if (unlikely(adev->pm.smu_debug_mask & SMU_DEBUG_HALT_ON_ERROR) && + ret) { + amdgpu_device_halt(adev); + WARN_ON(1); + } + + mutex_unlock(&ctl->lock); + return ret; +} + +static int smu_msg_v1_wait_response(struct smu_msg_ctl *ctl, u32 timeout_us) +{ + struct smu_context *smu = ctl->smu; + struct amdgpu_device *adev = smu->adev; + u32 reg; + int ret; + + reg = __smu_msg_v1_poll_stat(ctl, timeout_us); + ret = smu_msg_v1_decode_response(reg); + + if (ret == -EREMOTEIO) + smu->smc_fw_state = SMU_FW_HANG; + + if (unlikely(adev->pm.smu_debug_mask & SMU_DEBUG_HALT_ON_ERROR) && + ret && (ret != -ETIME)) { + amdgpu_device_halt(adev); + WARN_ON(1); + } + + return ret; +} + +const struct smu_msg_ops smu_msg_v1_ops = { + .send_msg = smu_msg_v1_send_msg, + .wait_response = smu_msg_v1_wait_response, + .decode_response = smu_msg_v1_decode_response, +}; + +int smu_msg_wait_response(struct smu_msg_ctl *ctl, u32 timeout_us) +{ + return ctl->ops->wait_response(ctl, timeout_us); +} + int smu_cmn_to_asic_specific_index(struct smu_context *smu, enum smu_cmn2asic_mapping_type type, uint32_t index) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h index 3a8d05afa654..d9a37ed4e720 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h @@ -25,6 +25,10 @@ #include "amdgpu_smu.h" +extern const struct smu_msg_ops smu_msg_v1_ops; + +int smu_msg_wait_response(struct smu_msg_ctl *ctl, u32 timeout_us); + #if defined(SWSMU_CODE_LAYER_L2) || defined(SWSMU_CODE_LAYER_L3) || defined(SWSMU_CODE_LAYER_L4) #define FDO_PWM_MODE_STATIC 1 From 6d74c9ff6ae5d246d601f855aab234b1cbaf4e15 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Tue, 6 Jan 2026 13:29:25 +0530 Subject: [PATCH 04/69] drm/amd/pm: Add message control for SMUv11 Initialize smu message control in SMUv11 SOCs. Signed-off-by: Lijo Lazar Reviewed-by: Asad Kamal Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h | 2 ++ .../gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 1 + .../drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c | 1 + drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 1 + .../drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 1 + drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c | 17 +++++++++++++++++ .../gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 1 + 7 files changed, 24 insertions(+) diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h index d18934c6fbd5..97c19005952c 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h @@ -283,6 +283,8 @@ int smu_v11_0_handle_passthrough_sbr(struct smu_context *smu, bool enable); int smu_v11_0_restore_user_od_settings(struct smu_context *smu); void smu_v11_0_set_smu_mailbox_registers(struct smu_context *smu); +void smu_v11_0_init_msg_ctl(struct smu_context *smu, + const struct cmn2asic_msg_mapping *message_map); #endif #endif 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 81241976b53c..eadd81e413aa 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c @@ -1966,4 +1966,5 @@ void arcturus_set_ppt_funcs(struct smu_context *smu) smu->pwr_src_map = arcturus_pwr_src_map; smu->workload_map = arcturus_workload_map; smu_v11_0_set_smu_mailbox_registers(smu); + smu_v11_0_init_msg_ctl(smu, arcturus_message_map); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c index 51f0e299b840..5ae6ee87de04 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c @@ -605,4 +605,5 @@ void cyan_skillfish_set_ppt_funcs(struct smu_context *smu) smu->table_map = cyan_skillfish_table_map; smu->is_apu = true; smu_v11_0_set_smu_mailbox_registers(smu); + smu_v11_0_init_msg_ctl(smu, cyan_skillfish_message_map); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c index 74f24618485a..3596cb7f8adf 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c @@ -3376,4 +3376,5 @@ void navi10_set_ppt_funcs(struct smu_context *smu) smu->pwr_src_map = navi10_pwr_src_map; smu->workload_map = navi10_workload_map; smu_v11_0_set_smu_mailbox_registers(smu); + smu_v11_0_init_msg_ctl(smu, navi10_message_map); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c index 3f3947dc52a9..9ea6b0d1954b 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c @@ -3189,4 +3189,5 @@ void sienna_cichlid_set_ppt_funcs(struct smu_context *smu) smu->pwr_src_map = sienna_cichlid_pwr_src_map; smu->workload_map = sienna_cichlid_workload_map; smu_v11_0_set_smu_mailbox_registers(smu); + smu_v11_0_init_msg_ctl(smu, sienna_cichlid_message_map); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c index 3d03010abcc1..579b1dbd36ac 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c @@ -2176,3 +2176,20 @@ void smu_v11_0_set_smu_mailbox_registers(struct smu_context *smu) smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66); smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); } + +void smu_v11_0_init_msg_ctl(struct smu_context *smu, + const struct cmn2asic_msg_mapping *message_map) +{ + struct amdgpu_device *adev = smu->adev; + struct smu_msg_ctl *ctl = &smu->msg_ctl; + + ctl->smu = smu; + mutex_init(&ctl->lock); + ctl->config.msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66); + ctl->config.resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); + ctl->config.arg_regs[0] = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82); + ctl->config.num_arg_regs = 1; + ctl->ops = &smu_msg_v1_ops; + ctl->default_timeout = adev->usec_timeout * 20; + ctl->message_map = message_map; +} diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c index 65a0302ce875..a645094b029b 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c @@ -2569,4 +2569,5 @@ void vangogh_set_ppt_funcs(struct smu_context *smu) smu->workload_map = vangogh_workload_map; smu->is_apu = true; smu_v11_0_set_smu_mailbox_registers(smu); + smu_v11_0_init_msg_ctl(smu, vangogh_message_map); } From 067e46a36bfc6897ebb0bd8a7f50ed98ca068ef2 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Tue, 16 Dec 2025 11:37:11 +0530 Subject: [PATCH 05/69] drm/amd/pm: Add message control for SMUv12 Initialize smu message control in SMUv12 SOCs. Signed-off-by: Lijo Lazar Reviewed-by: Asad Kamal Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/inc/smu_v12_0.h | 3 +++ drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c | 1 + drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c | 17 +++++++++++++++++ 3 files changed, 21 insertions(+) diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v12_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v12_0.h index 0886d8cffbd0..fd3937b08662 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v12_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v12_0.h @@ -62,5 +62,8 @@ int smu_v12_0_set_driver_table_location(struct smu_context *smu); int smu_v12_0_get_vbios_bootup_values(struct smu_context *smu); +void smu_v12_0_init_msg_ctl(struct smu_context *smu, + const struct cmn2asic_msg_mapping *message_map); + #endif #endif diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c index c72ddef3fce5..7e41991f140e 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c @@ -1507,4 +1507,5 @@ void renoir_set_ppt_funcs(struct smu_context *smu) smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82); smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66); smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); + smu_v12_0_init_msg_ctl(smu, renoir_message_map); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c index 942bc3b0f700..2c20624caca4 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c @@ -405,3 +405,20 @@ int smu_v12_0_get_vbios_bootup_values(struct smu_context *smu) return 0; } + +void smu_v12_0_init_msg_ctl(struct smu_context *smu, + const struct cmn2asic_msg_mapping *message_map) +{ + struct amdgpu_device *adev = smu->adev; + struct smu_msg_ctl *ctl = &smu->msg_ctl; + + ctl->smu = smu; + mutex_init(&ctl->lock); + ctl->config.msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66); + ctl->config.resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); + ctl->config.arg_regs[0] = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82); + ctl->config.num_arg_regs = 1; + ctl->ops = &smu_msg_v1_ops; + ctl->default_timeout = adev->usec_timeout * 20; + ctl->message_map = message_map; +} From 667912bbabc2044e00eecf7d0b5e00ad81ac2dfa Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Tue, 16 Dec 2025 12:03:09 +0530 Subject: [PATCH 06/69] drm/amd/pm: Add message control for SMUv13 Initialize smu message control in SMUv13 SOCs. Signed-off-by: Lijo Lazar Reviewed-by: Asad Kamal Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h | 2 ++ .../drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 1 + .../gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c | 17 ++++++++++++++ .../drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 1 + .../drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c | 23 +++++++++++++++++-- .../drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c | 17 ++++++++++++++ .../drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c | 1 + .../drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 1 + .../drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c | 1 + 9 files changed, 62 insertions(+), 2 deletions(-) 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 c35cbb2aee93..fabf61e15dba 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 @@ -252,6 +252,8 @@ int smu_v13_0_od_edit_dpm_table(struct smu_context *smu, int smu_v13_0_set_default_dpm_tables(struct smu_context *smu); void smu_v13_0_set_smu_mailbox_registers(struct smu_context *smu); +void smu_v13_0_init_msg_ctl(struct smu_context *smu, + const struct cmn2asic_msg_mapping *message_map); int smu_v13_0_mode1_reset(struct smu_context *smu); 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 e999ee7d053e..a3f4b25ac474 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -2038,4 +2038,5 @@ void aldebaran_set_ppt_funcs(struct smu_context *smu) smu->table_map = aldebaran_table_map; smu->smc_driver_if_version = SMU13_DRIVER_IF_VERSION_ALDE; smu_v13_0_set_smu_mailbox_registers(smu); + smu_v13_0_init_msg_ctl(smu, aldebaran_message_map); } 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 bf00ed3f2848..e5996162fd5c 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 @@ -2357,6 +2357,23 @@ void smu_v13_0_set_smu_mailbox_registers(struct smu_context *smu) smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); } +void smu_v13_0_init_msg_ctl(struct smu_context *smu, + const struct cmn2asic_msg_mapping *message_map) +{ + struct amdgpu_device *adev = smu->adev; + struct smu_msg_ctl *ctl = &smu->msg_ctl; + + ctl->smu = smu; + mutex_init(&ctl->lock); + ctl->config.msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66); + ctl->config.resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); + ctl->config.arg_regs[0] = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82); + ctl->config.num_arg_regs = 1; + ctl->ops = &smu_msg_v1_ops; + ctl->default_timeout = adev->usec_timeout * 20; + ctl->message_map = message_map; +} + int smu_v13_0_mode1_reset(struct smu_context *smu) { int ret = 0; 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 91442e39aa79..128fb68abf70 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 @@ -3231,6 +3231,7 @@ void smu_v13_0_0_set_ppt_funcs(struct smu_context *smu) smu->workload_map = smu_v13_0_0_workload_map; smu->smc_driver_if_version = SMU13_0_0_DRIVER_IF_VERSION; smu_v13_0_0_set_smu_mailbox_registers(smu); + smu_v13_0_init_msg_ctl(smu, smu_v13_0_0_message_map); if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 10) && diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c index 4a99f585f071..d8ef38535fe8 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c @@ -1133,6 +1133,22 @@ static void smu_v13_0_4_set_smu_mailbox_registers(struct smu_context *smu) smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); } +static void smu_v13_0_4_init_msg_ctl(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + struct smu_msg_ctl *ctl = &smu->msg_ctl; + + ctl->smu = smu; + mutex_init(&ctl->lock); + ctl->config.msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66); + ctl->config.resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); + ctl->config.arg_regs[0] = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82); + ctl->config.num_arg_regs = 1; + ctl->ops = &smu_msg_v1_ops; + ctl->default_timeout = adev->usec_timeout * 20; + ctl->message_map = smu_v13_0_4_message_map; +} + void smu_v13_0_4_set_ppt_funcs(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; @@ -1144,8 +1160,11 @@ void smu_v13_0_4_set_ppt_funcs(struct smu_context *smu) smu->smc_driver_if_version = SMU13_0_4_DRIVER_IF_VERSION; smu->is_apu = true; - if (amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 4)) + if (amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 4)) { smu_v13_0_4_set_smu_mailbox_registers(smu); - else + smu_v13_0_4_init_msg_ctl(smu); + } else { smu_v13_0_set_smu_mailbox_registers(smu); + smu_v13_0_init_msg_ctl(smu, smu_v13_0_4_message_map); + } } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c index f2e3c80ee203..f351880a5e97 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c @@ -1126,6 +1126,22 @@ static const struct pptable_funcs smu_v13_0_5_ppt_funcs = { .set_fine_grain_gfx_freq_parameters = smu_v13_0_5_set_fine_grain_gfx_freq_parameters, }; +static void smu_v13_0_5_init_msg_ctl(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + struct smu_msg_ctl *ctl = &smu->msg_ctl; + + ctl->smu = smu; + mutex_init(&ctl->lock); + ctl->config.msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_C2PMSG_2); + ctl->config.resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_C2PMSG_33); + ctl->config.arg_regs[0] = SOC15_REG_OFFSET(MP1, 0, mmMP1_C2PMSG_34); + ctl->config.num_arg_regs = 1; + ctl->ops = &smu_msg_v1_ops; + ctl->default_timeout = adev->usec_timeout * 20; + ctl->message_map = smu_v13_0_5_message_map; +} + void smu_v13_0_5_set_ppt_funcs(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; @@ -1139,4 +1155,5 @@ void smu_v13_0_5_set_ppt_funcs(struct smu_context *smu) smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_C2PMSG_34); smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_C2PMSG_2); smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_C2PMSG_33); + smu_v13_0_5_init_msg_ctl(smu); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c index 2c16da1065c8..a9789f3a23b0 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c @@ -3911,6 +3911,7 @@ void smu_v13_0_6_set_ppt_funcs(struct smu_context *smu) smu->smc_driver_if_version = SMU_IGNORE_IF_VERSION; smu->smc_fw_caps |= SMU_FW_CAP_RAS_PRI; smu_v13_0_set_smu_mailbox_registers(smu); + smu_v13_0_init_msg_ctl(smu, smu->message_map); smu_v13_0_6_set_temp_funcs(smu); amdgpu_mca_smu_init_funcs(smu->adev, &smu_v13_0_6_mca_smu_funcs); amdgpu_aca_set_smu_funcs(smu->adev, &smu_v13_0_6_aca_smu_funcs); 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 26f4e0383ace..d8f2059a1631 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 @@ -2817,4 +2817,5 @@ void smu_v13_0_7_set_ppt_funcs(struct smu_context *smu) smu->workload_map = smu_v13_0_7_workload_map; smu->smc_driver_if_version = SMU13_0_7_DRIVER_IF_VERSION; smu_v13_0_set_smu_mailbox_registers(smu); + smu_v13_0_init_msg_ctl(smu, smu_v13_0_7_message_map); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c index 358fe97ceea3..79ec2d235a09 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c @@ -1366,4 +1366,5 @@ void yellow_carp_set_ppt_funcs(struct smu_context *smu) smu->is_apu = true; smu->smc_driver_if_version = SMU13_YELLOW_CARP_DRIVER_IF_VERSION; smu_v13_0_set_smu_mailbox_registers(smu); + smu_v13_0_init_msg_ctl(smu, yellow_carp_message_map); } From 0d81c3982d32e4572fc91d5b8aca9e1a808a1820 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Tue, 16 Dec 2025 12:06:04 +0530 Subject: [PATCH 07/69] drm/amd/pm: Add message control for SMUv14 Initialize smu message control in SMUv14 SOCs. Signed-off-by: Lijo Lazar Reviewed-by: Asad Kamal Signed-off-by: Alex Deucher --- .../drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c | 17 +++++++++++++++++ .../drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c | 17 +++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c index ba895ca4f3e6..9c15fccac2b8 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c @@ -1740,6 +1740,22 @@ static void smu_v14_0_0_set_smu_mailbox_registers(struct smu_context *smu) smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); } +static void smu_v14_0_0_init_msg_ctl(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + struct smu_msg_ctl *ctl = &smu->msg_ctl; + + ctl->smu = smu; + mutex_init(&ctl->lock); + ctl->config.msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66); + ctl->config.resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); + ctl->config.arg_regs[0] = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82); + ctl->config.num_arg_regs = 1; + ctl->ops = &smu_msg_v1_ops; + ctl->default_timeout = adev->usec_timeout * 20; + ctl->message_map = smu_v14_0_0_message_map; +} + void smu_v14_0_0_set_ppt_funcs(struct smu_context *smu) { @@ -1750,4 +1766,5 @@ void smu_v14_0_0_set_ppt_funcs(struct smu_context *smu) smu->is_apu = true; smu_v14_0_0_set_smu_mailbox_registers(smu); + smu_v14_0_0_init_msg_ctl(smu); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c index b1fee26d989a..5bf10555effd 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c @@ -2120,6 +2120,22 @@ static void smu_v14_0_2_set_smu_mailbox_registers(struct smu_context *smu) smu->debug_resp_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_54); } +static void smu_v14_0_2_init_msg_ctl(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + struct smu_msg_ctl *ctl = &smu->msg_ctl; + + ctl->smu = smu; + mutex_init(&ctl->lock); + ctl->config.msg_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_66); + ctl->config.resp_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_90); + ctl->config.arg_regs[0] = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_82); + ctl->config.num_arg_regs = 1; + ctl->ops = &smu_msg_v1_ops; + ctl->default_timeout = adev->usec_timeout * 20; + ctl->message_map = smu_v14_0_2_message_map; +} + static ssize_t smu_v14_0_2_get_gpu_metrics(struct smu_context *smu, void **table) { @@ -2866,4 +2882,5 @@ void smu_v14_0_2_set_ppt_funcs(struct smu_context *smu) smu->pwr_src_map = smu_v14_0_2_pwr_src_map; smu->workload_map = smu_v14_0_2_workload_map; smu_v14_0_2_set_smu_mailbox_registers(smu); + smu_v14_0_2_init_msg_ctl(smu); } From 34199fde4a8604d9d3ad2d939c5eed530460cc79 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Thu, 8 Jan 2026 09:54:59 +0530 Subject: [PATCH 08/69] drm/amd/pm: Add message control for SMUv15 Initialize smu message control in SMUv15 SOCs. Signed-off-by: Lijo Lazar Reviewed-by: Asad Kamal Signed-off-by: Alex Deucher --- .../drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c index 05d4e8d293ea..bbde9ade02ac 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c @@ -1342,6 +1342,22 @@ static void smu_v15_0_0_set_smu_mailbox_registers(struct smu_context *smu) smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_31); } +static void smu_v15_0_0_init_msg_ctl(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + struct smu_msg_ctl *ctl = &smu->msg_ctl; + + ctl->smu = smu; + mutex_init(&ctl->lock); + ctl->config.msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_30); + ctl->config.resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_31); + ctl->config.arg_regs[0] = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_32); + ctl->config.num_arg_regs = 1; + ctl->ops = &smu_msg_v1_ops; + ctl->default_timeout = adev->usec_timeout * 20; + ctl->message_map = smu_v15_0_0_message_map; +} + void smu_v15_0_0_set_ppt_funcs(struct smu_context *smu) { @@ -1352,4 +1368,5 @@ void smu_v15_0_0_set_ppt_funcs(struct smu_context *smu) smu->is_apu = true; smu_v15_0_0_set_smu_mailbox_registers(smu); + smu_v15_0_0_init_msg_ctl(smu); } From 28665cad86f2830b966547afa996c3c20a432dfb Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Tue, 16 Dec 2025 12:32:05 +0530 Subject: [PATCH 09/69] drm/amd/pm: Use message control in messaging Use message control block operations in common message functions. Signed-off-by: Lijo Lazar Reviewed-by: Asad Kamal Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 217 ++----------------------- 1 file changed, 15 insertions(+), 202 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c index de4b7f423a76..ef603a4d57f6 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c @@ -65,14 +65,6 @@ static const char *smu_get_message_name(struct smu_context *smu, return __smu_message_names[type]; } -static void smu_cmn_read_arg(struct smu_context *smu, - uint32_t *arg) -{ - struct amdgpu_device *adev = smu->adev; - - *arg = RREG32(smu->param_reg); -} - /* Redefine the SMU error codes here. * * Note that these definitions are redundant and should be removed @@ -127,75 +119,6 @@ static u32 __smu_cmn_poll_stat(struct smu_context *smu) return reg; } -static void __smu_cmn_reg_print_error(struct smu_context *smu, - u32 reg_c2pmsg_90, - int msg_index, - u32 param, - enum smu_message_type msg) -{ - struct amdgpu_device *adev = smu->adev; - const char *message = smu_get_message_name(smu, msg); - u32 msg_idx, prm; - - switch (reg_c2pmsg_90) { - case SMU_RESP_NONE: { - msg_idx = RREG32(smu->msg_reg); - prm = RREG32(smu->param_reg); - dev_err_ratelimited(adev->dev, - "SMU: I'm not done with your previous command: SMN_C2PMSG_66:0x%08X SMN_C2PMSG_82:0x%08X", - msg_idx, prm); - } - break; - case SMU_RESP_OK: - /* The SMU executed the command. It completed with a - * successful result. - */ - break; - case SMU_RESP_CMD_FAIL: - /* The SMU executed the command. It completed with an - * unsuccessful result. - */ - break; - case SMU_RESP_CMD_UNKNOWN: - dev_err_ratelimited(adev->dev, - "SMU: unknown command: index:%d param:0x%08X message:%s", - msg_index, param, message); - break; - case SMU_RESP_CMD_BAD_PREREQ: - dev_err_ratelimited(adev->dev, - "SMU: valid command, bad prerequisites: index:%d param:0x%08X message:%s", - msg_index, param, message); - break; - case SMU_RESP_BUSY_OTHER: - /* It is normal for SMU_MSG_GetBadPageCount to return busy - * so don't print error at this case. - */ - if (msg != SMU_MSG_GetBadPageCount) - dev_err_ratelimited(adev->dev, - "SMU: I'm very busy for your command: index:%d param:0x%08X message:%s", - msg_index, param, message); - break; - case SMU_RESP_DEBUG_END: - dev_err_ratelimited(adev->dev, - "SMU: I'm debugging!"); - break; - case SMU_RESP_UNEXP: - if (amdgpu_device_bus_status_check(smu->adev)) { - /* print error immediately if device is off the bus */ - dev_err(adev->dev, - "SMU: response:0x%08X for index:%d param:0x%08X message:%s?", - reg_c2pmsg_90, msg_index, param, message); - break; - } - fallthrough; - default: - dev_err_ratelimited(adev->dev, - "SMU: response:0x%08X for index:%d param:0x%08X message:%s?", - reg_c2pmsg_90, msg_index, param, message); - break; - } -} - static int __smu_cmn_reg2errno(struct smu_context *smu, u32 reg_c2pmsg_90) { int res; @@ -252,54 +175,6 @@ static void __smu_cmn_send_msg(struct smu_context *smu, WREG32(smu->msg_reg, msg); } -static inline uint32_t __smu_cmn_get_msg_flags(struct smu_context *smu, - enum smu_message_type msg) -{ - return smu->message_map[msg].flags; -} - -static int __smu_cmn_ras_filter_msg(struct smu_context *smu, - enum smu_message_type msg, bool *poll) -{ - struct amdgpu_device *adev = smu->adev; - uint32_t flags, resp; - bool fed_status, pri; - - flags = __smu_cmn_get_msg_flags(smu, msg); - *poll = true; - - pri = !!(flags & SMU_MSG_NO_PRECHECK); - /* When there is RAS fatal error, FW won't process non-RAS priority - * messages. Don't allow any messages other than RAS priority messages. - */ - fed_status = amdgpu_ras_get_fed_status(adev); - if (fed_status) { - if (!(flags & SMU_MSG_RAS_PRI)) { - dev_dbg(adev->dev, - "RAS error detected, skip sending %s", - smu_get_message_name(smu, msg)); - return -EACCES; - } - } - - if (pri || fed_status) { - /* FW will ignore non-priority messages when a RAS fatal error - * or reset condition is detected. Hence it is possible that a - * previous message wouldn't have got response. Allow to - * continue without polling for response status for priority - * messages. - */ - resp = RREG32(smu->resp_reg); - dev_dbg(adev->dev, - "Sending priority message %s response status: %x", - smu_get_message_name(smu, msg), resp); - if (resp == 0) - *poll = false; - } - - return 0; -} - static int __smu_cmn_send_debug_msg(struct smu_context *smu, u32 msg, u32 param) @@ -375,22 +250,7 @@ int smu_cmn_send_msg_without_waiting(struct smu_context *smu, */ int smu_cmn_wait_for_response(struct smu_context *smu) { - u32 reg; - int res; - - reg = __smu_cmn_poll_stat(smu); - res = __smu_cmn_reg2errno(smu, reg); - - if (res == -EREMOTEIO) - smu->smc_fw_state = SMU_FW_HANG; - - if (unlikely(smu->adev->pm.smu_debug_mask & SMU_DEBUG_HALT_ON_ERROR) && - res && (res != -ETIME)) { - amdgpu_device_halt(smu->adev); - WARN_ON(1); - } - - return res; + return smu_msg_wait_response(&smu->msg_ctl, 0); } /** @@ -430,70 +290,23 @@ int smu_cmn_send_smc_msg_with_param(struct smu_context *smu, uint32_t param, uint32_t *read_arg) { - struct amdgpu_device *adev = smu->adev; - int res, index; - bool poll = true; - u32 reg; + struct smu_msg_ctl *ctl = &smu->msg_ctl; + struct smu_msg_args args = { + .msg = msg, + .args[0] = param, + .num_args = 1, + .num_out_args = read_arg ? 1 : 0, + .flags = 0, + .timeout = 0, + }; + int ret; - if (adev->no_hw_access) - return 0; + ret = ctl->ops->send_msg(ctl, &args); - index = smu_cmn_to_asic_specific_index(smu, - CMN2ASIC_MAPPING_MSG, - msg); - if (index < 0) - return index == -EACCES ? 0 : index; + if (read_arg) + *read_arg = args.out_args[0]; - mutex_lock(&smu->message_lock); - - if (smu->smc_fw_caps & SMU_FW_CAP_RAS_PRI) { - res = __smu_cmn_ras_filter_msg(smu, msg, &poll); - if (res) - goto Out; - } - - if (smu->smc_fw_state == SMU_FW_HANG) { - dev_err(adev->dev, "SMU is in hanged state, failed to send smu message!\n"); - res = -EREMOTEIO; - goto Out; - } else if (smu->smc_fw_state == SMU_FW_INIT) { - /* Ignore initial smu response register value */ - poll = false; - smu->smc_fw_state = SMU_FW_RUNTIME; - } - - if (poll) { - reg = __smu_cmn_poll_stat(smu); - res = __smu_cmn_reg2errno(smu, reg); - if (reg == SMU_RESP_NONE || res == -EREMOTEIO) { - __smu_cmn_reg_print_error(smu, reg, index, param, msg); - goto Out; - } - } - __smu_cmn_send_msg(smu, (uint16_t) index, param); - reg = __smu_cmn_poll_stat(smu); - res = __smu_cmn_reg2errno(smu, reg); - if (res != 0) { - if (res == -EREMOTEIO) - smu->smc_fw_state = SMU_FW_HANG; - __smu_cmn_reg_print_error(smu, reg, index, param, msg); - } - if (read_arg) { - smu_cmn_read_arg(smu, read_arg); - dev_dbg(adev->dev, "smu send message: %s(%d) param: 0x%08x, resp: 0x%08x, readval: 0x%08x\n", - smu_get_message_name(smu, msg), index, param, reg, *read_arg); - } else { - dev_dbg(adev->dev, "smu send message: %s(%d) param: 0x%08x, resp: 0x%08x\n", - smu_get_message_name(smu, msg), index, param, reg); - } -Out: - if (unlikely(adev->pm.smu_debug_mask & SMU_DEBUG_HALT_ON_ERROR) && res) { - amdgpu_device_halt(adev); - WARN_ON(1); - } - - mutex_unlock(&smu->message_lock); - return res; + return ret; } int smu_cmn_send_smc_msg(struct smu_context *smu, From c42852d83d0154cdb41626246a90aa64d1e4fb52 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Tue, 16 Dec 2025 12:46:40 +0530 Subject: [PATCH 10/69] drm/amd/pm: Add async message call support Add asynchronous messaging (message which doesn't wait for response) using message control block. Signed-off-by: Lijo Lazar Reviewed-by: Asad Kamal Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 3 +- drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 37 +++++++++++++++++-- drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h | 2 + 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h index 842ae201a8ca..3b2937c07cad 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h @@ -554,7 +554,8 @@ struct cmn2asic_mapping { #define SMU_MSG_MAX_ARGS 4 /* Message flags for smu_msg_args */ -#define SMU_MSG_FLAG_NO_WAIT BIT(0) /* Skip post-poll (for split send/wait) */ +#define SMU_MSG_FLAG_ASYNC BIT(0) /* Async send - skip post-poll */ +#define SMU_MSG_FLAG_LOCK_HELD BIT(1) /* Caller holds ctl->lock */ struct smu_msg_ctl; /** diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c index ef603a4d57f6..ce2986276a81 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c @@ -546,6 +546,7 @@ static int smu_msg_v1_send_msg(struct smu_msg_ctl *ctl, u32 reg, msg_flags; int ret, index; bool skip_pre_poll = false; + bool lock_held = args->flags & SMU_MSG_FLAG_LOCK_HELD; /* Early exit if no HW access */ if (adev->no_hw_access) @@ -570,7 +571,8 @@ static int smu_msg_v1_send_msg(struct smu_msg_ctl *ctl, if (amdgpu_sriov_vf(adev) && !(msg_flags & SMU_MSG_VF_FLAG)) return 0; - mutex_lock(&ctl->lock); + if (!lock_held) + mutex_lock(&ctl->lock); /* RAS priority filter */ ret = __smu_msg_v1_ras_filter(ctl, args->msg, msg_flags, @@ -602,8 +604,8 @@ static int smu_msg_v1_send_msg(struct smu_msg_ctl *ctl, /* Send message */ __smu_msg_v1_send(ctl, (u16)index, args); - /* Post-poll (skip if NO_WAIT) */ - if (args->flags & SMU_MSG_FLAG_NO_WAIT) { + /* Post-poll (skip if ASYNC) */ + if (args->flags & SMU_MSG_FLAG_ASYNC) { ret = 0; goto out; } @@ -650,7 +652,8 @@ static int smu_msg_v1_send_msg(struct smu_msg_ctl *ctl, WARN_ON(1); } - mutex_unlock(&ctl->lock); + if (!lock_held) + mutex_unlock(&ctl->lock); return ret; } @@ -687,6 +690,32 @@ int smu_msg_wait_response(struct smu_msg_ctl *ctl, u32 timeout_us) return ctl->ops->wait_response(ctl, timeout_us); } +/** + * smu_msg_send_async_locked - Send message asynchronously, caller holds lock + * @ctl: Message control block + * @msg: Message type + * @param: Message parameter + * + * Send an SMU message without waiting for response. Caller must hold ctl->lock + * and call smu_msg_wait_response() later to get the result. + * + * Return: 0 on success, negative errno on failure + */ +int smu_msg_send_async_locked(struct smu_msg_ctl *ctl, + enum smu_message_type msg, u32 param) +{ + struct smu_msg_args args = { + .msg = msg, + .args[0] = param, + .num_args = 1, + .num_out_args = 0, + .flags = SMU_MSG_FLAG_ASYNC | SMU_MSG_FLAG_LOCK_HELD, + .timeout = 0, + }; + + return ctl->ops->send_msg(ctl, &args); +} + int smu_cmn_to_asic_specific_index(struct smu_context *smu, enum smu_cmn2asic_mapping_type type, uint32_t index) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h index d9a37ed4e720..13a5c1320874 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h @@ -28,6 +28,8 @@ extern const struct smu_msg_ops smu_msg_v1_ops; int smu_msg_wait_response(struct smu_msg_ctl *ctl, u32 timeout_us); +int smu_msg_send_async_locked(struct smu_msg_ctl *ctl, + enum smu_message_type msg, u32 param); #if defined(SWSMU_CODE_LAYER_L2) || defined(SWSMU_CODE_LAYER_L3) || defined(SWSMU_CODE_LAYER_L4) From 3b7743701969e29d1956c40822e09acb3850d422 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Tue, 16 Dec 2025 12:55:26 +0530 Subject: [PATCH 11/69] drm/amd/pm: Replace without wait with async calls Use the new async locked message function instead of without_waiting messaging function. Signed-off-by: Lijo Lazar Reviewed-by: Asad Kamal Signed-off-by: Alex Deucher --- .../amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 22 ++++++++--------- .../gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 16 ++++--------- .../drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 24 ++++++++++--------- .../gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c | 13 ++++++---- .../drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c | 24 +++++++++---------- .../gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c | 12 ++++++---- .../gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c | 12 ++++++---- 7 files changed, 64 insertions(+), 59 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c index 9ea6b0d1954b..087b4b6ce857 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c @@ -3043,21 +3043,21 @@ static int sienna_cichlid_stb_get_data_direct(struct smu_context *smu, static int sienna_cichlid_mode2_reset(struct smu_context *smu) { - int ret = 0, index; + struct smu_msg_ctl *ctl = &smu->msg_ctl; struct amdgpu_device *adev = smu->adev; + int ret = 0; int timeout = 100; - index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG, - SMU_MSG_DriverMode2Reset); + mutex_lock(&ctl->lock); - mutex_lock(&smu->message_lock); + ret = smu_msg_send_async_locked(ctl, SMU_MSG_DriverMode2Reset, + SMU_RESET_MODE_2); + if (ret) + goto out; - ret = smu_cmn_send_msg_without_waiting(smu, (uint16_t)index, - SMU_RESET_MODE_2); - - ret = smu_cmn_wait_for_response(smu); + ret = smu_msg_wait_response(ctl, 0); while (ret != 0 && timeout) { - ret = smu_cmn_wait_for_response(smu); + ret = smu_msg_wait_response(ctl, 0); /* Wait a bit more time for getting ACK */ if (ret != 0) { --timeout; @@ -3075,11 +3075,11 @@ static int sienna_cichlid_mode2_reset(struct smu_context *smu) goto out; } - dev_info(smu->adev->dev, "restore config space...\n"); + dev_info(adev->dev, "restore config space...\n"); /* Restore the config space saved during init */ amdgpu_device_load_pci_state(adev->pdev); out: - mutex_unlock(&smu->message_lock); + mutex_unlock(&ctl->lock); return ret; } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c index a645094b029b..fe1924289040 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c @@ -2272,18 +2272,12 @@ static int vangogh_post_smu_init(struct smu_context *smu) static int vangogh_mode_reset(struct smu_context *smu, int type) { - int ret = 0, index = 0; + struct smu_msg_ctl *ctl = &smu->msg_ctl; + int ret; - index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG, - SMU_MSG_GfxDeviceDriverReset); - if (index < 0) - return index == -EACCES ? 0 : index; - - mutex_lock(&smu->message_lock); - - ret = smu_cmn_send_msg_without_waiting(smu, (uint16_t)index, type); - - mutex_unlock(&smu->message_lock); + mutex_lock(&ctl->lock); + ret = smu_msg_send_async_locked(ctl, SMU_MSG_GfxDeviceDriverReset, type); + mutex_unlock(&ctl->lock); mdelay(10); 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 a3f4b25ac474..76edb54972dc 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -1828,26 +1828,28 @@ static int aldebaran_mode1_reset(struct smu_context *smu) static int aldebaran_mode2_reset(struct smu_context *smu) { - int ret = 0, index; + struct smu_msg_ctl *ctl = &smu->msg_ctl; struct amdgpu_device *adev = smu->adev; + int ret = 0; int timeout = 10; - index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG, - SMU_MSG_GfxDeviceDriverReset); - if (index < 0 ) - return -EINVAL; - mutex_lock(&smu->message_lock); + mutex_lock(&ctl->lock); + if (smu->smc_fw_version >= 0x00441400) { - ret = smu_cmn_send_msg_without_waiting(smu, (uint16_t)index, SMU_RESET_MODE_2); + ret = smu_msg_send_async_locked(ctl, SMU_MSG_GfxDeviceDriverReset, + SMU_RESET_MODE_2); + if (ret) + goto out; + /* This is similar to FLR, wait till max FLR timeout */ msleep(100); - dev_dbg(smu->adev->dev, "restore config space...\n"); + dev_dbg(adev->dev, "restore config space...\n"); /* Restore the config space saved during init */ amdgpu_device_load_pci_state(adev->pdev); - dev_dbg(smu->adev->dev, "wait for reset ack\n"); + dev_dbg(adev->dev, "wait for reset ack\n"); while (ret == -ETIME && timeout) { - ret = smu_cmn_wait_for_response(smu); + ret = smu_msg_wait_response(ctl, 0); /* Wait a bit more time for getting ACK */ if (ret == -ETIME) { --timeout; @@ -1870,7 +1872,7 @@ static int aldebaran_mode2_reset(struct smu_context *smu) if (ret == 1) ret = 0; out: - mutex_unlock(&smu->message_lock); + mutex_unlock(&ctl->lock); return ret; } 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 e5996162fd5c..b941ab24f823 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 @@ -2244,18 +2244,21 @@ int smu_v13_0_baco_exit(struct smu_context *smu) int smu_v13_0_set_gfx_power_up_by_imu(struct smu_context *smu) { - uint16_t index; + struct smu_msg_ctl *ctl = &smu->msg_ctl; struct amdgpu_device *adev = smu->adev; + int ret; if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_EnableGfxImu, ENABLE_IMU_ARG_GFXOFF_ENABLE, NULL); } - index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG, - SMU_MSG_EnableGfxImu); - return smu_cmn_send_msg_without_waiting(smu, index, - ENABLE_IMU_ARG_GFXOFF_ENABLE); + mutex_lock(&ctl->lock); + ret = smu_msg_send_async_locked(ctl, SMU_MSG_EnableGfxImu, + ENABLE_IMU_ARG_GFXOFF_ENABLE); + mutex_unlock(&ctl->lock); + + return ret; } int smu_v13_0_od_edit_dpm_table(struct smu_context *smu, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c index a9789f3a23b0..cf011fc3bb61 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c @@ -2897,24 +2897,22 @@ static void smu_v13_0_6_restore_pci_config(struct smu_context *smu) static int smu_v13_0_6_mode2_reset(struct smu_context *smu) { - int ret = 0, index; + struct smu_msg_ctl *ctl = &smu->msg_ctl; struct amdgpu_device *adev = smu->adev; + int ret = 0; int timeout = 10; - index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG, - SMU_MSG_GfxDeviceDriverReset); - if (index < 0) - return index; + mutex_lock(&ctl->lock); - mutex_lock(&smu->message_lock); - - ret = smu_cmn_send_msg_without_waiting(smu, (uint16_t)index, - SMU_RESET_MODE_2); + ret = smu_msg_send_async_locked(ctl, SMU_MSG_GfxDeviceDriverReset, + SMU_RESET_MODE_2); + if (ret) + goto out; /* Reset takes a bit longer, wait for 200ms. */ msleep(200); - dev_dbg(smu->adev->dev, "restore config space...\n"); + dev_dbg(adev->dev, "restore config space...\n"); /* Restore the config space saved during init */ amdgpu_device_load_pci_state(adev->pdev); @@ -2932,9 +2930,9 @@ static int smu_v13_0_6_mode2_reset(struct smu_context *smu) if (!(adev->flags & AMD_IS_APU)) smu_v13_0_6_restore_pci_config(smu); - dev_dbg(smu->adev->dev, "wait for reset ack\n"); + dev_dbg(adev->dev, "wait for reset ack\n"); do { - ret = smu_cmn_wait_for_response(smu); + ret = smu_msg_wait_response(ctl, 0); /* Wait a bit more time for getting ACK */ if (ret == -ETIME) { --timeout; @@ -2948,7 +2946,7 @@ static int smu_v13_0_6_mode2_reset(struct smu_context *smu) } while (ret == -ETIME && timeout); out: - mutex_unlock(&smu->message_lock); + mutex_unlock(&ctl->lock); if (ret) dev_err(adev->dev, "failed to send mode2 reset, error code %d", diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c index 8f7f293de3d8..f85ba23f9d99 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c @@ -1834,17 +1834,21 @@ int smu_v14_0_baco_exit(struct smu_context *smu) int smu_v14_0_set_gfx_power_up_by_imu(struct smu_context *smu) { - uint16_t index; + struct smu_msg_ctl *ctl = &smu->msg_ctl; struct amdgpu_device *adev = smu->adev; + int ret; if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_EnableGfxImu, ENABLE_IMU_ARG_GFXOFF_ENABLE, NULL); } - index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG, - SMU_MSG_EnableGfxImu); - return smu_cmn_send_msg_without_waiting(smu, index, ENABLE_IMU_ARG_GFXOFF_ENABLE); + mutex_lock(&ctl->lock); + ret = smu_msg_send_async_locked(ctl, SMU_MSG_EnableGfxImu, + ENABLE_IMU_ARG_GFXOFF_ENABLE); + mutex_unlock(&ctl->lock); + + return ret; } int smu_v14_0_set_default_dpm_tables(struct smu_context *smu) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c index 631bdf387163..6557085a7c72 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c @@ -1709,17 +1709,21 @@ int smu_v15_0_baco_exit(struct smu_context *smu) int smu_v15_0_set_gfx_power_up_by_imu(struct smu_context *smu) { - uint16_t index; + struct smu_msg_ctl *ctl = &smu->msg_ctl; struct amdgpu_device *adev = smu->adev; + int ret; if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_EnableGfxImu, ENABLE_IMU_ARG_GFXOFF_ENABLE, NULL); } - index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG, - SMU_MSG_EnableGfxImu); - return smu_cmn_send_msg_without_waiting(smu, index, ENABLE_IMU_ARG_GFXOFF_ENABLE); + mutex_lock(&ctl->lock); + ret = smu_msg_send_async_locked(ctl, SMU_MSG_EnableGfxImu, + ENABLE_IMU_ARG_GFXOFF_ENABLE); + mutex_unlock(&ctl->lock); + + return ret; } int smu_v15_0_set_default_dpm_tables(struct smu_context *smu) From 359b9f088f53a3e0ff90e094cf1f4b32dc1d86f3 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Tue, 16 Dec 2025 13:39:39 +0530 Subject: [PATCH 12/69] drm/amd/pm: Remove unused legacy message functions Messaging functions are now moved to message control block. Remove unused legacy functions around messaging. Signed-off-by: Lijo Lazar Reviewed-by: Asad Kamal Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 146 +------------------------ drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h | 3 - 2 files changed, 2 insertions(+), 147 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c index ce2986276a81..177643df1aab 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c @@ -82,98 +82,6 @@ static const char *smu_get_message_name(struct smu_context *smu, #define SMU_RESP_DEBUG_END 0xFB #define SMU_RESP_UNEXP (~0U) -/** - * __smu_cmn_poll_stat -- poll for a status from the SMU - * @smu: a pointer to SMU context - * - * Returns the status of the SMU, which could be, - * 0, the SMU is busy with your command; - * 1, execution status: success, execution result: success; - * 0xFF, execution status: success, execution result: failure; - * 0xFE, unknown command; - * 0xFD, valid command, but bad (command) prerequisites; - * 0xFC, the command was rejected as the SMU is busy; - * 0xFB, "SMC_Result_DebugDataDumpEnd". - * - * The values here are not defined by macros, because I'd rather we - * include a single header file which defines them, which is - * maintained by the SMU FW team, so that we're impervious to firmware - * changes. At the moment those values are defined in various header - * files, one for each ASIC, yet here we're a single ASIC-agnostic - * interface. Such a change can be followed-up by a subsequent patch. - */ -static u32 __smu_cmn_poll_stat(struct smu_context *smu) -{ - struct amdgpu_device *adev = smu->adev; - int timeout = adev->usec_timeout * 20; - u32 reg; - - for ( ; timeout > 0; timeout--) { - reg = RREG32(smu->resp_reg); - if ((reg & MP1_C2PMSG_90__CONTENT_MASK) != 0) - break; - - udelay(1); - } - - return reg; -} - -static int __smu_cmn_reg2errno(struct smu_context *smu, u32 reg_c2pmsg_90) -{ - int res; - - switch (reg_c2pmsg_90) { - case SMU_RESP_NONE: - /* The SMU is busy--still executing your command. - */ - res = -ETIME; - break; - case SMU_RESP_OK: - res = 0; - break; - case SMU_RESP_CMD_FAIL: - /* Command completed successfully, but the command - * status was failure. - */ - res = -EIO; - break; - case SMU_RESP_CMD_UNKNOWN: - /* Unknown command--ignored by the SMU. - */ - res = -EOPNOTSUPP; - break; - case SMU_RESP_CMD_BAD_PREREQ: - /* Valid command--bad prerequisites. - */ - res = -EINVAL; - break; - case SMU_RESP_BUSY_OTHER: - /* The SMU is busy with other commands. The client - * should retry in 10 us. - */ - res = -EBUSY; - break; - default: - /* Unknown or debug response from the SMU. - */ - res = -EREMOTEIO; - break; - } - - return res; -} - -static void __smu_cmn_send_msg(struct smu_context *smu, - u16 msg, - u32 param) -{ - struct amdgpu_device *adev = smu->adev; - - WREG32(smu->resp_reg, 0); - WREG32(smu->param_reg, param); - WREG32(smu->msg_reg, msg); -} static int __smu_cmn_send_debug_msg(struct smu_context *smu, u32 msg, @@ -187,56 +95,6 @@ static int __smu_cmn_send_debug_msg(struct smu_context *smu, return 0; } -/** - * smu_cmn_send_msg_without_waiting -- send the message; don't wait for status - * @smu: pointer to an SMU context - * @msg_index: message index - * @param: message parameter to send to the SMU - * - * Send a message to the SMU with the parameter passed. Do not wait - * for status/result of the message, thus the "without_waiting". - * - * Return 0 on success, -errno on error if we weren't able to _send_ - * the message for some reason. See __smu_cmn_reg2errno() for details - * of the -errno. - */ -int smu_cmn_send_msg_without_waiting(struct smu_context *smu, - uint16_t msg_index, - uint32_t param) -{ - struct amdgpu_device *adev = smu->adev; - u32 reg; - int res; - - if (adev->no_hw_access) - return 0; - - if (smu->smc_fw_state == SMU_FW_HANG) { - dev_err(adev->dev, "SMU is in hanged state, failed to send smu message!\n"); - res = -EREMOTEIO; - goto Out; - } - - if (smu->smc_fw_state == SMU_FW_INIT) { - smu->smc_fw_state = SMU_FW_RUNTIME; - } else { - reg = __smu_cmn_poll_stat(smu); - res = __smu_cmn_reg2errno(smu, reg); - if (reg == SMU_RESP_NONE || res == -EREMOTEIO) - goto Out; - } - - __smu_cmn_send_msg(smu, msg_index, param); - res = 0; -Out: - if (unlikely(adev->pm.smu_debug_mask & SMU_DEBUG_HALT_ON_ERROR) && - res && (res != -ETIME)) { - amdgpu_device_halt(adev); - WARN_ON(1); - } - - return res; -} /** * smu_cmn_wait_for_response -- wait for response from the SMU @@ -246,7 +104,7 @@ int smu_cmn_send_msg_without_waiting(struct smu_context *smu, * * Return 0 on success, -errno on error, indicating the execution * status and result of the message being waited for. See - * __smu_cmn_reg2errno() for details of the -errno. + * smu_msg_v1_decode_response() for details of the -errno. */ int smu_cmn_wait_for_response(struct smu_context *smu) { @@ -269,7 +127,7 @@ int smu_cmn_wait_for_response(struct smu_context *smu) * message or receiving reply. If there is a PCI bus recovery or * the destination is a virtual GPU which does not allow this message * type, the message is simply dropped and success is also returned. - * See __smu_cmn_reg2errno() for details of the -errno. + * See smu_msg_v1_decode_response() for details of the -errno. * * If we weren't able to send the message to the SMU, we also print * the error to the standard log. diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h index 13a5c1320874..4af587b42dda 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h @@ -110,9 +110,6 @@ static inline int pcie_gen_to_speed(uint32_t gen) return ((gen == 0) ? link_speed[0] : link_speed[gen - 1]); } -int smu_cmn_send_msg_without_waiting(struct smu_context *smu, - uint16_t msg_index, - uint32_t param); int smu_cmn_send_smc_msg_with_param(struct smu_context *smu, enum smu_message_type msg, uint32_t param, From 8c502fd5b6e3831d8f138e8b1000c17b3add1929 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Tue, 16 Dec 2025 13:45:52 +0530 Subject: [PATCH 13/69] drm/amd/pm: Drop legacy message fields from SMUv11 Remove usage of legacy message related fields from SMUv11 SOCs. Signed-off-by: Lijo Lazar Reviewed-by: Asad Kamal Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h | 1 - drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 2 -- drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c | 2 -- drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 2 -- drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 2 -- drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c | 9 --------- drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 2 -- drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 4 ++-- 8 files changed, 2 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h index 97c19005952c..7c1701ed3e11 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h @@ -282,7 +282,6 @@ int smu_v11_0_handle_passthrough_sbr(struct smu_context *smu, bool enable); int smu_v11_0_restore_user_od_settings(struct smu_context *smu); -void smu_v11_0_set_smu_mailbox_registers(struct smu_context *smu); void smu_v11_0_init_msg_ctl(struct smu_context *smu, const struct cmn2asic_msg_mapping *message_map); 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 eadd81e413aa..4de7ae6f7c8e 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c @@ -1959,12 +1959,10 @@ static const struct pptable_funcs arcturus_ppt_funcs = { void arcturus_set_ppt_funcs(struct smu_context *smu) { smu->ppt_funcs = &arcturus_ppt_funcs; - smu->message_map = arcturus_message_map; smu->clock_map = arcturus_clk_map; smu->feature_map = arcturus_feature_mask_map; smu->table_map = arcturus_table_map; smu->pwr_src_map = arcturus_pwr_src_map; smu->workload_map = arcturus_workload_map; - smu_v11_0_set_smu_mailbox_registers(smu); smu_v11_0_init_msg_ctl(smu, arcturus_message_map); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c index 5ae6ee87de04..15968b057469 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c @@ -601,9 +601,7 @@ static const struct pptable_funcs cyan_skillfish_ppt_funcs = { void cyan_skillfish_set_ppt_funcs(struct smu_context *smu) { smu->ppt_funcs = &cyan_skillfish_ppt_funcs; - smu->message_map = cyan_skillfish_message_map; smu->table_map = cyan_skillfish_table_map; smu->is_apu = true; - smu_v11_0_set_smu_mailbox_registers(smu); smu_v11_0_init_msg_ctl(smu, cyan_skillfish_message_map); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c index 3596cb7f8adf..d7aa16681e24 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c @@ -3369,12 +3369,10 @@ static const struct pptable_funcs navi10_ppt_funcs = { void navi10_set_ppt_funcs(struct smu_context *smu) { smu->ppt_funcs = &navi10_ppt_funcs; - smu->message_map = navi10_message_map; smu->clock_map = navi10_clk_map; smu->feature_map = navi10_feature_mask_map; smu->table_map = navi10_table_map; smu->pwr_src_map = navi10_pwr_src_map; smu->workload_map = navi10_workload_map; - smu_v11_0_set_smu_mailbox_registers(smu); smu_v11_0_init_msg_ctl(smu, navi10_message_map); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c index 087b4b6ce857..90aba9adc24f 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c @@ -3182,12 +3182,10 @@ static const struct pptable_funcs sienna_cichlid_ppt_funcs = { void sienna_cichlid_set_ppt_funcs(struct smu_context *smu) { smu->ppt_funcs = &sienna_cichlid_ppt_funcs; - smu->message_map = sienna_cichlid_message_map; smu->clock_map = sienna_cichlid_clk_map; smu->feature_map = sienna_cichlid_feature_mask_map; smu->table_map = sienna_cichlid_table_map; smu->pwr_src_map = sienna_cichlid_pwr_src_map; smu->workload_map = sienna_cichlid_workload_map; - smu_v11_0_set_smu_mailbox_registers(smu); smu_v11_0_init_msg_ctl(smu, sienna_cichlid_message_map); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c index 579b1dbd36ac..eb1b9faf8e5c 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c @@ -2168,15 +2168,6 @@ int smu_v11_0_restore_user_od_settings(struct smu_context *smu) return ret; } -void smu_v11_0_set_smu_mailbox_registers(struct smu_context *smu) -{ - struct amdgpu_device *adev = smu->adev; - - smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82); - smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66); - smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); -} - void smu_v11_0_init_msg_ctl(struct smu_context *smu, const struct cmn2asic_msg_mapping *message_map) { diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c index fe1924289040..4ca211ea628f 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c @@ -2557,11 +2557,9 @@ static const struct pptable_funcs vangogh_ppt_funcs = { void vangogh_set_ppt_funcs(struct smu_context *smu) { smu->ppt_funcs = &vangogh_ppt_funcs; - smu->message_map = vangogh_message_map; smu->feature_map = vangogh_feature_mask_map; smu->table_map = vangogh_table_map; smu->workload_map = vangogh_workload_map; smu->is_apu = true; - smu_v11_0_set_smu_mailbox_registers(smu); smu_v11_0_init_msg_ctl(smu, vangogh_message_map); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c index 177643df1aab..6b673eefc7b1 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c @@ -584,10 +584,10 @@ int smu_cmn_to_asic_specific_index(struct smu_context *smu, switch (type) { case CMN2ASIC_MAPPING_MSG: if (index >= SMU_MSG_MAX_COUNT || - !smu->message_map) + !smu->msg_ctl.message_map) return -EINVAL; - msg_mapping = smu->message_map[index]; + msg_mapping = smu->msg_ctl.message_map[index]; if (!msg_mapping.valid_mapping) return -EINVAL; From 8ba2a9a987d047288b7b9b6617b3c3879b1e9731 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Tue, 16 Dec 2025 13:48:30 +0530 Subject: [PATCH 14/69] drm/amd/pm: Drop legacy message fields from SMUv12 Remove usage of legacy message related fields from SMUv12 SOCs. Signed-off-by: Lijo Lazar Reviewed-by: Asad Kamal Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c index 7e41991f140e..a81360abc2f0 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c @@ -41,15 +41,6 @@ #undef pr_info #undef pr_debug -#define mmMP1_SMN_C2PMSG_66 0x0282 -#define mmMP1_SMN_C2PMSG_66_BASE_IDX 0 - -#define mmMP1_SMN_C2PMSG_82 0x0292 -#define mmMP1_SMN_C2PMSG_82_BASE_IDX 0 - -#define mmMP1_SMN_C2PMSG_90 0x029a -#define mmMP1_SMN_C2PMSG_90_BASE_IDX 0 - static struct cmn2asic_msg_mapping renoir_message_map[SMU_MSG_MAX_COUNT] = { MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 1), MSG_MAP(GetSmuVersion, PPSMC_MSG_GetSmuVersion, 1), @@ -1495,17 +1486,11 @@ static const struct pptable_funcs renoir_ppt_funcs = { void renoir_set_ppt_funcs(struct smu_context *smu) { - struct amdgpu_device *adev = smu->adev; - smu->ppt_funcs = &renoir_ppt_funcs; - smu->message_map = renoir_message_map; smu->clock_map = renoir_clk_map; smu->table_map = renoir_table_map; smu->workload_map = renoir_workload_map; smu->smc_driver_if_version = SMU12_DRIVER_IF_VERSION; smu->is_apu = true; - smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82); - smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66); - smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); smu_v12_0_init_msg_ctl(smu, renoir_message_map); } From 8d623384894cc04ae8637ba2137d168909c83f8a Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Tue, 16 Dec 2025 14:17:45 +0530 Subject: [PATCH 15/69] drm/amd/pm: Drop legacy message fields from SMUv13 Remove usage of legacy message related fields from SMUv13 SOCs. Signed-off-by: Lijo Lazar Reviewed-by: Asad Kamal Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h | 1 - .../gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 2 -- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c | 9 --------- .../drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 14 -------------- .../drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c | 17 ++--------------- .../drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c | 6 ------ .../drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c | 7 ++++--- .../drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 2 -- .../drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c | 2 -- 9 files changed, 6 insertions(+), 54 deletions(-) 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 fabf61e15dba..efeaa3d57712 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 @@ -251,7 +251,6 @@ int smu_v13_0_od_edit_dpm_table(struct smu_context *smu, int smu_v13_0_set_default_dpm_tables(struct smu_context *smu); -void smu_v13_0_set_smu_mailbox_registers(struct smu_context *smu); void smu_v13_0_init_msg_ctl(struct smu_context *smu, const struct cmn2asic_msg_mapping *message_map); 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 76edb54972dc..94b8e5dd76b5 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -2034,11 +2034,9 @@ static const struct pptable_funcs aldebaran_ppt_funcs = { void aldebaran_set_ppt_funcs(struct smu_context *smu) { smu->ppt_funcs = &aldebaran_ppt_funcs; - smu->message_map = aldebaran_message_map; smu->clock_map = aldebaran_clk_map; smu->feature_map = aldebaran_feature_mask_map; smu->table_map = aldebaran_table_map; smu->smc_driver_if_version = SMU13_DRIVER_IF_VERSION_ALDE; - smu_v13_0_set_smu_mailbox_registers(smu); smu_v13_0_init_msg_ctl(smu, aldebaran_message_map); } 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 b941ab24f823..34ff4c35baff 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 @@ -2351,15 +2351,6 @@ int smu_v13_0_set_default_dpm_tables(struct smu_context *smu) smu_table->clocks_table, false); } -void smu_v13_0_set_smu_mailbox_registers(struct smu_context *smu) -{ - struct amdgpu_device *adev = smu->adev; - - smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82); - smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66); - smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); -} - void smu_v13_0_init_msg_ctl(struct smu_context *smu, const struct cmn2asic_msg_mapping *message_map) { 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 128fb68abf70..37941b6c2831 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 @@ -70,15 +70,6 @@ #define MP0_MP1_DATA_REGION_SIZE_COMBOPPTABLE 0x4000 -#define mmMP1_SMN_C2PMSG_66 0x0282 -#define mmMP1_SMN_C2PMSG_66_BASE_IDX 0 - -#define mmMP1_SMN_C2PMSG_82 0x0292 -#define mmMP1_SMN_C2PMSG_82_BASE_IDX 0 - -#define mmMP1_SMN_C2PMSG_90 0x029a -#define mmMP1_SMN_C2PMSG_90_BASE_IDX 0 - #define mmMP1_SMN_C2PMSG_75 0x028b #define mmMP1_SMN_C2PMSG_75_BASE_IDX 0 @@ -2895,10 +2886,6 @@ static void smu_v13_0_0_set_smu_mailbox_registers(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; - smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82); - smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66); - smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); - smu->debug_param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_53); smu->debug_msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_75); smu->debug_resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_54); @@ -3223,7 +3210,6 @@ static const struct pptable_funcs smu_v13_0_0_ppt_funcs = { void smu_v13_0_0_set_ppt_funcs(struct smu_context *smu) { smu->ppt_funcs = &smu_v13_0_0_ppt_funcs; - smu->message_map = smu_v13_0_0_message_map; smu->clock_map = smu_v13_0_0_clk_map; smu->feature_map = smu_v13_0_0_feature_mask_map; smu->table_map = smu_v13_0_0_table_map; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c index d8ef38535fe8..7ca9adfa2446 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c @@ -1124,15 +1124,6 @@ static const struct pptable_funcs smu_v13_0_4_ppt_funcs = { .set_gfx_power_up_by_imu = smu_v13_0_set_gfx_power_up_by_imu, }; -static void smu_v13_0_4_set_smu_mailbox_registers(struct smu_context *smu) -{ - struct amdgpu_device *adev = smu->adev; - - smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82); - smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66); - smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); -} - static void smu_v13_0_4_init_msg_ctl(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; @@ -1154,17 +1145,13 @@ void smu_v13_0_4_set_ppt_funcs(struct smu_context *smu) struct amdgpu_device *adev = smu->adev; smu->ppt_funcs = &smu_v13_0_4_ppt_funcs; - smu->message_map = smu_v13_0_4_message_map; smu->feature_map = smu_v13_0_4_feature_mask_map; smu->table_map = smu_v13_0_4_table_map; smu->smc_driver_if_version = SMU13_0_4_DRIVER_IF_VERSION; smu->is_apu = true; - if (amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 4)) { - smu_v13_0_4_set_smu_mailbox_registers(smu); + if (amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 4)) smu_v13_0_4_init_msg_ctl(smu); - } else { - smu_v13_0_set_smu_mailbox_registers(smu); + else smu_v13_0_init_msg_ctl(smu, smu_v13_0_4_message_map); - } } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c index f351880a5e97..29ec02f2dd6a 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c @@ -1144,16 +1144,10 @@ static void smu_v13_0_5_init_msg_ctl(struct smu_context *smu) void smu_v13_0_5_set_ppt_funcs(struct smu_context *smu) { - struct amdgpu_device *adev = smu->adev; - smu->ppt_funcs = &smu_v13_0_5_ppt_funcs; - smu->message_map = smu_v13_0_5_message_map; smu->feature_map = smu_v13_0_5_feature_mask_map; smu->table_map = smu_v13_0_5_table_map; smu->is_apu = true; smu->smc_driver_if_version = SMU13_0_5_DRIVER_IF_VERSION; - smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_C2PMSG_34); - smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_C2PMSG_2); - smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_C2PMSG_33); smu_v13_0_5_init_msg_ctl(smu); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c index cf011fc3bb61..d76ac14a8a64 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c @@ -3899,8 +3899,10 @@ static const struct pptable_funcs smu_v13_0_6_ppt_funcs = { void smu_v13_0_6_set_ppt_funcs(struct smu_context *smu) { + const struct cmn2asic_msg_mapping *message_map; + smu->ppt_funcs = &smu_v13_0_6_ppt_funcs; - smu->message_map = (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 12)) ? + message_map = (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 12)) ? smu_v13_0_12_message_map : smu_v13_0_6_message_map; smu->clock_map = smu_v13_0_6_clk_map; smu->feature_map = (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 12)) ? @@ -3908,8 +3910,7 @@ void smu_v13_0_6_set_ppt_funcs(struct smu_context *smu) smu->table_map = smu_v13_0_6_table_map; smu->smc_driver_if_version = SMU_IGNORE_IF_VERSION; smu->smc_fw_caps |= SMU_FW_CAP_RAS_PRI; - smu_v13_0_set_smu_mailbox_registers(smu); - smu_v13_0_init_msg_ctl(smu, smu->message_map); + smu_v13_0_init_msg_ctl(smu, message_map); smu_v13_0_6_set_temp_funcs(smu); amdgpu_mca_smu_init_funcs(smu->adev, &smu_v13_0_6_mca_smu_funcs); amdgpu_aca_set_smu_funcs(smu->adev, &smu_v13_0_6_aca_smu_funcs); 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 d8f2059a1631..0375e8484b2a 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 @@ -2809,13 +2809,11 @@ static const struct pptable_funcs smu_v13_0_7_ppt_funcs = { void smu_v13_0_7_set_ppt_funcs(struct smu_context *smu) { smu->ppt_funcs = &smu_v13_0_7_ppt_funcs; - smu->message_map = smu_v13_0_7_message_map; smu->clock_map = smu_v13_0_7_clk_map; smu->feature_map = smu_v13_0_7_feature_mask_map; smu->table_map = smu_v13_0_7_table_map; smu->pwr_src_map = smu_v13_0_7_pwr_src_map; smu->workload_map = smu_v13_0_7_workload_map; smu->smc_driver_if_version = SMU13_0_7_DRIVER_IF_VERSION; - smu_v13_0_set_smu_mailbox_registers(smu); smu_v13_0_init_msg_ctl(smu, smu_v13_0_7_message_map); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c index 79ec2d235a09..b4b55a66fb71 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c @@ -1360,11 +1360,9 @@ static const struct pptable_funcs yellow_carp_ppt_funcs = { void yellow_carp_set_ppt_funcs(struct smu_context *smu) { smu->ppt_funcs = &yellow_carp_ppt_funcs; - smu->message_map = yellow_carp_message_map; smu->feature_map = yellow_carp_feature_mask_map; smu->table_map = yellow_carp_table_map; smu->is_apu = true; smu->smc_driver_if_version = SMU13_YELLOW_CARP_DRIVER_IF_VERSION; - smu_v13_0_set_smu_mailbox_registers(smu); smu_v13_0_init_msg_ctl(smu, yellow_carp_message_map); } From 4068f195d1385d8b36440d7d9e92eb718fb423fd Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Tue, 16 Dec 2025 14:19:42 +0530 Subject: [PATCH 16/69] drm/amd/pm: Drop legacy message fields from SMUv14 Remove usage of legacy message related fields from SMUv14 SOCs. Signed-off-by: Lijo Lazar Reviewed-by: Asad Kamal Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h | 6 ++---- drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c | 12 ------------ drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c | 5 ----- 3 files changed, 2 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h index 4ecec85b8404..613d4d36f32f 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h @@ -215,10 +215,8 @@ int smu_v14_0_get_pptable_from_firmware(struct smu_context *smu, uint32_t pptable_id); int smu_v14_0_od_edit_dpm_table(struct smu_context *smu, - enum PP_OD_DPM_TABLE_COMMAND type, - long input[], uint32_t size); - -void smu_v14_0_set_smu_mailbox_registers(struct smu_context *smu); + enum PP_OD_DPM_TABLE_COMMAND type, + long input[], uint32_t size); int smu_v14_0_enable_thermal_alert(struct smu_context *smu); diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c index 9c15fccac2b8..0a509fec2180 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c @@ -1731,15 +1731,6 @@ static const struct pptable_funcs smu_v14_0_0_ppt_funcs = { .set_mall_enable = smu_v14_0_common_set_mall_enable, }; -static void smu_v14_0_0_set_smu_mailbox_registers(struct smu_context *smu) -{ - struct amdgpu_device *adev = smu->adev; - - smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82); - smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66); - smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); -} - static void smu_v14_0_0_init_msg_ctl(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; @@ -1758,13 +1749,10 @@ static void smu_v14_0_0_init_msg_ctl(struct smu_context *smu) void smu_v14_0_0_set_ppt_funcs(struct smu_context *smu) { - smu->ppt_funcs = &smu_v14_0_0_ppt_funcs; - smu->message_map = smu_v14_0_0_message_map; smu->feature_map = smu_v14_0_0_feature_mask_map; smu->table_map = smu_v14_0_0_table_map; smu->is_apu = true; - smu_v14_0_0_set_smu_mailbox_registers(smu); smu_v14_0_0_init_msg_ctl(smu); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c index 5bf10555effd..e414dfd6f644 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c @@ -2111,10 +2111,6 @@ static void smu_v14_0_2_set_smu_mailbox_registers(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; - smu->param_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_82); - smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_66); - smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_90); - smu->debug_param_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_53); smu->debug_msg_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_75); smu->debug_resp_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_54); @@ -2875,7 +2871,6 @@ static const struct pptable_funcs smu_v14_0_2_ppt_funcs = { void smu_v14_0_2_set_ppt_funcs(struct smu_context *smu) { smu->ppt_funcs = &smu_v14_0_2_ppt_funcs; - smu->message_map = smu_v14_0_2_message_map; smu->clock_map = smu_v14_0_2_clk_map; smu->feature_map = smu_v14_0_2_feature_mask_map; smu->table_map = smu_v14_0_2_table_map; From 97cf0aace8eae6daa9e8f19047d36b741f022e3a Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Thu, 8 Jan 2026 10:06:48 +0530 Subject: [PATCH 17/69] drm/amd/pm: Drop legacy message fields from SMUv15 Remove usage of legacy message related fields from SMUv15 SOCs. Signed-off-by: Lijo Lazar Reviewed-by: Asad Kamal Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/inc/smu_v15_0.h | 2 -- drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c | 12 ------------ 2 files changed, 14 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v15_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v15_0.h index 9020317ffd69..14e8d8c7a80a 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v15_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v15_0.h @@ -237,8 +237,6 @@ int smu_v15_0_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABLE_COMMAND type, long input[], uint32_t size); -void smu_v15_0_set_smu_mailbox_registers(struct smu_context *smu); - int smu_v15_0_enable_thermal_alert(struct smu_context *smu); int smu_v15_0_disable_thermal_alert(struct smu_context *smu); diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c index bbde9ade02ac..61387d2a65ef 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c @@ -1333,15 +1333,6 @@ static const struct pptable_funcs smu_v15_0_0_ppt_funcs = { .get_dpm_clock_table = smu_v15_0_common_get_dpm_table, }; -static void smu_v15_0_0_set_smu_mailbox_registers(struct smu_context *smu) -{ - struct amdgpu_device *adev = smu->adev; - - smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_32); - smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_30); - smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_31); -} - static void smu_v15_0_0_init_msg_ctl(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; @@ -1360,13 +1351,10 @@ static void smu_v15_0_0_init_msg_ctl(struct smu_context *smu) void smu_v15_0_0_set_ppt_funcs(struct smu_context *smu) { - smu->ppt_funcs = &smu_v15_0_0_ppt_funcs; - smu->message_map = smu_v15_0_0_message_map; smu->feature_map = smu_v15_0_0_feature_mask_map; smu->table_map = smu_v15_0_0_table_map; smu->is_apu = true; - smu_v15_0_0_set_smu_mailbox_registers(smu); smu_v15_0_0_init_msg_ctl(smu); } From a45eef15a2170b411ac441254fcd8d58b57bc92f Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Tue, 16 Dec 2025 14:26:46 +0530 Subject: [PATCH 18/69] drm/amd/pm: Drop legacy message related fields Remove legacy message related fields from smu context. Signed-off-by: Lijo Lazar Reviewed-by: Asad Kamal Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 2 -- drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 6 ------ 2 files changed, 8 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 8284f74b6c54..6b6b05e8f736 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -826,8 +826,6 @@ static int smu_early_init(struct amdgpu_ip_block *ip_block) smu->user_dpm_profile.fan_mode = -1; smu->power_profile_mode = PP_SMC_POWER_PROFILE_UNKNOWN; - mutex_init(&smu->message_lock); - adev->powerplay.pp_handle = smu; adev->powerplay.pp_funcs = &swsmu_pm_funcs; diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h index 3b2937c07cad..9e0c8ed67e73 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h @@ -655,13 +655,11 @@ struct smu_context { struct amdgpu_irq_src irq_source; const struct pptable_funcs *ppt_funcs; - const struct cmn2asic_msg_mapping *message_map; const struct cmn2asic_mapping *clock_map; const struct cmn2asic_mapping *feature_map; const struct cmn2asic_mapping *table_map; const struct cmn2asic_mapping *pwr_src_map; const struct cmn2asic_mapping *workload_map; - struct mutex message_lock; uint64_t pool_size; struct smu_table_context smu_table; @@ -745,10 +743,6 @@ struct smu_context { struct firmware pptable_firmware; - u32 param_reg; - u32 msg_reg; - u32 resp_reg; - u32 debug_param_reg; u32 debug_msg_reg; u32 debug_resp_reg; From 8376acce43aa958c2fff107a1d3d3a689a4eb85d Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Tue, 16 Dec 2025 14:34:43 +0530 Subject: [PATCH 19/69] drm/amd/pm: Drop unused ppt callback from SMUv11 SMU message related ppt callbacks are not used. Drop from SMUv11. Signed-off-by: Lijo Lazar Reviewed-by: Asad Kamal Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 2 -- drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c | 2 -- drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 2 -- drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 2 -- drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 2 -- 5 files changed, 10 deletions(-) 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 4de7ae6f7c8e..7c5ce6a6e2ca 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c @@ -1915,8 +1915,6 @@ static const struct pptable_funcs arcturus_ppt_funcs = { .set_tool_table_location = smu_v11_0_set_tool_table_location, .notify_memory_pool_location = smu_v11_0_notify_memory_pool_location, .system_features_control = smu_v11_0_system_features_control, - .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, - .send_smc_msg = smu_cmn_send_smc_msg, .init_display_count = NULL, .set_allowed_mask = smu_v11_0_set_allowed_mask, .get_enabled_mask = smu_cmn_get_enabled_mask, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c index 15968b057469..4a5dcc893665 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c @@ -592,8 +592,6 @@ static const struct pptable_funcs cyan_skillfish_ppt_funcs = { .get_dpm_ultimate_freq = cyan_skillfish_get_dpm_ultimate_freq, .register_irq_handler = smu_v11_0_register_irq_handler, .notify_memory_pool_location = smu_v11_0_notify_memory_pool_location, - .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, - .send_smc_msg = smu_cmn_send_smc_msg, .set_driver_table_location = smu_v11_0_set_driver_table_location, .interrupt_work = smu_v11_0_interrupt_work, }; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c index d7aa16681e24..1f84654bbc85 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c @@ -3319,8 +3319,6 @@ static const struct pptable_funcs navi10_ppt_funcs = { .set_tool_table_location = smu_v11_0_set_tool_table_location, .notify_memory_pool_location = smu_v11_0_notify_memory_pool_location, .system_features_control = smu_v11_0_system_features_control, - .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, - .send_smc_msg = smu_cmn_send_smc_msg, .init_display_count = smu_v11_0_init_display_count, .set_allowed_mask = smu_v11_0_set_allowed_mask, .get_enabled_mask = smu_cmn_get_enabled_mask, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c index 90aba9adc24f..f930ba2733e9 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c @@ -3126,8 +3126,6 @@ static const struct pptable_funcs sienna_cichlid_ppt_funcs = { .set_tool_table_location = smu_v11_0_set_tool_table_location, .notify_memory_pool_location = smu_v11_0_notify_memory_pool_location, .system_features_control = sienna_cichlid_system_features_control, - .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, - .send_smc_msg = smu_cmn_send_smc_msg, .init_display_count = NULL, .set_allowed_mask = smu_v11_0_set_allowed_mask, .get_enabled_mask = smu_cmn_get_enabled_mask, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c index 4ca211ea628f..4de1778ea6b3 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c @@ -2516,8 +2516,6 @@ static const struct pptable_funcs vangogh_ppt_funcs = { .fini_power = smu_v11_0_fini_power, .register_irq_handler = smu_v11_0_register_irq_handler, .notify_memory_pool_location = smu_v11_0_notify_memory_pool_location, - .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, - .send_smc_msg = smu_cmn_send_smc_msg, .dpm_set_vcn_enable = vangogh_dpm_set_vcn_enable, .dpm_set_jpeg_enable = vangogh_dpm_set_jpeg_enable, .is_dpm_running = vangogh_is_dpm_running, From c3c61d11419c6c8de0f0156c95d4dfb829121b3f Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Tue, 16 Dec 2025 14:35:59 +0530 Subject: [PATCH 20/69] drm/amd/pm: Drop unused ppt callback from SMUv12 SMU message related ppt callbacks are not used. Drop from SMUv12. Signed-off-by: Lijo Lazar Reviewed-by: Asad Kamal Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c index a81360abc2f0..5346b60b09b9 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c @@ -1459,8 +1459,6 @@ static const struct pptable_funcs renoir_ppt_funcs = { .check_fw_status = smu_v12_0_check_fw_status, .check_fw_version = smu_v12_0_check_fw_version, .powergate_sdma = smu_v12_0_powergate_sdma, - .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, - .send_smc_msg = smu_cmn_send_smc_msg, .set_gfx_cgpg = smu_v12_0_set_gfx_cgpg, .gfx_off_control = smu_v12_0_gfx_off_control, .get_gfx_off_status = smu_v12_0_get_gfxoff_status, From ca184ac28af0e1b033fdd432ce79a1225751f360 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Tue, 16 Dec 2025 14:38:59 +0530 Subject: [PATCH 21/69] drm/amd/pm: Drop unused ppt callback from SMUv13 SMU message related ppt callbacks are not used. Drop from SMUv13. Signed-off-by: Lijo Lazar Reviewed-by: Asad Kamal Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 2 -- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c | 2 -- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c | 2 -- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c | 2 -- drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c | 2 -- 5 files changed, 10 deletions(-) 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 94b8e5dd76b5..9de0b676bb7b 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -1996,8 +1996,6 @@ static const struct pptable_funcs aldebaran_ppt_funcs = { .set_tool_table_location = smu_v13_0_set_tool_table_location, .notify_memory_pool_location = smu_v13_0_notify_memory_pool_location, .system_features_control = aldebaran_system_features_control, - .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, - .send_smc_msg = smu_cmn_send_smc_msg, .get_enabled_mask = smu_cmn_get_enabled_mask, .feature_is_enabled = smu_cmn_feature_is_enabled, .disable_all_features_with_exception = smu_cmn_disable_all_features_with_exception, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c index 7ca9adfa2446..41c61362f7fc 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c @@ -1101,8 +1101,6 @@ static const struct pptable_funcs smu_v13_0_4_ppt_funcs = { .fini_smc_tables = smu_v13_0_4_fini_smc_tables, .get_vbios_bootup_values = smu_v13_0_get_vbios_bootup_values, .system_features_control = smu_v13_0_4_system_features_control, - .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, - .send_smc_msg = smu_cmn_send_smc_msg, .dpm_set_vcn_enable = smu_v13_0_set_vcn_enable, .dpm_set_jpeg_enable = smu_v13_0_set_jpeg_enable, .set_default_dpm_table = smu_v13_0_set_default_dpm_tables, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c index 29ec02f2dd6a..e4be727789c0 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c @@ -1104,8 +1104,6 @@ static const struct pptable_funcs smu_v13_0_5_ppt_funcs = { .fini_smc_tables = smu_v13_0_5_fini_smc_tables, .get_vbios_bootup_values = smu_v13_0_get_vbios_bootup_values, .system_features_control = smu_v13_0_5_system_features_control, - .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, - .send_smc_msg = smu_cmn_send_smc_msg, .dpm_set_vcn_enable = smu_v13_0_5_dpm_set_vcn_enable, .dpm_set_jpeg_enable = smu_v13_0_5_dpm_set_jpeg_enable, .set_default_dpm_table = smu_v13_0_5_set_default_dpm_tables, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c index d76ac14a8a64..1e82c43c851a 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c @@ -3860,8 +3860,6 @@ static const struct pptable_funcs smu_v13_0_6_ppt_funcs = { .set_tool_table_location = smu_v13_0_set_tool_table_location, .notify_memory_pool_location = smu_v13_0_notify_memory_pool_location, .system_features_control = smu_v13_0_6_system_features_control, - .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, - .send_smc_msg = smu_cmn_send_smc_msg, .get_enabled_mask = smu_v13_0_6_get_enabled_mask, .feature_is_enabled = smu_cmn_feature_is_enabled, .set_power_limit = smu_v13_0_6_set_power_limit, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c index b4b55a66fb71..7f70f79c3b2f 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c @@ -1333,8 +1333,6 @@ static const struct pptable_funcs yellow_carp_ppt_funcs = { .fini_smc_tables = yellow_carp_fini_smc_tables, .get_vbios_bootup_values = smu_v13_0_get_vbios_bootup_values, .system_features_control = yellow_carp_system_features_control, - .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, - .send_smc_msg = smu_cmn_send_smc_msg, .dpm_set_vcn_enable = yellow_carp_dpm_set_vcn_enable, .dpm_set_jpeg_enable = yellow_carp_dpm_set_jpeg_enable, .set_default_dpm_table = yellow_carp_set_default_dpm_tables, From 28aff13304196f4c6900602e8407a4b96147bef0 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Tue, 16 Dec 2025 14:39:49 +0530 Subject: [PATCH 22/69] drm/amd/pm: Drop unused ppt callback from SMUv14 SMU message related ppt callbacks are not used. Drop from SMUv14. Signed-off-by: Lijo Lazar Reviewed-by: Asad Kamal Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c index 0a509fec2180..a4e376e8328c 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c @@ -1701,8 +1701,6 @@ static const struct pptable_funcs smu_v14_0_0_ppt_funcs = { .fini_smc_tables = smu_v14_0_0_fini_smc_tables, .get_vbios_bootup_values = smu_v14_0_get_vbios_bootup_values, .system_features_control = smu_v14_0_0_system_features_control, - .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, - .send_smc_msg = smu_cmn_send_smc_msg, .dpm_set_vcn_enable = smu_v14_0_set_vcn_enable, .dpm_set_jpeg_enable = smu_v14_0_set_jpeg_enable, .set_default_dpm_table = smu_v14_0_set_default_dpm_tables, From 72838568bddc935a3626c67c85940efa3a1e76c9 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Thu, 8 Jan 2026 10:09:39 +0530 Subject: [PATCH 23/69] drm/amd/pm: Drop unused ppt callback from SMUv15 SMU message related ppt callbacks are not used. Drop from SMUv15. Signed-off-by: Lijo Lazar Reviewed-by: Asad Kamal Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c index 61387d2a65ef..95a693a4557c 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c @@ -1307,8 +1307,6 @@ static const struct pptable_funcs smu_v15_0_0_ppt_funcs = { .fini_smc_tables = smu_v15_0_0_fini_smc_tables, .get_vbios_bootup_values = smu_v15_0_get_vbios_bootup_values, .system_features_control = smu_v15_0_0_system_features_control, - .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, - .send_smc_msg = smu_cmn_send_smc_msg, .dpm_set_vcn_enable = smu_v15_0_set_vcn_enable, .dpm_set_jpeg_enable = smu_v15_0_set_jpeg_enable, .set_default_dpm_table = smu_v15_0_set_default_dpm_tables, From b9b393c68a10940b26d7a9c5d5d294bba887d440 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Tue, 16 Dec 2025 14:41:12 +0530 Subject: [PATCH 24/69] drm/amd/pm: Drop unused ppt callback definitions SMU message related ppt callbacks are not used. Drop from ppt_funcs. Signed-off-by: Lijo Lazar Reviewed-by: Asad Kamal Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 18 ------------------ drivers/gpu/drm/amd/pm/swsmu/smu_internal.h | 2 -- 2 files changed, 20 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h index 9e0c8ed67e73..e88fdd65e1cd 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h @@ -1187,24 +1187,6 @@ struct pptable_funcs { */ int (*system_features_control)(struct smu_context *smu, bool en); - /** - * @send_smc_msg_with_param: Send a message with a parameter to the SMU. - * &msg: Type of message. - * ¶m: Message parameter. - * &read_arg: SMU response (optional). - */ - int (*send_smc_msg_with_param)(struct smu_context *smu, - enum smu_message_type msg, uint32_t param, uint32_t *read_arg); - - /** - * @send_smc_msg: Send a message to the SMU. - * &msg: Type of message. - * &read_arg: SMU response (optional). - */ - int (*send_smc_msg)(struct smu_context *smu, - enum smu_message_type msg, - uint32_t *read_arg); - /** * @init_display_count: Notify the SMU of the number of display * components in current display configuration. diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h b/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h index 34f6b4b1c3ba..0f7778410a3a 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h @@ -54,8 +54,6 @@ #define smu_system_features_control(smu, en) smu_ppt_funcs(system_features_control, 0, smu, en) #define smu_init_max_sustainable_clocks(smu) smu_ppt_funcs(init_max_sustainable_clocks, 0, smu) #define smu_set_default_od_settings(smu) smu_ppt_funcs(set_default_od_settings, 0, smu) -#define smu_send_smc_msg_with_param(smu, msg, param, read_arg) smu_ppt_funcs(send_smc_msg_with_param, 0, smu, msg, param, read_arg) -#define smu_send_smc_msg(smu, msg, read_arg) smu_ppt_funcs(send_smc_msg, 0, smu, msg, read_arg) #define smu_init_display_count(smu, count) smu_ppt_funcs(init_display_count, 0, smu, count) #define smu_feature_set_allowed_mask(smu) smu_ppt_funcs(set_allowed_mask, 0, smu) #define smu_feature_get_enabled_mask(smu, mask) smu_ppt_funcs(get_enabled_mask, -EOPNOTSUPP, smu, mask) From 2f0d5ecae0f5604c87075237a919b68d38cc9500 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Wed, 17 Dec 2025 16:39:11 +0530 Subject: [PATCH 25/69] drm/amd/pm: Add debug message callback Add callback in message control to send message through debug mailbox. Signed-off-by: Lijo Lazar Reviewed-by: Asad Kamal Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 12 +++++++++++ drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 20 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h index e88fdd65e1cd..84b50820a613 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h @@ -557,6 +557,9 @@ struct cmn2asic_mapping { #define SMU_MSG_FLAG_ASYNC BIT(0) /* Async send - skip post-poll */ #define SMU_MSG_FLAG_LOCK_HELD BIT(1) /* Caller holds ctl->lock */ +/* smu_msg_ctl flags */ +#define SMU_MSG_CTL_DEBUG_MAILBOX BIT(0) /* Debug mailbox supported */ + struct smu_msg_ctl; /** * struct smu_msg_config - IP-level register configuration @@ -564,12 +567,18 @@ struct smu_msg_ctl; * @resp_reg: Response register offset * @arg_regs: Argument register offsets (up to SMU_MSG_MAX_ARGS) * @num_arg_regs: Number of argument registers available + * @debug_msg_reg: Debug message register offset + * @debug_resp_reg: Debug response register offset + * @debug_param_reg: Debug parameter register offset */ struct smu_msg_config { u32 msg_reg; u32 resp_reg; u32 arg_regs[SMU_MSG_MAX_ARGS]; int num_arg_regs; + u32 debug_msg_reg; + u32 debug_resp_reg; + u32 debug_param_reg; }; /** @@ -597,11 +606,13 @@ struct smu_msg_args { * @send_msg: send message protocol * @wait_response: wait for response (for split send/wait cases) * @decode_response: Convert response register value to errno + * @send_debug_msg: send debug message */ struct smu_msg_ops { int (*send_msg)(struct smu_msg_ctl *ctl, struct smu_msg_args *args); int (*wait_response)(struct smu_msg_ctl *ctl, u32 timeout_us); int (*decode_response)(u32 resp); + int (*send_debug_msg)(struct smu_msg_ctl *ctl, u32 msg, u32 param); }; /** @@ -617,6 +628,7 @@ struct smu_msg_ctl { const struct smu_msg_ops *ops; const struct cmn2asic_msg_mapping *message_map; u32 default_timeout; + u32 flags; }; struct stb_context { diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c index 6b673eefc7b1..f639d3636d30 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c @@ -83,6 +83,25 @@ static const char *smu_get_message_name(struct smu_context *smu, #define SMU_RESP_UNEXP (~0U) +static int smu_msg_v1_send_debug_msg(struct smu_msg_ctl *ctl, u32 msg, u32 param) +{ + struct amdgpu_device *adev = ctl->smu->adev; + struct smu_msg_config *cfg = &ctl->config; + + if (!(ctl->flags & SMU_MSG_CTL_DEBUG_MAILBOX)) + return -EOPNOTSUPP; + + mutex_lock(&ctl->lock); + + WREG32(cfg->debug_param_reg, param); + WREG32(cfg->debug_msg_reg, msg); + WREG32(cfg->debug_resp_reg, 0); + + mutex_unlock(&ctl->lock); + + return 0; +} + static int __smu_cmn_send_debug_msg(struct smu_context *smu, u32 msg, u32 param) @@ -541,6 +560,7 @@ const struct smu_msg_ops smu_msg_v1_ops = { .send_msg = smu_msg_v1_send_msg, .wait_response = smu_msg_v1_wait_response, .decode_response = smu_msg_v1_decode_response, + .send_debug_msg = smu_msg_v1_send_debug_msg, }; int smu_msg_wait_response(struct smu_msg_ctl *ctl, u32 timeout_us) From cf3f100cec0192630e37e9cc9232186c61c0703b Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Wed, 17 Dec 2025 16:55:09 +0530 Subject: [PATCH 26/69] drm/amd/pm: Use message control for debug mailbox Migrate existing debug message mechanism so that it uses debug message callbacks in message control block. Signed-off-by: Lijo Lazar Reviewed-by: Asad Kamal Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 4 ---- .../gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c | 1 + .../drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 16 ++++++++++------ .../drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c | 17 +++++++---------- drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 19 ++++++++----------- 5 files changed, 26 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h index 84b50820a613..3efd5cca3d09 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h @@ -755,10 +755,6 @@ struct smu_context { struct firmware pptable_firmware; - u32 debug_param_reg; - u32 debug_msg_reg; - u32 debug_resp_reg; - struct delayed_work swctf_delayed_work; /* data structures for wbrf feature support */ 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 34ff4c35baff..51f96fdcec24 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 @@ -2366,6 +2366,7 @@ void smu_v13_0_init_msg_ctl(struct smu_context *smu, ctl->ops = &smu_msg_v1_ops; ctl->default_timeout = adev->usec_timeout * 20; ctl->message_map = message_map; + ctl->flags = 0; } int smu_v13_0_mode1_reset(struct smu_context *smu) 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 37941b6c2831..ce52b616b935 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 @@ -2882,13 +2882,18 @@ static int smu_v13_0_0_enable_gfx_features(struct smu_context *smu) return -EOPNOTSUPP; } -static void smu_v13_0_0_set_smu_mailbox_registers(struct smu_context *smu) +static void smu_v13_0_0_init_msg_ctl(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; + struct smu_msg_ctl *ctl = &smu->msg_ctl; - smu->debug_param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_53); - smu->debug_msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_75); - smu->debug_resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_54); + smu_v13_0_init_msg_ctl(smu, smu_v13_0_0_message_map); + + /* Set up debug mailbox registers */ + ctl->config.debug_param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_53); + ctl->config.debug_msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_75); + ctl->config.debug_resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_54); + ctl->flags |= SMU_MSG_CTL_DEBUG_MAILBOX; } static int smu_v13_0_0_smu_send_bad_mem_page_num(struct smu_context *smu, @@ -3216,8 +3221,7 @@ void smu_v13_0_0_set_ppt_funcs(struct smu_context *smu) smu->pwr_src_map = smu_v13_0_0_pwr_src_map; smu->workload_map = smu_v13_0_0_workload_map; smu->smc_driver_if_version = SMU13_0_0_DRIVER_IF_VERSION; - smu_v13_0_0_set_smu_mailbox_registers(smu); - smu_v13_0_init_msg_ctl(smu, smu_v13_0_0_message_map); + smu_v13_0_0_init_msg_ctl(smu); if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 10) && diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c index e414dfd6f644..03c26d8248a3 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c @@ -2107,15 +2107,6 @@ static int smu_v14_0_2_enable_gfx_features(struct smu_context *smu) return -EOPNOTSUPP; } -static void smu_v14_0_2_set_smu_mailbox_registers(struct smu_context *smu) -{ - struct amdgpu_device *adev = smu->adev; - - smu->debug_param_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_53); - smu->debug_msg_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_75); - smu->debug_resp_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_54); -} - static void smu_v14_0_2_init_msg_ctl(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; @@ -2130,6 +2121,13 @@ static void smu_v14_0_2_init_msg_ctl(struct smu_context *smu) ctl->ops = &smu_msg_v1_ops; ctl->default_timeout = adev->usec_timeout * 20; ctl->message_map = smu_v14_0_2_message_map; + ctl->flags = 0; + + /* Set up debug mailbox registers */ + ctl->config.debug_param_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_53); + ctl->config.debug_msg_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_75); + ctl->config.debug_resp_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_54); + ctl->flags |= SMU_MSG_CTL_DEBUG_MAILBOX; } static ssize_t smu_v14_0_2_get_gpu_metrics(struct smu_context *smu, @@ -2876,6 +2874,5 @@ void smu_v14_0_2_set_ppt_funcs(struct smu_context *smu) smu->table_map = smu_v14_0_2_table_map; smu->pwr_src_map = smu_v14_0_2_pwr_src_map; smu->workload_map = smu_v14_0_2_workload_map; - smu_v14_0_2_set_smu_mailbox_registers(smu); smu_v14_0_2_init_msg_ctl(smu); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c index f639d3636d30..5b1f059105d6 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c @@ -102,17 +102,14 @@ static int smu_msg_v1_send_debug_msg(struct smu_msg_ctl *ctl, u32 msg, u32 param return 0; } -static int __smu_cmn_send_debug_msg(struct smu_context *smu, - u32 msg, - u32 param) +static int __smu_cmn_send_debug_msg(struct smu_msg_ctl *ctl, + u32 msg, + u32 param) { - struct amdgpu_device *adev = smu->adev; + if (!ctl->ops || !ctl->ops->send_debug_msg) + return -EOPNOTSUPP; - WREG32(smu->debug_param_reg, param); - WREG32(smu->debug_msg_reg, msg); - WREG32(smu->debug_resp_reg, 0); - - return 0; + return ctl->ops->send_debug_msg(ctl, msg, param); } /** @@ -199,13 +196,13 @@ int smu_cmn_send_smc_msg(struct smu_context *smu, int smu_cmn_send_debug_smc_msg(struct smu_context *smu, uint32_t msg) { - return __smu_cmn_send_debug_msg(smu, msg, 0); + return __smu_cmn_send_debug_msg(&smu->msg_ctl, msg, 0); } int smu_cmn_send_debug_smc_msg_with_param(struct smu_context *smu, uint32_t msg, uint32_t param) { - return __smu_cmn_send_debug_msg(smu, msg, param); + return __smu_cmn_send_debug_msg(&smu->msg_ctl, msg, param); } static int smu_msg_v1_decode_response(u32 resp) From 96e97a562d067a6d867862db79864cc66aae99c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Tue, 2 Dec 2025 16:12:41 +0100 Subject: [PATCH 27/69] drm/amdgpu: Drop MMIO_REMAP domain bit and keep it Internal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "AMDGPU_GEM_DOMAIN_MMIO_REMAP" - Never activated as UAPI and it turned out that this was to inflexible. Allocate the MMIO_REMAP buffer object as a regular GEM BO and explicitly move it into the fixed AMDGPU_PL_MMIO_REMAP placement at the TTM level. This avoids relying on GEM domain bits for MMIO_REMAP, keeps the placement purely internal, and makes the lifetime and pinning of the global MMIO_REMAP BO explicit. The BO is pinned in TTM so it cannot be migrated or evicted. The corresponding free path relies on normal DRM teardown ordering, where no further user ioctls can access the global BO once TTM teardown begins. v2 (Srini): - Updated patch title. - Drop use of AMDGPU_GEM_DOMAIN_MMIO_REMAP in amdgpu_ttm.c. The MMIO_REMAP domain bit is removed from UAPI, so keep the MMIO_REMAP BO allocation domain-less (bp.domain = 0) and rely on the TTM placement (AMDGPU_PL_MMIO_REMAP) for backing/pinning. - Keep fdinfo/mem-stats visibility for MMIO_REMAP by classifying BOs based on bo->tbo.resource->mem_type == AMDGPU_PL_MMIO_REMAP, since the domain bit is removed. v3: Squash patches #1 & #3 Fixes: 056132483724 ("drm/amdgpu/uapi: Introduce AMDGPU_GEM_DOMAIN_MMIO_REMAP") Fixes: 2a7a794eb82c ("drm/amdgpu/ttm: Allocate/Free 4K MMIO_REMAP Singleton") Cc: Alex Deucher Cc: Christian König Cc: Leo Liu Cc: Ruijing Dong Cc: David (Ming Qiang) Wu Signed-off-by: Srinivasan Shanmugam Signed-off-by: Christian König Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 3 - drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 21 +++--- drivers/gpu/drm/amd/amdgpu/amdgpu_object.h | 2 - drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 77 ++++++++++++++-------- include/uapi/drm/amdgpu_drm.h | 6 +- 5 files changed, 60 insertions(+), 49 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index 032971d0a3cc..ab899709c260 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -417,9 +417,6 @@ int amdgpu_gem_create_ioctl(struct drm_device *dev, void *data, /* always clear VRAM */ flags |= AMDGPU_GEM_CREATE_VRAM_CLEARED; - if (args->in.domains & AMDGPU_GEM_DOMAIN_MMIO_REMAP) - return -EINVAL; - /* create a gem object to contain this object in */ if (args->in.domains & (AMDGPU_GEM_DOMAIN_GDS | AMDGPU_GEM_DOMAIN_GWS | AMDGPU_GEM_DOMAIN_OA)) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index b676310ce9ac..1fb956400696 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -153,14 +153,6 @@ void amdgpu_bo_placement_from_domain(struct amdgpu_bo *abo, u32 domain) c++; } - if (domain & AMDGPU_GEM_DOMAIN_MMIO_REMAP) { - places[c].fpfn = 0; - places[c].lpfn = 0; - places[c].mem_type = AMDGPU_PL_MMIO_REMAP; - places[c].flags = 0; - c++; - } - if (domain & AMDGPU_GEM_DOMAIN_GTT) { places[c].fpfn = 0; places[c].lpfn = 0; @@ -1546,8 +1538,17 @@ u64 amdgpu_bo_gpu_offset_no_check(struct amdgpu_bo *bo) */ uint32_t amdgpu_bo_mem_stats_placement(struct amdgpu_bo *bo) { - uint32_t domain = bo->preferred_domains & AMDGPU_GEM_DOMAIN_MASK; + u32 domain; + /* + * MMIO_REMAP is internal now, so it no longer maps from a userspace + * domain bit. Keep fdinfo/mem-stats visibility by checking the actual + * TTM placement. + */ + if (bo->tbo.resource && bo->tbo.resource->mem_type == AMDGPU_PL_MMIO_REMAP) + return AMDGPU_PL_MMIO_REMAP; + + domain = bo->preferred_domains & AMDGPU_GEM_DOMAIN_MASK; if (!domain) return TTM_PL_SYSTEM; @@ -1566,8 +1567,6 @@ uint32_t amdgpu_bo_mem_stats_placement(struct amdgpu_bo *bo) return AMDGPU_PL_OA; case AMDGPU_GEM_DOMAIN_DOORBELL: return AMDGPU_PL_DOORBELL; - case AMDGPU_GEM_DOMAIN_MMIO_REMAP: - return AMDGPU_PL_MMIO_REMAP; default: return TTM_PL_SYSTEM; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h index 52c2d1731aab..912c9afaf9e1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h @@ -168,8 +168,6 @@ static inline unsigned amdgpu_mem_type_to_domain(u32 mem_type) return AMDGPU_GEM_DOMAIN_OA; case AMDGPU_PL_DOORBELL: return AMDGPU_GEM_DOMAIN_DOORBELL; - case AMDGPU_PL_MMIO_REMAP: - return AMDGPU_GEM_DOMAIN_MMIO_REMAP; default: break; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index cfbcce9c27c5..15d561e3d87f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -1909,42 +1909,45 @@ static void amdgpu_ttm_pools_fini(struct amdgpu_device *adev) } /** - * amdgpu_ttm_mmio_remap_bo_init - Allocate the singleton 4K MMIO_REMAP BO + * amdgpu_ttm_mmio_remap_bo_init - Allocate the singleton MMIO_REMAP BO * @adev: amdgpu device * - * Allocates a one-page (4K) GEM BO in AMDGPU_GEM_DOMAIN_MMIO_REMAP when the + * Allocates a global BO with backing AMDGPU_PL_MMIO_REMAP when the * hardware exposes a remap base (adev->rmmio_remap.bus_addr) and the host * PAGE_SIZE is <= AMDGPU_GPU_PAGE_SIZE (4K). The BO is created as a regular * GEM object (amdgpu_bo_create). * - * The BO is created as a normal GEM object via amdgpu_bo_create(), then - * reserved and pinned at the TTM level (ttm_bo_pin()) so it can never be - * migrated or evicted. No CPU mapping is established here. - * * Return: * * 0 on success or intentional skip (feature not present/unsupported) * * negative errno on allocation failure */ -static int amdgpu_ttm_mmio_remap_bo_init(struct amdgpu_device *adev) +static int amdgpu_ttm_alloc_mmio_remap_bo(struct amdgpu_device *adev) { + struct ttm_operation_ctx ctx = { false, false }; + struct ttm_placement placement; + struct ttm_buffer_object *tbo; + struct ttm_place placements; struct amdgpu_bo_param bp; + struct ttm_resource *tmp; int r; /* Skip if HW doesn't expose remap, or if PAGE_SIZE > AMDGPU_GPU_PAGE_SIZE (4K). */ if (!adev->rmmio_remap.bus_addr || PAGE_SIZE > AMDGPU_GPU_PAGE_SIZE) return 0; + /* + * Allocate a BO first and then move it to AMDGPU_PL_MMIO_REMAP. + * The initial TTM resource assigned by amdgpu_bo_create() is + * replaced below with a fixed MMIO_REMAP placement. + */ memset(&bp, 0, sizeof(bp)); - - /* Create exactly one GEM BO in the MMIO_REMAP domain. */ - bp.type = ttm_bo_type_device; /* userspace-mappable GEM */ - bp.size = AMDGPU_GPU_PAGE_SIZE; /* 4K */ + bp.type = ttm_bo_type_device; + bp.size = AMDGPU_GPU_PAGE_SIZE; bp.byte_align = AMDGPU_GPU_PAGE_SIZE; - bp.domain = AMDGPU_GEM_DOMAIN_MMIO_REMAP; + bp.domain = 0; bp.flags = 0; bp.resv = NULL; bp.bo_ptr_size = sizeof(struct amdgpu_bo); - r = amdgpu_bo_create(adev, &bp, &adev->rmmio_remap.bo); if (r) return r; @@ -1953,42 +1956,60 @@ static int amdgpu_ttm_mmio_remap_bo_init(struct amdgpu_device *adev) if (r) goto err_unref; + tbo = &adev->rmmio_remap.bo->tbo; + /* * MMIO_REMAP is a fixed I/O placement (AMDGPU_PL_MMIO_REMAP). - * Use TTM-level pin so the BO cannot be evicted/migrated, - * independent of GEM domains. This - * enforces the “fixed I/O window” */ - ttm_bo_pin(&adev->rmmio_remap.bo->tbo); + placement.num_placement = 1; + placement.placement = &placements; + placements.fpfn = 0; + placements.lpfn = 0; + placements.mem_type = AMDGPU_PL_MMIO_REMAP; + placements.flags = 0; + /* Force the BO into the fixed MMIO_REMAP placement */ + r = ttm_bo_mem_space(tbo, &placement, &tmp, &ctx); + if (unlikely(r)) + goto err_unlock; + + ttm_resource_free(tbo, &tbo->resource); + ttm_bo_assign_mem(tbo, tmp); + ttm_bo_pin(tbo); amdgpu_bo_unreserve(adev->rmmio_remap.bo); return 0; +err_unlock: + amdgpu_bo_unreserve(adev->rmmio_remap.bo); + err_unref: - if (adev->rmmio_remap.bo) - amdgpu_bo_unref(&adev->rmmio_remap.bo); + amdgpu_bo_unref(&adev->rmmio_remap.bo); adev->rmmio_remap.bo = NULL; return r; } /** - * amdgpu_ttm_mmio_remap_bo_fini - Free the singleton MMIO_REMAP BO + * amdgpu_ttm_free_mmio_remap_bo - Free the singleton MMIO_REMAP BO * @adev: amdgpu device * * Frees the kernel-owned MMIO_REMAP BO if it was allocated by * amdgpu_ttm_mmio_remap_bo_init(). */ -static void amdgpu_ttm_mmio_remap_bo_fini(struct amdgpu_device *adev) +static void amdgpu_ttm_free_mmio_remap_bo(struct amdgpu_device *adev) { - struct amdgpu_bo *bo = adev->rmmio_remap.bo; - - if (!bo) - return; /* <-- safest early exit */ + if (!adev->rmmio_remap.bo) + return; if (!amdgpu_bo_reserve(adev->rmmio_remap.bo, true)) { ttm_bo_unpin(&adev->rmmio_remap.bo->tbo); amdgpu_bo_unreserve(adev->rmmio_remap.bo); } + + /* + * At this point we rely on normal DRM teardown ordering: + * no new user ioctls can access the global MMIO_REMAP BO + * once TTM teardown begins. + */ amdgpu_bo_unref(&adev->rmmio_remap.bo); adev->rmmio_remap.bo = NULL; } @@ -2172,8 +2193,8 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) return r; } - /* Allocate the singleton MMIO_REMAP BO (4K) if supported */ - r = amdgpu_ttm_mmio_remap_bo_init(adev); + /* Allocate the singleton MMIO_REMAP BO if supported */ + r = amdgpu_ttm_alloc_mmio_remap_bo(adev); if (r) return r; @@ -2241,7 +2262,7 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev) amdgpu_bo_free_kernel(&adev->mman.sdma_access_bo, NULL, &adev->mman.sdma_access_ptr); - amdgpu_ttm_mmio_remap_bo_fini(adev); + amdgpu_ttm_free_mmio_remap_bo(adev); amdgpu_ttm_fw_reserve_vram_fini(adev); amdgpu_ttm_drv_reserve_vram_fini(adev); diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h index f902add31fc6..1d34daa0ebcd 100644 --- a/include/uapi/drm/amdgpu_drm.h +++ b/include/uapi/drm/amdgpu_drm.h @@ -105,8 +105,6 @@ extern "C" { * * %AMDGPU_GEM_DOMAIN_DOORBELL Doorbell. It is an MMIO region for * signalling user mode queues. - * - * %AMDGPU_GEM_DOMAIN_MMIO_REMAP MMIO remap page (special mapping for HDP flushing). */ #define AMDGPU_GEM_DOMAIN_CPU 0x1 #define AMDGPU_GEM_DOMAIN_GTT 0x2 @@ -115,15 +113,13 @@ extern "C" { #define AMDGPU_GEM_DOMAIN_GWS 0x10 #define AMDGPU_GEM_DOMAIN_OA 0x20 #define AMDGPU_GEM_DOMAIN_DOORBELL 0x40 -#define AMDGPU_GEM_DOMAIN_MMIO_REMAP 0x80 #define AMDGPU_GEM_DOMAIN_MASK (AMDGPU_GEM_DOMAIN_CPU | \ AMDGPU_GEM_DOMAIN_GTT | \ AMDGPU_GEM_DOMAIN_VRAM | \ AMDGPU_GEM_DOMAIN_GDS | \ AMDGPU_GEM_DOMAIN_GWS | \ AMDGPU_GEM_DOMAIN_OA | \ - AMDGPU_GEM_DOMAIN_DOORBELL | \ - AMDGPU_GEM_DOMAIN_MMIO_REMAP) + AMDGPU_GEM_DOMAIN_DOORBELL) /* Flag that CPU access will be required for the case of VRAM domain */ #define AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED (1 << 0) From 9858810e62ca6a85bd2e7795a92e00a4ffa1c545 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 21 Dec 2025 16:13:48 +0100 Subject: [PATCH 28/69] drm/amdgpu: Slightly simplify base_addr_show() sysfs_emit_at() never returns a negative error code. It returns 0 or the number of characters written in the buffer. Remove the useless tests. This simplifies the logic and saves a few lines of code. Signed-off-by: Christophe JAILLET Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c index 8070a6da794f..ee2c08f81051 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c @@ -891,22 +891,19 @@ static ssize_t num_base_addresses_show(struct ip_hw_instance *ip_hw_instance, ch static ssize_t base_addr_show(struct ip_hw_instance *ip_hw_instance, char *buf) { - ssize_t res, at; + ssize_t at; int ii; - for (res = at = ii = 0; ii < ip_hw_instance->num_base_addresses; ii++) { + for (at = ii = 0; ii < ip_hw_instance->num_base_addresses; ii++) { /* Here we satisfy the condition that, at + size <= PAGE_SIZE. */ if (at + 12 > PAGE_SIZE) break; - res = sysfs_emit_at(buf, at, "0x%08X\n", + at += sysfs_emit_at(buf, at, "0x%08X\n", ip_hw_instance->base_addr[ii]); - if (res <= 0) - break; - at += res; } - return res < 0 ? res : at; + return at; } static struct ip_hw_instance_attr ip_hw_attr[] = { From d967509651601cddce7ff2a9f09479f3636f684d Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 9 Jan 2026 08:54:55 -0500 Subject: [PATCH 29/69] drm/amdgpu: make sure userqs are enabled in userq IOCTLs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These IOCTLs shouldn't be called when userqs are not enabled. Make sure they are enabled before executing the IOCTLs. Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 16 ++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h | 1 + drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c | 6 ++++++ 3 files changed, 23 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index c5dd5815056c..c11ec5ab9cc1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -889,12 +889,28 @@ static int amdgpu_userq_input_args_validate(struct drm_device *dev, return 0; } +bool amdgpu_userq_enabled(struct drm_device *dev) +{ + struct amdgpu_device *adev = drm_to_adev(dev); + int i; + + for (i = 0; i < AMDGPU_HW_IP_NUM; i++) { + if (adev->userq_funcs[i]) + return true; + } + + return false; +} + int amdgpu_userq_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) { union drm_amdgpu_userq *args = data; int r; + if (!amdgpu_userq_enabled(dev)) + return -ENOTSUPP; + if (amdgpu_userq_input_args_validate(dev, args, filp) < 0) return -EINVAL; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h index 1eaa94f8a291..95ace14e458c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h @@ -135,6 +135,7 @@ uint64_t amdgpu_userq_get_doorbell_index(struct amdgpu_userq_mgr *uq_mgr, struct drm_file *filp); u32 amdgpu_userq_get_supported_ip_mask(struct amdgpu_device *adev); +bool amdgpu_userq_enabled(struct drm_device *dev); int amdgpu_userq_suspend(struct amdgpu_device *adev); int amdgpu_userq_resume(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c index 25f178536469..3c6bd5531627 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c @@ -474,6 +474,9 @@ int amdgpu_userq_signal_ioctl(struct drm_device *dev, void *data, struct drm_exec exec; u64 wptr; + if (!amdgpu_userq_enabled(dev)) + return -ENOTSUPP; + num_syncobj_handles = args->num_syncobj_handles; syncobj_handles = memdup_user(u64_to_user_ptr(args->syncobj_handles), size_mul(sizeof(u32), num_syncobj_handles)); @@ -656,6 +659,9 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data, int r, i, rentry, wentry, cnt; struct drm_exec exec; + if (!amdgpu_userq_enabled(dev)) + return -ENOTSUPP; + num_read_bo_handles = wait_info->num_bo_read_handles; bo_handles_read = memdup_user(u64_to_user_ptr(wait_info->bo_read_handles), size_mul(sizeof(u32), num_read_bo_handles)); From b7cccc8286bb9919a0952c812872da1dcfe9d390 Mon Sep 17 00:00:00 2001 From: Haoxiang Li Date: Thu, 8 Jan 2026 15:18:22 +0800 Subject: [PATCH 30/69] drm/amdkfd: fix a memory leak in device_queue_manager_init() If dqm->ops.initialize() fails, add deallocate_hiq_sdma_mqd() to release the memory allocated by allocate_hiq_sdma_mqd(). Move deallocate_hiq_sdma_mqd() up to ensure proper function visibility at the point of use. Fixes: 11614c36bc8f ("drm/amdkfd: Allocate MQD trunk for HIQ and SDMA") Signed-off-by: Haoxiang Li Signed-off-by: Felix Kuehling Reviewed-by: Oak Zeng Reviewed-by: Felix Kuehling Signed-off-by: Alex Deucher --- .../drm/amd/amdkfd/kfd_device_queue_manager.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index 9bc80f8ba7dc..dc4b6d19dc10 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -2916,6 +2916,14 @@ static int allocate_hiq_sdma_mqd(struct device_queue_manager *dqm) return retval; } +static void deallocate_hiq_sdma_mqd(struct kfd_node *dev, + struct kfd_mem_obj *mqd) +{ + WARN(!mqd, "No hiq sdma mqd trunk to free"); + + amdgpu_amdkfd_free_gtt_mem(dev->adev, &mqd->gtt_mem); +} + struct device_queue_manager *device_queue_manager_init(struct kfd_node *dev) { struct device_queue_manager *dqm; @@ -3041,19 +3049,14 @@ struct device_queue_manager *device_queue_manager_init(struct kfd_node *dev) return dqm; } + if (!dev->kfd->shared_resources.enable_mes) + deallocate_hiq_sdma_mqd(dev, &dqm->hiq_sdma_mqd); + out_free: kfree(dqm); return NULL; } -static void deallocate_hiq_sdma_mqd(struct kfd_node *dev, - struct kfd_mem_obj *mqd) -{ - WARN(!mqd, "No hiq sdma mqd trunk to free"); - - amdgpu_amdkfd_free_gtt_mem(dev->adev, &mqd->gtt_mem); -} - void device_queue_manager_uninit(struct device_queue_manager *dqm) { dqm->ops.stop(dqm); From efdc66fe12b07e7b7d28650bd8d4f7e3bb92c5d4 Mon Sep 17 00:00:00 2001 From: Srinivasan Shanmugam Date: Fri, 9 Jan 2026 18:01:23 +0530 Subject: [PATCH 31/69] drm/amdgpu: Refactor amdgpu_gem_va_ioctl for Handling Last Fence Update and Timeline Management v7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When GPU memory mappings are updated, the driver returns a fence so userspace knows when the update is finished. The previous refactor could pick the wrong fence or rely on checks that are not safe for GPU mappings that stay valid even when memory is missing. In some cases this could return an invalid fence or cause fence reference counting problems. Fix this by (v5,v6, per Christian): - Starting from the VM’s existing last update fence, so a valid and meaningful fence is always returned even when no new work is required. - Selecting the VM-level fence only for always-valid / PRT mappings using the required combined bo_va + bo guard. - Using the per-BO page table update fence for normal MAP and REPLACE operations. - For UNMAP and CLEAR, returning the fence provided by amdgpu_vm_clear_freed(), which may remain unchanged when nothing needs clearing. - Keeping fence reference counting balanced. v7: Drop the extra bo_va/bo NULL guard since amdgpu_vm_is_bo_always_valid() handles NULL BOs correctly (including PRT). (Christian) This makes VM timeline fences correct and prevents crashes caused by incorrect fence handling. Fixes: bd8150a1b337 ("drm/amdgpu: Refactor amdgpu_gem_va_ioctl for Handling Last Fence Update and Timeline Management v4") Suggested-by: Christian König Signed-off-by: Srinivasan Shanmugam Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 73 +++++++++++++------------ 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index ab899709c260..5f9fa2140f09 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -729,15 +729,23 @@ amdgpu_gem_va_update_vm(struct amdgpu_device *adev, struct amdgpu_bo_va *bo_va, uint32_t operation) { - struct dma_fence *clear_fence = dma_fence_get_stub(); - struct dma_fence *last_update = NULL; - int r; + struct dma_fence *fence; + int r = 0; + + /* Always start from the VM's existing last update fence. */ + fence = dma_fence_get(vm->last_update); if (!amdgpu_vm_ready(vm)) - return clear_fence; + return fence; - /* First clear freed BOs and get a fence for that work, if any. */ - r = amdgpu_vm_clear_freed(adev, vm, &clear_fence); + /* + * First clean up any freed mappings in the VM. + * + * amdgpu_vm_clear_freed() may replace @fence with a new fence if it + * schedules GPU work. If nothing needs clearing, @fence can remain as + * the original vm->last_update. + */ + r = amdgpu_vm_clear_freed(adev, vm, &fence); if (r) goto error; @@ -755,35 +763,38 @@ amdgpu_gem_va_update_vm(struct amdgpu_device *adev, goto error; /* - * Decide which fence represents the "last update" for this VM/BO: + * Decide which fence best represents the last update: * - * - For MAP/REPLACE we want the PT update fence, which is tracked as - * either vm->last_update (for always-valid BOs) or bo_va->last_pt_update - * (for per-BO updates). + * MAP/REPLACE: + * - For always-valid mappings, use vm->last_update. + * - Otherwise, export bo_va->last_pt_update. * - * - For UNMAP/CLEAR we rely on the fence returned by - * amdgpu_vm_clear_freed(), which already covers the page table work - * for the removed mappings. + * UNMAP/CLEAR: + * Keep the fence returned by amdgpu_vm_clear_freed(). If no work was + * needed, it can remain as vm->last_pt_update. + * + * The VM and BO update fences are always initialized to a valid value. + * vm->last_update and bo_va->last_pt_update always start as valid fences. + * and are never expected to be NULL. */ switch (operation) { case AMDGPU_VA_OP_MAP: case AMDGPU_VA_OP_REPLACE: - if (bo_va && bo_va->base.bo) { - if (amdgpu_vm_is_bo_always_valid(vm, bo_va->base.bo)) { - if (vm->last_update) - last_update = dma_fence_get(vm->last_update); - } else { - if (bo_va->last_pt_update) - last_update = dma_fence_get(bo_va->last_pt_update); - } - } + /* + * For MAP/REPLACE, return the page table update fence for the + * mapping we just modified. bo_va is expected to be valid here. + */ + dma_fence_put(fence); + + if (amdgpu_vm_is_bo_always_valid(vm, bo_va->base.bo)) + fence = dma_fence_get(vm->last_update); + else + fence = dma_fence_get(bo_va->last_pt_update); break; case AMDGPU_VA_OP_UNMAP: case AMDGPU_VA_OP_CLEAR: - if (clear_fence) - last_update = dma_fence_get(clear_fence); - break; default: + /* keep @fence as returned by amdgpu_vm_clear_freed() */ break; } @@ -791,17 +802,7 @@ amdgpu_gem_va_update_vm(struct amdgpu_device *adev, if (r && r != -ERESTARTSYS) DRM_ERROR("Couldn't update BO_VA (%d)\n", r); - /* - * If we managed to pick a more specific last-update fence, prefer it - * over the generic clear_fence and drop the extra reference to the - * latter. - */ - if (last_update) { - dma_fence_put(clear_fence); - return last_update; - } - - return clear_fence; + return fence; } int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, From 0f744593adecfa12ce7c4bfc4a6c2850458c4e88 Mon Sep 17 00:00:00 2001 From: Lang Yu Date: Fri, 19 Dec 2025 20:27:00 +0800 Subject: [PATCH 32/69] drm/amdgpu/mes: Simplify hqd mask initialization "adev->mes.compute_hqd_mask[i] = adev->gfx.disable_kq ? 0xF" is actually incorrect for MEC with 8 queues per pipe. Let's get rid of version check and hardcode, calculate hqd mask with number of queues per pipe and number of gfx/compute queues kernel used. Currently, only MEC1 is used for both kernel/user compute queue. To enable other MEC, we need to redistribute queues per pipe and adjust queue resource shared with kfd that needs a separate patch. Just skip other MEC for now to avoid potential issues. v2: Force reserved queues to 0 if kernel queue is explicitly disabled. Signed-off-by: Lang Yu Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c | 65 ++++++++++++++++--------- 1 file changed, 41 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c index dffa0f7276b7..6e19836c5ff6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -31,7 +31,6 @@ #define AMDGPU_MES_MAX_NUM_OF_QUEUES_PER_PROCESS 1024 #define AMDGPU_ONE_DOORBELL_SIZE 8 -#define AMDGPU_MES_RESERVED_QUEUES 2 int amdgpu_mes_doorbell_process_slice(struct amdgpu_device *adev) { @@ -89,12 +88,30 @@ static void amdgpu_mes_doorbell_free(struct amdgpu_device *adev) bitmap_free(adev->mes.doorbell_bitmap); } +static inline u32 amdgpu_mes_get_hqd_mask(u32 num_pipe, + u32 num_hqd_per_pipe, + u32 num_reserved_hqd) +{ + if (num_pipe == 0) + return 0; + + u32 total_hqd_mask = (u32)((1ULL << num_hqd_per_pipe) - 1); + u32 reserved_hqd_mask = (u32)((1ULL << DIV_ROUND_UP(num_reserved_hqd, num_pipe)) - 1); + + return (total_hqd_mask & ~reserved_hqd_mask); +} + int amdgpu_mes_init(struct amdgpu_device *adev) { int i, r, num_pipes; u32 total_vmid_mask, reserved_vmid_mask; - u32 queue_mask, reserved_queue_mask; int num_xcc = adev->gfx.xcc_mask ? NUM_XCC(adev->gfx.xcc_mask) : 1; + u32 gfx_hqd_mask = amdgpu_mes_get_hqd_mask(adev->gfx.me.num_pipe_per_me, + adev->gfx.me.num_queue_per_pipe, + adev->gfx.disable_kq ? 0 : adev->gfx.num_gfx_rings); + u32 compute_hqd_mask = amdgpu_mes_get_hqd_mask(adev->gfx.mec.num_pipe_per_mec, + adev->gfx.mec.num_queue_per_pipe, + adev->gfx.disable_kq ? 0 : adev->gfx.num_compute_rings); adev->mes.adev = adev; @@ -115,9 +132,6 @@ int amdgpu_mes_init(struct amdgpu_device *adev) adev->mes.vmid_mask_mmhub = 0xFF00; adev->mes.vmid_mask_gfxhub = total_vmid_mask & ~reserved_vmid_mask; - queue_mask = (u32)(1UL << adev->gfx.mec.num_queue_per_pipe) - 1; - reserved_queue_mask = (u32)(1UL << AMDGPU_MES_RESERVED_QUEUES) - 1; - num_pipes = adev->gfx.me.num_pipe_per_me * adev->gfx.me.num_me; if (num_pipes > AMDGPU_MES_MAX_GFX_PIPES) dev_warn(adev->dev, "more gfx pipes than supported by MES! (%d vs %d)\n", @@ -126,22 +140,8 @@ int amdgpu_mes_init(struct amdgpu_device *adev) for (i = 0; i < AMDGPU_MES_MAX_GFX_PIPES; i++) { if (i >= num_pipes) break; - if (amdgpu_ip_version(adev, GC_HWIP, 0) >= - IP_VERSION(12, 0, 0)) - /* - * GFX V12 has only one GFX pipe, but 8 queues in it. - * GFX pipe 0 queue 0 is being used by Kernel queue. - * Set GFX pipe 0 queue 1-7 for MES scheduling - * mask = 1111 1110b - */ - adev->mes.gfx_hqd_mask[i] = adev->gfx.disable_kq ? 0xFF : 0xFE; - else - /* - * GFX pipe 0 queue 0 is being used by Kernel queue. - * Set GFX pipe 0 queue 1 for MES scheduling - * mask = 10b - */ - adev->mes.gfx_hqd_mask[i] = adev->gfx.disable_kq ? 0x3 : 0x2; + + adev->mes.gfx_hqd_mask[i] = gfx_hqd_mask; } num_pipes = adev->gfx.mec.num_pipe_per_mec * adev->gfx.mec.num_mec; @@ -150,10 +150,16 @@ int amdgpu_mes_init(struct amdgpu_device *adev) num_pipes, AMDGPU_MES_MAX_COMPUTE_PIPES); for (i = 0; i < AMDGPU_MES_MAX_COMPUTE_PIPES; i++) { - if (i >= num_pipes) + /* + * Currently, only MEC1 is used for both kernel and user compute queue. + * To enable other MEC, we need to redistribute queues per pipe and + * adjust queue resource shared with kfd that needs a separate patch. + * Skip other MEC for now to avoid potential issues. + */ + if (i >= adev->gfx.mec.num_pipe_per_mec) break; - adev->mes.compute_hqd_mask[i] = - adev->gfx.disable_kq ? 0xF : (queue_mask & ~reserved_queue_mask); + + adev->mes.compute_hqd_mask[i] = compute_hqd_mask; } num_pipes = adev->sdma.num_instances; @@ -167,6 +173,17 @@ int amdgpu_mes_init(struct amdgpu_device *adev) adev->mes.sdma_hqd_mask[i] = 0xfc; } + dev_info(adev->dev, + "MES: vmid_mask_mmhub 0x%08x, vmid_mask_gfxhub 0x%08x\n", + adev->mes.vmid_mask_mmhub, + adev->mes.vmid_mask_gfxhub); + + dev_info(adev->dev, + "MES: gfx_hqd_mask 0x%08x, compute_hqd_mask 0x%08x, sdma_hqd_mask 0x%08x\n", + adev->mes.gfx_hqd_mask[0], + adev->mes.compute_hqd_mask[0], + adev->mes.sdma_hqd_mask[0]); + for (i = 0; i < AMDGPU_MAX_MES_PIPES * num_xcc; i++) { r = amdgpu_device_wb_get(adev, &adev->mes.sch_ctx_offs[i]); if (r) { From 1e5cd4adfc547bc0d0d69896e7696b96697ad0aa Mon Sep 17 00:00:00 2001 From: Peichen Huang Date: Tue, 9 Dec 2025 10:47:06 +0800 Subject: [PATCH 33/69] drm/amd/display: move panel replay out from edp [WHY] Panel Replay is not an eDP-specific function. [HOW] Create new Panel Replay source files and move the Panel Replay functions from the eDP files to the new files. Additionally, create a new link_service construct function to assign the related function pointers. Reviewed-by: Robin Chen Signed-off-by: Peichen Huang Signed-off-by: Matthew Stewart Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../amd/display/amdgpu_dm/amdgpu_dm_replay.c | 2 +- .../drm/amd/display/dc/core/dc_link_exports.c | 9 +- .../gpu/drm/amd/display/dc/inc/link_service.h | 10 +- drivers/gpu/drm/amd/display/dc/link/Makefile | 2 +- .../drm/amd/display/dc/link/link_factory.c | 18 +- .../dc/link/protocols/link_dp_irq_handler.c | 1 + .../dc/link/protocols/link_dp_panel_replay.c | 308 ++++++++++++++++++ .../dc/link/protocols/link_dp_panel_replay.h | 38 +++ .../link/protocols/link_edp_panel_control.c | 271 +-------------- .../link/protocols/link_edp_panel_control.h | 8 +- 10 files changed, 373 insertions(+), 294 deletions(-) create mode 100644 drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.c create mode 100644 drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.h diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c index da94e3544b65..fb619a3336b7 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c @@ -161,7 +161,7 @@ bool amdgpu_dm_replay_enable(struct dc_stream_state *stream, bool wait) link = stream->link; if (link) { - link->dc->link_srv->edp_setup_replay(link, stream); + link->dc->link_srv->dp_setup_replay(link, stream); link->dc->link_srv->edp_set_coasting_vtotal(link, stream->timing.v_total, 0); DRM_DEBUG_DRIVER("Enabling replay...\n"); link->dc->link_srv->edp_set_replay_allow_active(link, &replay_active, wait, false, NULL); diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c index a8d7228907c2..7bb4504889be 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c @@ -493,24 +493,24 @@ bool dc_link_get_replay_state(const struct dc_link *link, uint64_t *state) bool dc_link_set_pr_enable(struct dc_link *link, bool enable) { - return link->dc->link_srv->edp_pr_enable(link, enable); + return link->dc->link_srv->dp_pr_enable(link, enable); } bool dc_link_update_pr_state(struct dc_link *link, struct dmub_cmd_pr_update_state_data *update_state_data) { - return link->dc->link_srv->edp_pr_update_state(link, update_state_data); + return link->dc->link_srv->dp_pr_update_state(link, update_state_data); } bool dc_link_set_pr_general_cmd(struct dc_link *link, struct dmub_cmd_pr_general_cmd_data *general_cmd_data) { - return link->dc->link_srv->edp_pr_set_general_cmd(link, general_cmd_data); + return link->dc->link_srv->dp_pr_set_general_cmd(link, general_cmd_data); } bool dc_link_get_pr_state(const struct dc_link *link, uint64_t *state) { - return link->dc->link_srv->edp_pr_get_state(link, state); + return link->dc->link_srv->dp_pr_get_state(link, state); } bool dc_link_wait_for_t12(struct dc_link *link) @@ -549,4 +549,3 @@ void dc_link_get_alpm_support(struct dc_link *link, { link->dc->link_srv->edp_get_alpm_support(link, auxless_support, auxwake_support); } - diff --git a/drivers/gpu/drm/amd/display/dc/inc/link_service.h b/drivers/gpu/drm/amd/display/dc/inc/link_service.h index 4b092a9ee4c6..5885b4abdf38 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/link_service.h +++ b/drivers/gpu/drm/amd/display/dc/inc/link_service.h @@ -283,7 +283,7 @@ struct link_service { bool (*edp_set_replay_allow_active)(struct dc_link *dc_link, const bool *enable, bool wait, bool force_static, const unsigned int *power_opts); - bool (*edp_setup_replay)(struct dc_link *link, + bool (*dp_setup_replay)(struct dc_link *link, const struct dc_stream_state *stream); bool (*edp_send_replay_cmd)(struct dc_link *link, enum replay_FW_Message_type msg, @@ -304,10 +304,10 @@ struct link_service { bool (*edp_receiver_ready_T9)(struct dc_link *link); bool (*edp_receiver_ready_T7)(struct dc_link *link); bool (*edp_power_alpm_dpcd_enable)(struct dc_link *link, bool enable); - bool (*edp_pr_enable)(struct dc_link *link, bool enable); - bool (*edp_pr_update_state)(struct dc_link *link, struct dmub_cmd_pr_update_state_data *update_state_data); - bool (*edp_pr_set_general_cmd)(struct dc_link *link, struct dmub_cmd_pr_general_cmd_data *general_cmd_data); - bool (*edp_pr_get_state)(const struct dc_link *link, uint64_t *state); + bool (*dp_pr_enable)(struct dc_link *link, bool enable); + bool (*dp_pr_update_state)(struct dc_link *link, struct dmub_cmd_pr_update_state_data *update_state_data); + bool (*dp_pr_set_general_cmd)(struct dc_link *link, struct dmub_cmd_pr_general_cmd_data *general_cmd_data); + bool (*dp_pr_get_state)(const struct dc_link *link, uint64_t *state); void (*edp_set_panel_power)(struct dc_link *link, bool powerOn); diff --git a/drivers/gpu/drm/amd/display/dc/link/Makefile b/drivers/gpu/drm/amd/display/dc/link/Makefile index 84c7af5fa589..84dace27daf7 100644 --- a/drivers/gpu/drm/amd/display/dc/link/Makefile +++ b/drivers/gpu/drm/amd/display/dc/link/Makefile @@ -56,7 +56,7 @@ LINK_PROTOCOLS = link_hpd.o link_ddc.o link_dpcd.o link_dp_dpia.o \ link_dp_training.o link_dp_training_8b_10b.o link_dp_training_128b_132b.o \ link_dp_training_dpia.o link_dp_training_auxless.o \ link_dp_training_fixed_vs_pe_retimer.o link_dp_phy.o link_dp_capability.o \ -link_edp_panel_control.o link_dp_irq_handler.o link_dp_dpia_bw.o +link_edp_panel_control.o link_dp_panel_replay.o link_dp_irq_handler.o link_dp_dpia_bw.o AMD_DAL_LINK_PROTOCOLS = $(addprefix $(AMDDALPATH)/dc/link/protocols/, \ $(LINK_PROTOCOLS)) diff --git a/drivers/gpu/drm/amd/display/dc/link/link_factory.c b/drivers/gpu/drm/amd/display/dc/link/link_factory.c index 923517715651..e185f2caad0c 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_factory.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_factory.c @@ -41,6 +41,7 @@ #include "protocols/link_dp_phy.h" #include "protocols/link_dp_training.h" #include "protocols/link_edp_panel_control.h" +#include "protocols/link_dp_panel_replay.h" #include "protocols/link_hpd.h" #include "gpio_service_interface.h" #include "atomfirmware.h" @@ -214,7 +215,6 @@ static void construct_link_service_edp_panel_control(struct link_service *link_s link_srv->edp_get_replay_state = edp_get_replay_state; link_srv->edp_set_replay_allow_active = edp_set_replay_allow_active; - link_srv->edp_setup_replay = edp_setup_replay; link_srv->edp_send_replay_cmd = edp_send_replay_cmd; link_srv->edp_set_coasting_vtotal = edp_set_coasting_vtotal; link_srv->edp_replay_residency = edp_replay_residency; @@ -228,13 +228,20 @@ static void construct_link_service_edp_panel_control(struct link_service *link_s link_srv->edp_receiver_ready_T9 = edp_receiver_ready_T9; link_srv->edp_receiver_ready_T7 = edp_receiver_ready_T7; link_srv->edp_power_alpm_dpcd_enable = edp_power_alpm_dpcd_enable; - link_srv->edp_pr_enable = edp_pr_enable; - link_srv->edp_pr_update_state = edp_pr_update_state; - link_srv->edp_pr_set_general_cmd = edp_pr_set_general_cmd; - link_srv->edp_pr_get_state = edp_pr_get_state; link_srv->edp_set_panel_power = edp_set_panel_power; } +/* link dp panel replay implements DP panel replay functionality. + */ +static void construct_link_service_dp_panel_replay(struct link_service *link_srv) +{ + link_srv->dp_setup_replay = dp_setup_replay; + link_srv->dp_pr_enable = dp_pr_enable; + link_srv->dp_pr_update_state = dp_pr_update_state; + link_srv->dp_pr_set_general_cmd = dp_pr_set_general_cmd; + link_srv->dp_pr_get_state = dp_pr_get_state; +} + /* link dp cts implements dp compliance test automation protocols and manual * testing interfaces for debugging and certification purpose. */ @@ -287,6 +294,7 @@ static void construct_link_service(struct link_service *link_srv) construct_link_service_dp_phy_or_dpia(link_srv); construct_link_service_dp_irq_handler(link_srv); construct_link_service_edp_panel_control(link_srv); + construct_link_service_dp_panel_replay(link_srv); construct_link_service_dp_cts(link_srv); construct_link_service_dp_trace(link_srv); } diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c index 4b01ab0a5a7f..47abd3ec69b3 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c @@ -38,6 +38,7 @@ #include "link/link_dpms.h" #include "dm_helpers.h" #include "link_dp_dpia_bw.h" +#include "link_dp_panel_replay.h" #define DC_LOGGER \ link->ctx->logger diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.c new file mode 100644 index 000000000000..3168c42d662c --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.c @@ -0,0 +1,308 @@ +/* + * Copyright 2025 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. + * + * Authors: AMD + * + */ + +#include "link_dp_panel_replay.h" +#include "link_edp_panel_control.h" +#include "link_dpcd.h" +#include "dm_helpers.h" +#include "dc/dc_dmub_srv.h" +#include "dce/dmub_replay.h" + +#define DC_LOGGER \ + link->ctx->logger + +#define DP_SINK_PR_ENABLE_AND_CONFIGURATION 0x37B + +static bool dp_setup_panel_replay(struct dc_link *link, const struct dc_stream_state *stream) +{ + /* To-do: Setup Replay */ + struct dc *dc; + struct dmub_replay *replay; + int i; + unsigned int panel_inst; + struct replay_context replay_context = { 0 }; + unsigned int lineTimeInNs = 0; + + union panel_replay_enable_and_configuration_1 pr_config_1 = { 0 }; + union panel_replay_enable_and_configuration_2 pr_config_2 = { 0 }; + + union dpcd_alpm_configuration alpm_config; + + replay_context.controllerId = CONTROLLER_ID_UNDEFINED; + + if (!link) + return false; + + //Clear Panel Replay enable & config + dm_helpers_dp_write_dpcd(link->ctx, link, + DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_1, + (uint8_t *)&(pr_config_1.raw), sizeof(uint8_t)); + + dm_helpers_dp_write_dpcd(link->ctx, link, + DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_2, + (uint8_t *)&(pr_config_2.raw), sizeof(uint8_t)); + + if (!(link->replay_settings.config.replay_supported)) + return false; + + dc = link->ctx->dc; + + //not sure should keep or not + replay = dc->res_pool->replay; + + if (!replay) + return false; + + if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) + return false; + + replay_context.aux_inst = link->ddc->ddc_pin->hw_info.ddc_channel; + replay_context.digbe_inst = link->link_enc->transmitter; + replay_context.digfe_inst = link->link_enc->preferred_engine; + + for (i = 0; i < MAX_PIPES; i++) { + if (dc->current_state->res_ctx.pipe_ctx[i].stream + == stream) { + /* dmcu -1 for all controller id values, + * therefore +1 here + */ + replay_context.controllerId = + dc->current_state->res_ctx.pipe_ctx[i].stream_res.tg->inst + 1; + break; + } + } + + lineTimeInNs = + ((stream->timing.h_total * 1000000) / + (stream->timing.pix_clk_100hz / 10)) + 1; + + replay_context.line_time_in_ns = lineTimeInNs; + + link->replay_settings.replay_feature_enabled = dp_pr_copy_settings(link, &replay_context); + + if (link->replay_settings.replay_feature_enabled) { + pr_config_1.bits.PANEL_REPLAY_ENABLE = 1; + pr_config_1.bits.PANEL_REPLAY_CRC_ENABLE = 1; + pr_config_1.bits.IRQ_HPD_ASSDP_MISSING = 1; + pr_config_1.bits.IRQ_HPD_VSCSDP_UNCORRECTABLE_ERROR = 1; + pr_config_1.bits.IRQ_HPD_RFB_ERROR = 1; + pr_config_1.bits.IRQ_HPD_ACTIVE_FRAME_CRC_ERROR = 1; + pr_config_1.bits.PANEL_REPLAY_SELECTIVE_UPDATE_ENABLE = 1; + pr_config_1.bits.PANEL_REPLAY_EARLY_TRANSPORT_ENABLE = 1; + + pr_config_2.bits.SINK_REFRESH_RATE_UNLOCK_GRANTED = 0; + pr_config_2.bits.SU_Y_GRANULARITY_EXT_VALUE_ENABLED = 0; + pr_config_2.bits.SU_REGION_SCAN_LINE_CAPTURE_INDICATION = 0; + + dm_helpers_dp_write_dpcd(link->ctx, link, + DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_1, + (uint8_t *)&(pr_config_1.raw), sizeof(uint8_t)); + + dm_helpers_dp_write_dpcd(link->ctx, link, + DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_2, + (uint8_t *)&(pr_config_2.raw), sizeof(uint8_t)); + + //ALPM Setup + memset(&alpm_config, 0, sizeof(alpm_config)); + alpm_config.bits.ENABLE = link->replay_settings.config.alpm_mode != DC_ALPM_UNSUPPORTED ? 1 : 0; + + if (link->replay_settings.config.alpm_mode == DC_ALPM_AUXLESS) { + alpm_config.bits.ALPM_MODE_SEL = 1; + alpm_config.bits.ACDS_PERIOD_DURATION = 1; + } + + dm_helpers_dp_write_dpcd( + link->ctx, + link, + DP_RECEIVER_ALPM_CONFIG, + &alpm_config.raw, + sizeof(alpm_config.raw)); + } + + return true; +} + +bool dp_setup_replay(struct dc_link *link, const struct dc_stream_state *stream) +{ + if (!link) + return false; + if (link->replay_settings.config.replay_version == DC_VESA_PANEL_REPLAY) + return dp_setup_panel_replay(link, stream); + else if (link->replay_settings.config.replay_version == DC_FREESYNC_REPLAY) + return edp_setup_freesync_replay(link, stream); + else + return false; +} + +bool dp_pr_enable(struct dc_link *link, bool enable) +{ + struct dc *dc = link->ctx->dc; + unsigned int panel_inst = 0; + union dmub_rb_cmd cmd; + + if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) + return false; + + if (link->replay_settings.replay_allow_active != enable) { + //for sending PR enable commands to DMUB + memset(&cmd, 0, sizeof(cmd)); + + cmd.pr_enable.header.type = DMUB_CMD__PR; + cmd.pr_enable.header.sub_type = DMUB_CMD__PR_ENABLE; + cmd.pr_enable.header.payload_bytes = sizeof(struct dmub_cmd_pr_enable_data); + cmd.pr_enable.data.panel_inst = panel_inst; + cmd.pr_enable.data.enable = enable ? 1 : 0; + + dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + + link->replay_settings.replay_allow_active = enable; + } + return true; +} + +bool dp_pr_copy_settings(struct dc_link *link, struct replay_context *replay_context) +{ + struct dc *dc = link->ctx->dc; + unsigned int panel_inst = 0; + union dmub_rb_cmd cmd; + struct pipe_ctx *pipe_ctx = NULL; + + if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) + return false; + + for (unsigned int i = 0; i < MAX_PIPES; i++) { + if (dc->current_state->res_ctx.pipe_ctx[i].stream && + dc->current_state->res_ctx.pipe_ctx[i].stream->link && + dc->current_state->res_ctx.pipe_ctx[i].stream->link == link && + dc->current_state->res_ctx.pipe_ctx[i].stream->link->connector_signal == SIGNAL_TYPE_EDP) { + pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; + //TODO: refactor for multi edp support + break; + } + } + + if (!pipe_ctx) + return false; + + memset(&cmd, 0, sizeof(cmd)); + cmd.pr_copy_settings.header.type = DMUB_CMD__PR; + cmd.pr_copy_settings.header.sub_type = DMUB_CMD__PR_COPY_SETTINGS; + cmd.pr_copy_settings.header.payload_bytes = sizeof(struct dmub_cmd_pr_copy_settings_data); + cmd.pr_copy_settings.data.panel_inst = panel_inst; + // HW inst + cmd.pr_copy_settings.data.aux_inst = replay_context->aux_inst; + cmd.pr_copy_settings.data.digbe_inst = replay_context->digbe_inst; + cmd.pr_copy_settings.data.digfe_inst = replay_context->digfe_inst; + if (pipe_ctx->plane_res.dpp) + cmd.pr_copy_settings.data.dpp_inst = pipe_ctx->plane_res.dpp->inst; + else + cmd.pr_copy_settings.data.dpp_inst = 0; + if (pipe_ctx->stream_res.tg) + cmd.pr_copy_settings.data.otg_inst = pipe_ctx->stream_res.tg->inst; + else + cmd.pr_copy_settings.data.otg_inst = 0; + + cmd.pr_copy_settings.data.dpphy_inst = link->link_enc->transmitter; + + cmd.pr_copy_settings.data.line_time_in_ns = replay_context->line_time_in_ns; + cmd.pr_copy_settings.data.flags.bitfields.fec_enable_status = (link->fec_state == dc_link_fec_enabled); + cmd.pr_copy_settings.data.flags.bitfields.dsc_enable_status = (pipe_ctx->stream->timing.flags.DSC == 1); + cmd.pr_copy_settings.data.debug.u32All = link->replay_settings.config.debug_flags; + + dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + return true; +} + +bool dp_pr_update_state(struct dc_link *link, struct dmub_cmd_pr_update_state_data *update_state_data) +{ + struct dc *dc = link->ctx->dc; + unsigned int panel_inst = 0; + union dmub_rb_cmd cmd; + + if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) + return false; + + memset(&cmd, 0, sizeof(cmd)); + cmd.pr_update_state.header.type = DMUB_CMD__PR; + cmd.pr_update_state.header.sub_type = DMUB_CMD__PR_UPDATE_STATE; + cmd.pr_update_state.header.payload_bytes = sizeof(struct dmub_cmd_pr_update_state_data); + cmd.pr_update_state.data.panel_inst = panel_inst; + + memcpy(&cmd.pr_update_state.data, update_state_data, sizeof(struct dmub_cmd_pr_update_state_data)); + + dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + return true; +} + +bool dp_pr_set_general_cmd(struct dc_link *link, struct dmub_cmd_pr_general_cmd_data *general_cmd_data) +{ + struct dc *dc = link->ctx->dc; + unsigned int panel_inst = 0; + union dmub_rb_cmd cmd; + + if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) + return false; + + memset(&cmd, 0, sizeof(cmd)); + cmd.pr_general_cmd.header.type = DMUB_CMD__PR; + cmd.pr_general_cmd.header.sub_type = DMUB_CMD__PR_GENERAL_CMD; + cmd.pr_general_cmd.header.payload_bytes = sizeof(struct dmub_cmd_pr_general_cmd_data); + cmd.pr_general_cmd.data.panel_inst = panel_inst; + + memcpy(&cmd.pr_general_cmd.data, general_cmd_data, sizeof(struct dmub_cmd_pr_general_cmd_data)); + + dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + return true; +} + +bool dp_pr_get_state(const struct dc_link *link, uint64_t *state) +{ + const struct dc *dc = link->ctx->dc; + unsigned int panel_inst = 0; + uint32_t retry_count = 0; + uint32_t replay_state = 0; + + if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) + return false; + + do { + // Send gpint command and wait for ack + if (!dc_wake_and_execute_gpint(dc->ctx, DMUB_GPINT__GET_REPLAY_STATE, panel_inst, + &replay_state, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)) { + // Return invalid state when GPINT times out + replay_state = PR_STATE_INVALID; + } + /* Copy 32-bit result into 64-bit output */ + *state = replay_state; + } while (++retry_count <= 1000 && *state == PR_STATE_INVALID); + + // Assert if max retry hit + if (retry_count >= 1000 && *state == PR_STATE_INVALID) { + ASSERT(0); + /* To-do: Add retry fail log */ + } + + return true; +} diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.h new file mode 100644 index 000000000000..b936092edb85 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.h @@ -0,0 +1,38 @@ +/* + * Copyright 2025 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. + * + * Authors: AMD + * + */ +#ifndef __DC_LINK_DP_PANEL_REPLAY_H__ +#define __DC_LINK_DP_PANEL_REPLAY_H__ + +#include "link_service.h" + +bool dp_setup_replay(struct dc_link *link, + const struct dc_stream_state *stream); +bool dp_pr_enable(struct dc_link *link, bool enable); +bool dp_pr_copy_settings(struct dc_link *link, struct replay_context *replay_context); +bool dp_pr_update_state(struct dc_link *link, struct dmub_cmd_pr_update_state_data *update_state_data); +bool dp_pr_set_general_cmd(struct dc_link *link, struct dmub_cmd_pr_general_cmd_data *general_cmd_data); +bool dp_pr_get_state(const struct dc_link *link, uint64_t *state); + +#endif /* __DC_LINK_DP_PANEL_REPLAY_H__ */ \ No newline at end of file diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c index d6e91da72ef8..ab047ff556a1 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c @@ -1003,116 +1003,8 @@ bool edp_get_replay_state(const struct dc_link *link, uint64_t *state) return true; } -static bool edp_setup_panel_replay(struct dc_link *link, const struct dc_stream_state *stream) -{ - /* To-do: Setup Replay */ - struct dc *dc; - struct dmub_replay *replay; - int i; - unsigned int panel_inst; - struct replay_context replay_context = { 0 }; - unsigned int lineTimeInNs = 0; - union panel_replay_enable_and_configuration_1 pr_config_1 = { 0 }; - union panel_replay_enable_and_configuration_2 pr_config_2 = { 0 }; - - union dpcd_alpm_configuration alpm_config; - - replay_context.controllerId = CONTROLLER_ID_UNDEFINED; - - if (!link) - return false; - - //Clear Panel Replay enable & config - dm_helpers_dp_write_dpcd(link->ctx, link, - DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_1, - (uint8_t *)&(pr_config_1.raw), sizeof(uint8_t)); - - dm_helpers_dp_write_dpcd(link->ctx, link, - DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_2, - (uint8_t *)&(pr_config_2.raw), sizeof(uint8_t)); - - if (!(link->replay_settings.config.replay_supported)) - return false; - - dc = link->ctx->dc; - - //not sure should keep or not - replay = dc->res_pool->replay; - - if (!replay) - return false; - - if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) - return false; - - replay_context.aux_inst = link->ddc->ddc_pin->hw_info.ddc_channel; - replay_context.digbe_inst = link->link_enc->transmitter; - replay_context.digfe_inst = link->link_enc->preferred_engine; - - for (i = 0; i < MAX_PIPES; i++) { - if (dc->current_state->res_ctx.pipe_ctx[i].stream - == stream) { - /* dmcu -1 for all controller id values, - * therefore +1 here - */ - replay_context.controllerId = - dc->current_state->res_ctx.pipe_ctx[i].stream_res.tg->inst + 1; - break; - } - } - - lineTimeInNs = - ((stream->timing.h_total * 1000000) / - (stream->timing.pix_clk_100hz / 10)) + 1; - - replay_context.line_time_in_ns = lineTimeInNs; - - link->replay_settings.replay_feature_enabled = edp_pr_copy_settings(link, &replay_context); - - if (link->replay_settings.replay_feature_enabled) { - pr_config_1.bits.PANEL_REPLAY_ENABLE = 1; - pr_config_1.bits.PANEL_REPLAY_CRC_ENABLE = 1; - pr_config_1.bits.IRQ_HPD_ASSDP_MISSING = 1; - pr_config_1.bits.IRQ_HPD_VSCSDP_UNCORRECTABLE_ERROR = 1; - pr_config_1.bits.IRQ_HPD_RFB_ERROR = 1; - pr_config_1.bits.IRQ_HPD_ACTIVE_FRAME_CRC_ERROR = 1; - pr_config_1.bits.PANEL_REPLAY_SELECTIVE_UPDATE_ENABLE = 1; - pr_config_1.bits.PANEL_REPLAY_EARLY_TRANSPORT_ENABLE = 1; - - pr_config_2.bits.SINK_REFRESH_RATE_UNLOCK_GRANTED = 0; - pr_config_2.bits.SU_Y_GRANULARITY_EXT_VALUE_ENABLED = 0; - pr_config_2.bits.SU_REGION_SCAN_LINE_CAPTURE_INDICATION = 0; - - dm_helpers_dp_write_dpcd(link->ctx, link, - DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_1, - (uint8_t *)&(pr_config_1.raw), sizeof(uint8_t)); - - dm_helpers_dp_write_dpcd(link->ctx, link, - DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_2, - (uint8_t *)&(pr_config_2.raw), sizeof(uint8_t)); - - //ALPM Setup - memset(&alpm_config, 0, sizeof(alpm_config)); - alpm_config.bits.ENABLE = link->replay_settings.config.alpm_mode != DC_ALPM_UNSUPPORTED ? 1 : 0; - - if (link->replay_settings.config.alpm_mode == DC_ALPM_AUXLESS) { - alpm_config.bits.ALPM_MODE_SEL = 1; - alpm_config.bits.ACDS_PERIOD_DURATION = 1; - } - - dm_helpers_dp_write_dpcd( - link->ctx, - link, - DP_RECEIVER_ALPM_CONFIG, - &alpm_config.raw, - sizeof(alpm_config.raw)); - } - - return true; -} - -static bool edp_setup_freesync_replay(struct dc_link *link, const struct dc_stream_state *stream) +bool edp_setup_freesync_replay(struct dc_link *link, const struct dc_stream_state *stream) { /* To-do: Setup Replay */ struct dc *dc; @@ -1208,17 +1100,6 @@ static bool edp_setup_freesync_replay(struct dc_link *link, const struct dc_stre return true; } -bool edp_setup_replay(struct dc_link *link, const struct dc_stream_state *stream) -{ - if (!link) - return false; - if (link->replay_settings.config.replay_version == DC_VESA_PANEL_REPLAY) - return edp_setup_panel_replay(link, stream); - else if (link->replay_settings.config.replay_version == DC_FREESYNC_REPLAY) - return edp_setup_freesync_replay(link, stream); - else - return false; -} /* * This is general Interface for Replay to set an 32 bit variable to dmub @@ -1323,156 +1204,6 @@ bool edp_set_replay_power_opt_and_coasting_vtotal(struct dc_link *link, return true; } -bool edp_pr_enable(struct dc_link *link, bool enable) -{ - struct dc *dc = link->ctx->dc; - unsigned int panel_inst = 0; - union dmub_rb_cmd cmd; - - if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) - return false; - - if (link->replay_settings.replay_allow_active != enable) { - //for sending PR enable commands to DMUB - memset(&cmd, 0, sizeof(cmd)); - - cmd.pr_enable.header.type = DMUB_CMD__PR; - cmd.pr_enable.header.sub_type = DMUB_CMD__PR_ENABLE; - cmd.pr_enable.header.payload_bytes = sizeof(struct dmub_cmd_pr_enable_data); - cmd.pr_enable.data.panel_inst = panel_inst; - cmd.pr_enable.data.enable = enable ? 1 : 0; - - dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); - - link->replay_settings.replay_allow_active = enable; - } - return true; -} - -bool edp_pr_copy_settings(struct dc_link *link, struct replay_context *replay_context) -{ - struct dc *dc = link->ctx->dc; - unsigned int panel_inst = 0; - union dmub_rb_cmd cmd; - struct pipe_ctx *pipe_ctx = NULL; - - if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) - return false; - - for (unsigned int i = 0; i < MAX_PIPES; i++) { - if (dc->current_state->res_ctx.pipe_ctx[i].stream && - dc->current_state->res_ctx.pipe_ctx[i].stream->link && - dc->current_state->res_ctx.pipe_ctx[i].stream->link == link && - dc->current_state->res_ctx.pipe_ctx[i].stream->link->connector_signal == SIGNAL_TYPE_EDP) { - pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; - //TODO: refactor for multi edp support - break; - } - } - - if (!pipe_ctx) - return false; - - memset(&cmd, 0, sizeof(cmd)); - cmd.pr_copy_settings.header.type = DMUB_CMD__PR; - cmd.pr_copy_settings.header.sub_type = DMUB_CMD__PR_COPY_SETTINGS; - cmd.pr_copy_settings.header.payload_bytes = sizeof(struct dmub_cmd_pr_copy_settings_data); - cmd.pr_copy_settings.data.panel_inst = panel_inst; - // HW inst - cmd.pr_copy_settings.data.aux_inst = replay_context->aux_inst; - cmd.pr_copy_settings.data.digbe_inst = replay_context->digbe_inst; - cmd.pr_copy_settings.data.digfe_inst = replay_context->digfe_inst; - if (pipe_ctx->plane_res.dpp) - cmd.pr_copy_settings.data.dpp_inst = pipe_ctx->plane_res.dpp->inst; - else - cmd.pr_copy_settings.data.dpp_inst = 0; - if (pipe_ctx->stream_res.tg) - cmd.pr_copy_settings.data.otg_inst = pipe_ctx->stream_res.tg->inst; - else - cmd.pr_copy_settings.data.otg_inst = 0; - - cmd.pr_copy_settings.data.dpphy_inst = link->link_enc->transmitter; - - cmd.pr_copy_settings.data.line_time_in_ns = replay_context->line_time_in_ns; - cmd.pr_copy_settings.data.flags.bitfields.fec_enable_status = (link->fec_state == dc_link_fec_enabled); - cmd.pr_copy_settings.data.flags.bitfields.dsc_enable_status = (pipe_ctx->stream->timing.flags.DSC == 1); - cmd.pr_copy_settings.data.debug.u32All = link->replay_settings.config.debug_flags; - - dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); - return true; -} - -bool edp_pr_update_state(struct dc_link *link, struct dmub_cmd_pr_update_state_data *update_state_data) -{ - struct dc *dc = link->ctx->dc; - unsigned int panel_inst = 0; - union dmub_rb_cmd cmd; - - if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) - return false; - - memset(&cmd, 0, sizeof(cmd)); - cmd.pr_update_state.header.type = DMUB_CMD__PR; - cmd.pr_update_state.header.sub_type = DMUB_CMD__PR_UPDATE_STATE; - cmd.pr_update_state.header.payload_bytes = sizeof(struct dmub_cmd_pr_update_state_data); - cmd.pr_update_state.data.panel_inst = panel_inst; - - memcpy(&cmd.pr_update_state.data, update_state_data, sizeof(struct dmub_cmd_pr_update_state_data)); - - dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); - return true; -} - -bool edp_pr_set_general_cmd(struct dc_link *link, struct dmub_cmd_pr_general_cmd_data *general_cmd_data) -{ - struct dc *dc = link->ctx->dc; - unsigned int panel_inst = 0; - union dmub_rb_cmd cmd; - - if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) - return false; - - memset(&cmd, 0, sizeof(cmd)); - cmd.pr_general_cmd.header.type = DMUB_CMD__PR; - cmd.pr_general_cmd.header.sub_type = DMUB_CMD__PR_GENERAL_CMD; - cmd.pr_general_cmd.header.payload_bytes = sizeof(struct dmub_cmd_pr_general_cmd_data); - cmd.pr_general_cmd.data.panel_inst = panel_inst; - - memcpy(&cmd.pr_general_cmd.data, general_cmd_data, sizeof(struct dmub_cmd_pr_general_cmd_data)); - - dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); - return true; -} - -bool edp_pr_get_state(const struct dc_link *link, uint64_t *state) -{ - const struct dc *dc = link->ctx->dc; - unsigned int panel_inst = 0; - uint32_t retry_count = 0; - uint32_t replay_state = 0; - - if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) - return false; - - do { - // Send gpint command and wait for ack - if (!dc_wake_and_execute_gpint(dc->ctx, DMUB_GPINT__GET_REPLAY_STATE, panel_inst, - &replay_state, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)) { - // Return invalid state when GPINT times out - replay_state = PR_STATE_INVALID; - } - /* Copy 32-bit result into 64-bit output */ - *state = replay_state; - } while (++retry_count <= 1000 && *state == PR_STATE_INVALID); - - // Assert if max retry hit - if (retry_count >= 1000 && *state == PR_STATE_INVALID) { - ASSERT(0); - /* To-do: Add retry fail log */ - } - - return true; -} static struct abm *get_abm_from_stream_res(const struct dc_link *link) { diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h index fd63b5d0f948..8780bbc4e8c5 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h @@ -54,8 +54,6 @@ bool edp_set_sink_vtotal_in_psr_active(const struct dc_link *link, void edp_get_psr_residency(const struct dc_link *link, uint32_t *residency, enum psr_residency_mode mode); bool edp_set_replay_allow_active(struct dc_link *dc_link, const bool *enable, bool wait, bool force_static, const unsigned int *power_opts); -bool edp_setup_replay(struct dc_link *link, - const struct dc_stream_state *stream); bool edp_send_replay_cmd(struct dc_link *link, enum replay_FW_Message_type msg, union dmub_replay_cmd_set *cmd_data); @@ -75,11 +73,7 @@ void edp_add_delay_for_T9(struct dc_link *link); bool edp_receiver_ready_T9(struct dc_link *link); bool edp_receiver_ready_T7(struct dc_link *link); bool edp_power_alpm_dpcd_enable(struct dc_link *link, bool enable); -bool edp_pr_enable(struct dc_link *link, bool enable); -bool edp_pr_copy_settings(struct dc_link *link, struct replay_context *replay_context); -bool edp_pr_update_state(struct dc_link *link, struct dmub_cmd_pr_update_state_data *update_state_data); -bool edp_pr_set_general_cmd(struct dc_link *link, struct dmub_cmd_pr_general_cmd_data *general_cmd_data); -bool edp_pr_get_state(const struct dc_link *link, uint64_t *state); +bool edp_setup_freesync_replay(struct dc_link *link, const struct dc_stream_state *stream); void edp_set_panel_power(struct dc_link *link, bool powerOn); void edp_set_panel_assr(struct dc_link *link, struct pipe_ctx *pipe_ctx, enum dp_panel_mode *panel_mode, bool enable); From 872818e2357b026462b21e90aad115aa369966ba Mon Sep 17 00:00:00 2001 From: Joshua Aberback Date: Fri, 12 Dec 2025 04:23:03 -0500 Subject: [PATCH 34/69] drm/amd/display: Re-implement minimal transition deferral [Why] The update v3 path got refactored into new functions, which happened just before the previous implementation was submitted, which resulted in the optimizations not executing. This commit re-implements the same logic in the new codepath. Reviewed-by: Aric Cyr Signed-off-by: Joshua Aberback Signed-off-by: Matthew Stewart Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 49 ++++++++++++++++-------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 57f6a4c8afff..aba5ad2a7a33 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -7246,6 +7246,14 @@ static bool update_planes_and_stream_prepare_v3_intermediate_seamless( ); } +static void transition_countdown_init(struct dc *dc) +{ + dc->check_config.transition_countdown_to_steady_state = + dc->debug.num_fast_flips_to_steady_state_override ? + dc->debug.num_fast_flips_to_steady_state_override : + NUM_FAST_FLIPS_TO_STEADY_STATE; +} + static bool update_planes_and_stream_prepare_v3( struct dc_update_scratch_space *scratch ) @@ -7305,9 +7313,17 @@ static bool update_planes_and_stream_prepare_v3( ); if (seamless) { scratch->flow = UPDATE_V3_FLOW_NEW_CONTEXT_SEAMLESS; + if (scratch->dc->check_config.deferred_transition_state) + /* reset countdown as steady state not reached */ + transition_countdown_init(scratch->dc); return true; } + if (!scratch->dc->debug.disable_deferred_minimal_transitions) { + scratch->dc->check_config.deferred_transition_state = true; + transition_countdown_init(scratch->dc); + } + scratch->intermediate_context = create_minimal_transition_state( scratch->dc, scratch->new_context, @@ -7351,7 +7367,8 @@ static bool update_planes_and_stream_prepare_v3( static void update_planes_and_stream_execute_v3_commit( const struct dc_update_scratch_space *scratch, bool intermediate_update, - bool intermediate_context + bool intermediate_context, + bool use_stream_update ) { commit_planes_for_stream( @@ -7359,7 +7376,7 @@ static void update_planes_and_stream_execute_v3_commit( intermediate_update ? scratch->intermediate_updates : scratch->surface_updates, intermediate_update ? scratch->intermediate_count : scratch->surface_count, scratch->stream, - intermediate_context ? NULL : scratch->stream_update, + use_stream_update ? scratch->stream_update : NULL, intermediate_context ? UPDATE_TYPE_FULL : scratch->update_type, // `dc->current_state` only used in `NO_NEW_CONTEXT`, where it is equal to `new_context` intermediate_context ? scratch->intermediate_context : scratch->new_context @@ -7385,15 +7402,16 @@ static void update_planes_and_stream_execute_v3( case UPDATE_V3_FLOW_NO_NEW_CONTEXT_CONTEXT_FULL: case UPDATE_V3_FLOW_NEW_CONTEXT_SEAMLESS: - update_planes_and_stream_execute_v3_commit(scratch, false, false); + update_planes_and_stream_execute_v3_commit(scratch, false, false, true); break; case UPDATE_V3_FLOW_NEW_CONTEXT_MINIMAL_NEW: - update_planes_and_stream_execute_v3_commit(scratch, false, true); + update_planes_and_stream_execute_v3_commit(scratch, false, true, + scratch->dc->check_config.deferred_transition_state); break; case UPDATE_V3_FLOW_NEW_CONTEXT_MINIMAL_CURRENT: - update_planes_and_stream_execute_v3_commit(scratch, true, true); + update_planes_and_stream_execute_v3_commit(scratch, true, true, false); break; case UPDATE_V3_FLOW_INVALID: @@ -7402,13 +7420,6 @@ static void update_planes_and_stream_execute_v3( } } -static void update_planes_and_stream_cleanup_v3_new_context( - struct dc_update_scratch_space *scratch -) -{ - swap_and_release_current_context(scratch->dc, scratch->new_context, scratch->stream); -} - static void update_planes_and_stream_cleanup_v3_release_minimal( struct dc_update_scratch_space *scratch, bool backup @@ -7439,17 +7450,23 @@ static bool update_planes_and_stream_cleanup_v3( switch (scratch->flow) { case UPDATE_V3_FLOW_NO_NEW_CONTEXT_CONTEXT_FAST: case UPDATE_V3_FLOW_NO_NEW_CONTEXT_CONTEXT_FULL: - // No cleanup required + if (scratch->dc->check_config.transition_countdown_to_steady_state) + scratch->dc->check_config.transition_countdown_to_steady_state--; break; case UPDATE_V3_FLOW_NEW_CONTEXT_SEAMLESS: - update_planes_and_stream_cleanup_v3_new_context(scratch); + swap_and_release_current_context(scratch->dc, scratch->new_context, scratch->stream); break; case UPDATE_V3_FLOW_NEW_CONTEXT_MINIMAL_NEW: update_planes_and_stream_cleanup_v3_intermediate(scratch, false); - scratch->flow = UPDATE_V3_FLOW_NEW_CONTEXT_SEAMLESS; - return true; + if (scratch->dc->check_config.deferred_transition_state) { + dc_state_release(scratch->new_context); + } else { + scratch->flow = UPDATE_V3_FLOW_NEW_CONTEXT_SEAMLESS; + return true; + } + break; case UPDATE_V3_FLOW_NEW_CONTEXT_MINIMAL_CURRENT: update_planes_and_stream_cleanup_v3_intermediate(scratch, true); From 16ac1b6a6b52ff0bbd87b6361b8b01d358dfdadc Mon Sep 17 00:00:00 2001 From: Robin Chen Date: Tue, 16 Dec 2025 18:03:45 +0800 Subject: [PATCH 35/69] drm/amd/display: Remove unused DMUB replay commands [WHY] Remove unused DMUB Replay set version command and related code. Reviewed-by: Jack Chang Signed-off-by: Robin Chen Signed-off-by: Matthew Stewart Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc_types.h | 1 - .../gpu/drm/amd/display/dc/dce/dmub_replay.c | 13 ------ .../gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 46 ------------------- 3 files changed, 60 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index b3b785f1897d..5e71156d28e3 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -1101,7 +1101,6 @@ enum replay_FW_Message_type { Replay_Set_Residency_Frameupdate_Timer, Replay_Set_Pseudo_VTotal, Replay_Disabled_Adaptive_Sync_SDP, - Replay_Set_Version, Replay_Set_General_Cmd, }; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c index cf1372aaff6c..fd8244c94687 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c @@ -387,19 +387,6 @@ static void dmub_replay_send_cmd(struct dmub_replay *dmub, cmd.replay_disabled_adaptive_sync_sdp.data.force_disabled = cmd_element->disabled_adaptive_sync_sdp_data.force_disabled; break; - case Replay_Set_Version: - //Header - cmd.replay_set_version.header.sub_type = - DMUB_CMD__REPLAY_SET_VERSION; - cmd.replay_set_version.header.payload_bytes = - sizeof(struct dmub_rb_cmd_replay_set_version) - - sizeof(struct dmub_cmd_header); - //Cmd Body - cmd.replay_set_version.replay_set_version_data.panel_inst = - cmd_element->version_data.panel_inst; - cmd.replay_set_version.replay_set_version_data.version = - cmd_element->version_data.version; - break; case Replay_Set_General_Cmd: //Header cmd.replay_set_general_cmd.header.sub_type = 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 6c599559c5da..04c79069670a 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -4334,10 +4334,6 @@ enum dmub_cmd_replay_type { * Set adaptive sync sdp enabled */ DMUB_CMD__REPLAY_DISABLED_ADAPTIVE_SYNC_SDP = 8, - /** - * Set version - */ - DMUB_CMD__REPLAY_SET_VERSION = 9, /** * Set Replay General command. */ @@ -4505,40 +4501,6 @@ enum replay_version { REPLAY_VERSION_UNSUPPORTED = 0xFF, }; -/** - * Data passed from driver to FW in a DMUB_CMD___SET_REPLAY_VERSION command. - */ -struct dmub_cmd_replay_set_version_data { - /** - * Panel Instance. - * Panel instance to identify which psr_state to use - * Currently the support is only for 0 or 1 - */ - uint8_t panel_inst; - /** - * Replay version that FW should implement. - */ - enum replay_version version; - /** - * Explicit padding to 4 byte boundary. - */ - uint8_t pad[3]; -}; - -/** - * Definition of a DMUB_CMD__REPLAY_SET_VERSION command. - */ -struct dmub_rb_cmd_replay_set_version { - /** - * Command header. - */ - struct dmub_cmd_header header; - /** - * Data passed from driver to FW in a DMUB_CMD__REPLAY_SET_VERSION command. - */ - struct dmub_cmd_replay_set_version_data replay_set_version_data; -}; - /** * Definition of a DMUB_CMD__REPLAY_COPY_SETTINGS command. */ @@ -4929,10 +4891,6 @@ union dmub_replay_cmd_set { * Definition of DMUB_CMD__REPLAY_DISABLED_ADAPTIVE_SYNC_SDP command data. */ struct dmub_cmd_replay_disabled_adaptive_sync_sdp_data disabled_adaptive_sync_sdp_data; - /** - * Definition of DMUB_CMD__REPLAY_SET_VERSION command data. - */ - struct dmub_cmd_replay_set_version_data version_data; /** * Definition of DMUB_CMD__REPLAY_SET_GENERAL_CMD command data. */ @@ -7020,10 +6978,6 @@ union dmub_rb_cmd { * Definition of a DMUB_CMD__IDLE_OPT_SET_DC_POWER_STATE command. */ struct dmub_rb_cmd_idle_opt_set_dc_power_state idle_opt_set_dc_power_state; - /** - * Definition of a DMUB_CMD__REPLAY_SET_VERSION command. - */ - struct dmub_rb_cmd_replay_set_version replay_set_version; /* * Definition of a DMUB_CMD__REPLAY_COPY_SETTINGS command. */ From 99f77f6229c0766b980ae05affcf9f742d97de6a Mon Sep 17 00:00:00 2001 From: "Mario Limonciello (AMD)" Date: Sun, 14 Dec 2025 08:59:16 -0600 Subject: [PATCH 36/69] drm/amd/display: Show link name in PSR status message [Why] The PSR message was moved in commit 4321742c394e ("drm/amd/display: Move PSR support message into amdgpu_dm"). This message however shows for every single link without showing which link is which. This can send a confusing message to the user. [How] Add link name into the message. Fixes: 4321742c394e ("drm/amd/display: Move PSR support message into amdgpu_dm") Reviewed-by: Alex Hung Signed-off-by: Mario Limonciello (AMD) Signed-off-by: Matthew Stewart Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 06b97029001b..3977a6cf341b 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -5639,7 +5639,8 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) if (psr_feature_enabled) { amdgpu_dm_set_psr_caps(link); - drm_info(adev_to_drm(adev), "PSR support %d, DC PSR ver %d, sink PSR ver %d DPCD caps 0x%x su_y_granularity %d\n", + drm_info(adev_to_drm(adev), "%s: PSR support %d, DC PSR ver %d, sink PSR ver %d DPCD caps 0x%x su_y_granularity %d\n", + aconnector->base.name, link->psr_settings.psr_feature_enabled, link->psr_settings.psr_version, link->dpcd_caps.psr_info.psr_version, From ac1e65d8ade46c09fb184579b81acadf36dcb91e Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 15 Dec 2025 14:08:30 -0600 Subject: [PATCH 37/69] drm/amd/display: Bump the HDMI clock to 340MHz [Why] DP-HDMI dongles can execeed bandwidth requirements on high resolution monitors. This can lead to pruning the high resolution modes. HDMI 1.3 bumped the clock to 340MHz, but display code never matched it. [How] Set default to (DVI) 165MHz. Once HDMI display is identified update to 340MHz. Reported-by: Dianne Skoll Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4780 Reviewed-by: Chris Park Signed-off-by: Mario Limonciello Signed-off-by: Matthew Stewart Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc_hdmi_types.h | 2 +- drivers/gpu/drm/amd/display/dc/link/link_detection.c | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc_hdmi_types.h b/drivers/gpu/drm/amd/display/dc/dc_hdmi_types.h index b015e80672ec..fcd3ab4b0045 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_hdmi_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_hdmi_types.h @@ -41,7 +41,7 @@ /* kHZ*/ #define DP_ADAPTOR_DVI_MAX_TMDS_CLK 165000 /* kHZ*/ -#define DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK 165000 +#define DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK 340000 struct dp_hdmi_dongle_signature_data { int8_t id[15];/* "DP-HDMI ADAPTOR"*/ diff --git a/drivers/gpu/drm/amd/display/dc/link/link_detection.c b/drivers/gpu/drm/amd/display/dc/link/link_detection.c index f24365395cd9..2c9d2b932482 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_detection.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_detection.c @@ -335,7 +335,7 @@ static void query_dp_dual_mode_adaptor( /* Assume we have no valid DP passive dongle connected */ *dongle = DISPLAY_DONGLE_NONE; - sink_cap->max_hdmi_pixel_clock = DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK; + sink_cap->max_hdmi_pixel_clock = DP_ADAPTOR_DVI_MAX_TMDS_CLK; /* Read DP-HDMI dongle I2c (no response interpreted as DP-DVI dongle)*/ if (!i2c_read( @@ -391,6 +391,8 @@ static void query_dp_dual_mode_adaptor( } } + if (is_valid_hdmi_signature) + sink_cap->max_hdmi_pixel_clock = DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK; if (is_type2_dongle) { uint32_t max_tmds_clk = From a230696d4e009abb22b7a2f9d434f1555bfa08ca Mon Sep 17 00:00:00 2001 From: Jack Chang Date: Thu, 4 Dec 2025 16:57:47 +0800 Subject: [PATCH 38/69] drm/amd/display: DPCD for Selective Update [Why&How] Add flow to read selective update related info from DPCD, and pass the info to DMUB. Reviewed-by: Robin Chen Reviewed-by: Wenjing Liu Signed-off-by: Jack Chang Signed-off-by: Matthew Stewart Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc_dp_types.h | 23 ++++++++- .../dc/link/protocols/link_dp_capability.c | 47 ++++++++++++++++++- .../dc/link/protocols/link_dp_panel_replay.c | 16 ++++++- .../gpu/drm/amd/display/include/dpcd_defs.h | 15 ++++++ 4 files changed, 97 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h index 273610d85438..d0d9297ccac0 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h @@ -1167,6 +1167,25 @@ union dpcd_panel_replay_capability_supported { unsigned char raw; }; +union dpcd_panel_replay_capability { + struct { + unsigned char RESERVED :2; + unsigned char DSC_DECODE_NOT_SUPPORTED :1; + unsigned char ASYNC_VIDEO_TIMING_NOT_SUPPORTED :1; + unsigned char DSC_CRC_OF_MULTI_SU_SUPPORTED :1; + unsigned char PR_SU_GRANULARITY_NEEDED :1; + unsigned char SU_Y_GRANULARITY_EXT_CAP_SUPPORTED :1; + unsigned char LINK_OFF_SUPPORTED_IN_PR_ACTIVE :1; + } bits; + unsigned char raw; +}; + +struct dpcd_panel_replay_selective_update_info { + uint16_t pr_su_x_granularity; + uint8_t pr_su_y_granularity; + uint16_t pr_su_y_granularity_extended_caps; +}; + enum dpcd_downstream_port_max_bpc { DOWN_STREAM_MAX_8BPC = 0, DOWN_STREAM_MAX_10BPC, @@ -1290,7 +1309,9 @@ struct dpcd_caps { struct edp_psr_info psr_info; struct replay_info pr_info; - union dpcd_panel_replay_capability_supported pr_caps_supported; + union dpcd_panel_replay_capability_supported vesa_replay_caps_supported; + union dpcd_panel_replay_capability vesa_replay_caps; + struct dpcd_panel_replay_selective_update_info vesa_replay_su_info; uint16_t edp_oled_emission_rate; union dp_receive_port0_cap receive_port0_cap; /* Indicates the number of SST links supported by MSO (Multi-Stream Output) */ diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c index 54c417928b61..8bbf5637b166 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c @@ -1593,6 +1593,41 @@ static bool dpcd_read_sink_ext_caps(struct dc_link *link) return true; } +static void retrieve_vesa_replay_su_info(struct dc_link *link) +{ + uint8_t dpcd_data = 0; + + core_link_read_dpcd(link, + DP_PR_SU_X_GRANULARITY_LOW, + &dpcd_data, + sizeof(dpcd_data)); + link->dpcd_caps.vesa_replay_su_info.pr_su_x_granularity = dpcd_data; + + core_link_read_dpcd(link, + DP_PR_SU_X_GRANULARITY_HIGH, + &dpcd_data, + sizeof(dpcd_data)); + link->dpcd_caps.vesa_replay_su_info.pr_su_x_granularity |= (dpcd_data << 8); + + core_link_read_dpcd(link, + DP_PR_SU_Y_GRANULARITY, + &dpcd_data, + sizeof(dpcd_data)); + link->dpcd_caps.vesa_replay_su_info.pr_su_y_granularity = dpcd_data; + + core_link_read_dpcd(link, + DP_PR_SU_Y_GRANULARITY_EXTENDED_CAP_LOW, + &dpcd_data, + sizeof(dpcd_data)); + link->dpcd_caps.vesa_replay_su_info.pr_su_y_granularity_extended_caps = dpcd_data; + + core_link_read_dpcd(link, + DP_PR_SU_Y_GRANULARITY_EXTENDED_CAP_HIGH, + &dpcd_data, + sizeof(dpcd_data)); + link->dpcd_caps.vesa_replay_su_info.pr_su_y_granularity_extended_caps |= (dpcd_data << 8); +} + enum dc_status dp_retrieve_lttpr_cap(struct dc_link *link) { uint8_t lttpr_dpcd_data[10] = {0}; @@ -2094,8 +2129,16 @@ static bool retrieve_link_cap(struct dc_link *link) core_link_read_dpcd(link, DP_PANEL_REPLAY_CAPABILITY_SUPPORT, - &link->dpcd_caps.pr_caps_supported.raw, - sizeof(link->dpcd_caps.pr_caps_supported.raw)); + &link->dpcd_caps.vesa_replay_caps_supported.raw, + sizeof(link->dpcd_caps.vesa_replay_caps_supported.raw)); + + core_link_read_dpcd(link, + DP_PANEL_REPLAY_CAPABILITY, + &link->dpcd_caps.vesa_replay_caps.raw, + sizeof(link->dpcd_caps.vesa_replay_caps.raw)); + + /* Read VESA Panel Replay Selective Update caps */ + retrieve_vesa_replay_su_info(link); /* Read DP tunneling information. */ status = dpcd_get_tunneling_device_data(link); diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.c index 3168c42d662c..fdbfa5103183 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.c @@ -113,7 +113,10 @@ static bool dp_setup_panel_replay(struct dc_link *link, const struct dc_stream_s pr_config_1.bits.PANEL_REPLAY_EARLY_TRANSPORT_ENABLE = 1; pr_config_2.bits.SINK_REFRESH_RATE_UNLOCK_GRANTED = 0; - pr_config_2.bits.SU_Y_GRANULARITY_EXT_VALUE_ENABLED = 0; + + if (link->dpcd_caps.vesa_replay_caps.bits.SU_Y_GRANULARITY_EXT_CAP_SUPPORTED) + pr_config_2.bits.SU_Y_GRANULARITY_EXT_VALUE_ENABLED = 1; + pr_config_2.bits.SU_REGION_SCAN_LINE_CAPTURE_INDICATION = 0; dm_helpers_dp_write_dpcd(link->ctx, link, @@ -231,6 +234,17 @@ bool dp_pr_copy_settings(struct dc_link *link, struct replay_context *replay_con cmd.pr_copy_settings.data.flags.bitfields.dsc_enable_status = (pipe_ctx->stream->timing.flags.DSC == 1); cmd.pr_copy_settings.data.debug.u32All = link->replay_settings.config.debug_flags; + cmd.pr_copy_settings.data.su_granularity_needed = link->dpcd_caps.vesa_replay_caps.bits.PR_SU_GRANULARITY_NEEDED; + cmd.pr_copy_settings.data.su_x_granularity = link->dpcd_caps.vesa_replay_su_info.pr_su_x_granularity; + cmd.pr_copy_settings.data.su_y_granularity = link->dpcd_caps.vesa_replay_su_info.pr_su_y_granularity; + cmd.pr_copy_settings.data.su_y_granularity_extended_caps = + link->dpcd_caps.vesa_replay_su_info.pr_su_y_granularity_extended_caps; + + if (pipe_ctx->stream->timing.dsc_cfg.num_slices_v > 0) + cmd.pr_copy_settings.data.dsc_slice_height = (pipe_ctx->stream->timing.v_addressable + + pipe_ctx->stream->timing.v_border_top + pipe_ctx->stream->timing.v_border_bottom) / + pipe_ctx->stream->timing.dsc_cfg.num_slices_v; + dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); return true; } diff --git a/drivers/gpu/drm/amd/display/include/dpcd_defs.h b/drivers/gpu/drm/amd/display/include/dpcd_defs.h index 8445c540f042..43d58df67bab 100644 --- a/drivers/gpu/drm/amd/display/include/dpcd_defs.h +++ b/drivers/gpu/drm/amd/display/include/dpcd_defs.h @@ -37,6 +37,21 @@ #ifndef DP_PANEL_REPLAY_CAPABILITY // can remove this once the define gets into linux drm_dp_helper.h #define DP_PANEL_REPLAY_CAPABILITY 0x0b1 #endif /* DP_PANEL_REPLAY_CAPABILITY */ +#ifndef DP_PR_SU_X_GRANULARITY_LOW // can remove this once the define gets into linux drm_dp_helper.h +#define DP_PR_SU_X_GRANULARITY_LOW 0x0b2 +#endif /* DP_PR_SU_X_GRANULARITY_LOW */ +#ifndef DP_PR_SU_X_GRANULARITY_HIGH // can remove this once the define gets into linux drm_dp_helper.h +#define DP_PR_SU_X_GRANULARITY_HIGH 0x0b3 +#endif /* DP_PR_SU_X_GRANULARITY_HIGH */ +#ifndef DP_PR_SU_Y_GRANULARITY // can remove this once the define gets into linux drm_dp_helper.h +#define DP_PR_SU_Y_GRANULARITY 0x0b4 +#endif /* DP_PR_SU_Y_GRANULARITY */ +#ifndef DP_PR_SU_Y_GRANULARITY_EXTENDED_CAP_LOW // can remove this once the define gets into linux drm_dp_helper.h +#define DP_PR_SU_Y_GRANULARITY_EXTENDED_CAP_LOW 0x0b5 +#endif /* DP_PR_SU_Y_GRANULARITY_EXTENDED_CAP_LOW */ +#ifndef DP_PR_SU_Y_GRANULARITY_EXTENDED_CAP_HIGH // can remove this once the define gets into linux drm_dp_helper.h +#define DP_PR_SU_Y_GRANULARITY_EXTENDED_CAP_HIGH 0x0b6 +#endif /* DP_PR_SU_Y_GRANULARITY_EXTENDED_CAP_HIGH */ #ifndef DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_1 // can remove this once the define gets into linux drm_dp_helper.h #define DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_1 0x1b0 #endif /* DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_1 */ From 53edf8604a7c594d1d5091deb7c11d2c3b2e6b79 Mon Sep 17 00:00:00 2001 From: Jack Chang Date: Thu, 6 Nov 2025 10:58:26 +0800 Subject: [PATCH 39/69] drm/amd/display: PR error HPD_IRQ handling [Why & How] Add error handling for IRQ_HPD in Panel Replay Reviewed-by: Robin Chen Reviewed-by: Wenjing Liu Signed-off-by: Jack Chang Signed-off-by: Matthew Stewart Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc_dp_types.h | 11 +++++ .../dc/link/protocols/link_dp_irq_handler.c | 42 +++++++++++++++++++ .../gpu/drm/amd/display/include/dpcd_defs.h | 15 +++++++ 3 files changed, 68 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h index d0d9297ccac0..5e3646b7550c 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h @@ -1423,6 +1423,17 @@ union dpcd_sink_active_vtotal_control_mode { unsigned char raw; }; +union pr_error_status { + struct { + unsigned char LINK_CRC_ERROR :1; + unsigned char RFB_STORAGE_ERROR :1; + unsigned char VSC_SDP_ERROR :1; + unsigned char ASSDP_MISSING_ERROR :1; + unsigned char RESERVED :4; + } bits; + unsigned char raw; +}; + union psr_error_status { struct { unsigned char LINK_CRC_ERROR :1; diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c index 47abd3ec69b3..cc18a3bebef2 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c @@ -34,6 +34,7 @@ #include "link_dp_training.h" #include "link_dp_capability.h" #include "link_edp_panel_control.h" +#include "link_dp_panel_replay.h" #include "link/accessories/link_dp_trace.h" #include "link/link_dpms.h" #include "dm_helpers.h" @@ -186,6 +187,42 @@ static bool handle_hpd_irq_psr_sink(struct dc_link *link) return false; } +static void handle_hpd_irq_vesa_replay_sink(struct dc_link *link) +{ + union pr_error_status pr_error_status = {0}; + + if (!link->replay_settings.replay_feature_enabled || + link->replay_settings.config.replay_version != DC_VESA_PANEL_REPLAY) + return; + + dm_helpers_dp_read_dpcd( + link->ctx, + link, + DP_PR_ERROR_STATUS, + &pr_error_status.raw, + sizeof(pr_error_status.raw)); + + if (pr_error_status.bits.LINK_CRC_ERROR || + pr_error_status.bits.RFB_STORAGE_ERROR || + pr_error_status.bits.VSC_SDP_ERROR || + pr_error_status.bits.ASSDP_MISSING_ERROR) { + + /* Acknowledge and clear error bits */ + dm_helpers_dp_write_dpcd( + link->ctx, + link, + DP_PR_ERROR_STATUS, /*DpcdAddress_PR_Error_Status*/ + &pr_error_status.raw, + sizeof(pr_error_status.raw)); + + /* Replay error, disable and re-enable Replay */ + if (link->replay_settings.replay_allow_active) { + dp_pr_enable(link, false); + dp_pr_enable(link, true); + } + } +} + static void handle_hpd_irq_replay_sink(struct dc_link *link) { union dpcd_replay_configuration replay_configuration = {0}; @@ -197,6 +234,11 @@ static void handle_hpd_irq_replay_sink(struct dc_link *link) if (!link->replay_settings.replay_feature_enabled) return; + if (link->replay_settings.config.replay_version != DC_FREESYNC_REPLAY) { + handle_hpd_irq_vesa_replay_sink(link); + return; + } + while (retries < 10) { ret = dm_helpers_dp_read_dpcd( link->ctx, diff --git a/drivers/gpu/drm/amd/display/include/dpcd_defs.h b/drivers/gpu/drm/amd/display/include/dpcd_defs.h index 43d58df67bab..7d8359a7d99d 100644 --- a/drivers/gpu/drm/amd/display/include/dpcd_defs.h +++ b/drivers/gpu/drm/amd/display/include/dpcd_defs.h @@ -61,6 +61,21 @@ #ifndef DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_2 // can remove this once the define gets into linux drm_dp_helper.h #define DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_2 0x1b1 #endif /* DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_2 */ +#ifndef DP_PR_ERROR_STATUS // can remove this once the define gets into linux drm_dp_helper.h +#define DP_PR_ERROR_STATUS 0x2020 /* DP 2.0 */ +#endif /* DP_PR_ERROR_STATUS */ +#ifndef DP_PR_LINK_CRC_ERROR // can remove this once the define gets into linux drm_dp_helper.h +#define DP_PR_LINK_CRC_ERROR (1 << 0) +#endif /* DP_PR_LINK_CRC_ERROR */ +#ifndef DP_PR_RFB_STORAGE_ERROR // can remove this once the define gets into linux drm_dp_helper.h +#define DP_PR_RFB_STORAGE_ERROR (1 << 1) +#endif /* DP_PR_RFB_STORAGE_ERROR */ +#ifndef DP_PR_VSC_SDP_UNCORRECTABLE_ERROR // can remove this once the define gets into linux drm_dp_helper.h +#define DP_PR_VSC_SDP_UNCORRECTABLE_ERROR (1 << 2) /* eDP 1.4 */ +#endif /* DP_PR_VSC_SDP_UNCORRECTABLE_ERROR */ +#ifndef DP_PR_ASSDP_MISSING_ERROR // can remove this once the define gets into linux drm_dp_helper.h +#define DP_PR_ASSDP_MISSING_ERROR (1 << 3) /* eDP 1.5 */ +#endif /* DP_PR_ASSDP_MISSING_ERROR */ enum dpcd_revision { DPCD_REV_10 = 0x10, From 0839d8d24e6f1fc2587c4a976f44da9fa69ae3d0 Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin Date: Tue, 16 Dec 2025 16:38:50 -0500 Subject: [PATCH 40/69] drm/amd/display: only power down dig on phy endpoints This avoids any issues with dpia endpoints Reviewed-by: Charlene Liu Signed-off-by: Dmytro Laktyushkin Signed-off-by: Matthew Stewart Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c index b7593b886dc6..22c1d5e68420 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c @@ -287,6 +287,8 @@ void dcn401_init_hw(struct dc *dc) for (i = 0; i < dc->link_count; i++) { struct dc_link *link = dc->links[i]; + if (link->ep_type != DISPLAY_ENDPOINT_PHY) + continue; if (link->link_enc->funcs->is_dig_enabled && link->link_enc->funcs->is_dig_enabled(link->link_enc) && hws->funcs.power_down) { From 1883b2578df3e3577b429fd46776e788b2107ec0 Mon Sep 17 00:00:00 2001 From: Leo Chen Date: Wed, 17 Dec 2025 19:32:45 -0500 Subject: [PATCH 41/69] drm/amd/display: Add global fgcg function prototype to DCCG [Why & How] Add the ability to enable/disable global fine grain clock gating within DCCG. Reviewed-by: Charlene Liu Signed-off-by: Leo Chen Signed-off-by: Matthew Stewart Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h index 500a601e99b5..1e6ffd86a4c0 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h @@ -333,6 +333,7 @@ struct dccg_funcs { void (*set_ref_dscclk)(struct dccg *dccg, uint32_t dsc_inst); void (*dccg_root_gate_disable_control)(struct dccg *dccg, uint32_t pipe_idx, uint32_t disable_clock_gating); void (*dccg_read_reg_state)(struct dccg *dccg, struct dcn_dccg_reg_state *dccg_reg_state); + void (*dccg_enable_global_fgcg)(struct dccg *dccg, bool enable); }; #endif //__DAL_DCCG_H__ From e7b09b766ae2c2d0cb8e9a2d81b7b9dfca04a9b1 Mon Sep 17 00:00:00 2001 From: Ausef Yousof Date: Mon, 1 Dec 2025 15:03:10 -0500 Subject: [PATCH 42/69] drm/amd/display: correct clip x assignment in cursor programming [why&how] primary planes for external displays getting incorrect clip values, detect such a scenario and pass correct parameters Reviewed-by: Ovidiu (Ovi) Bunea Signed-off-by: Ausef Yousof Signed-off-by: Matthew Stewart Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc_hw_types.h | 6 ++++++ drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c | 6 +++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h index 667852517246..cfa569a7bff1 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h @@ -491,6 +491,12 @@ struct dc_cursor_position { * for each plane. */ bool translate_by_source; + + /** + * @use_viewport_for_clip: Use viewport position for clip_x calculation + * instead of clip_rect. Required to protect against clip being overwritten + */ + bool use_viewport_for_clip; }; struct dc_cursor_mi_param { diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c index fa62e40a9858..8a23763ca98e 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c @@ -3666,7 +3666,11 @@ void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) int y_plane = pipe_ctx->plane_state->dst_rect.y; int x_pos = pos_cpy.x; int y_pos = pos_cpy.y; - int clip_x = pipe_ctx->plane_state->clip_rect.x; + bool is_primary_plane = (pipe_ctx->plane_state->layer_index == 0); + + int clip_x = (pos_cpy.use_viewport_for_clip && is_primary_plane && + !odm_combine_on && !pipe_split_on && param.viewport.x != 0) + ? param.viewport.x : pipe_ctx->plane_state->clip_rect.x; int clip_width = pipe_ctx->plane_state->clip_rect.width; if ((pipe_ctx->top_pipe != NULL) || (pipe_ctx->bottom_pipe != NULL)) { From 1758cf3cfd3152530d875b9e5cb84eedafdb2e0b Mon Sep 17 00:00:00 2001 From: Derek Lai Date: Thu, 18 Dec 2025 11:44:50 +0800 Subject: [PATCH 43/69] drm/amd/display: revert "write default Vesa Aux backlight control in dmub" This reverts commit 08f133e932cc. Commit causing backlight darker when the system wakes up from standby mode, and green screen w/ secondary screen only when the system wakes up from standby mode. Reviewed-by: Charlene Liu Signed-off-by: Derek Lai Signed-off-by: Matthew Stewart Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../drm/amd/display/dc/link/link_detection.c | 2 +- .../gpu/drm/amd/display/dc/link/link_dpms.c | 4 +-- .../dc/link/protocols/link_dp_capability.c | 2 +- .../link/protocols/link_edp_panel_control.c | 26 +++---------------- .../link/protocols/link_edp_panel_control.h | 2 +- 5 files changed, 8 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/link/link_detection.c b/drivers/gpu/drm/amd/display/dc/link/link_detection.c index 2c9d2b932482..578509e8d0e2 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_detection.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_detection.c @@ -995,7 +995,7 @@ static bool detect_link_and_local_sink(struct dc_link *link, (link->dpcd_sink_ext_caps.bits.oled == 1)) { dpcd_set_source_specific_data(link); msleep(post_oui_delay); - set_default_brightness(link); + set_default_brightness_aux(link); } return true; diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c index 323cc0b3c09a..7e46ea98952c 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c @@ -2061,7 +2061,7 @@ static enum dc_status enable_link_dp(struct dc_state *state, skip_video_pattern = false; if (stream->sink_patches.oled_optimize_display_on) - set_default_brightness(link); + set_default_brightness_aux(link); if (perform_link_training_with_retries(link_settings, skip_video_pattern, @@ -2087,7 +2087,7 @@ static enum dc_status enable_link_dp(struct dc_state *state, link->dpcd_sink_ext_caps.bits.sdr_aux_backlight_control == 1 || link->dpcd_sink_ext_caps.bits.hdr_aux_backlight_control == 1) { if (!stream->sink_patches.oled_optimize_display_on) { - set_default_brightness(link); + set_default_brightness_aux(link); if (link->dpcd_sink_ext_caps.bits.oled == 1) msleep(bl_oled_enable_delay); edp_backlight_enable_aux(link, true); diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c index 8bbf5637b166..cdc7587cf0b6 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c @@ -2210,7 +2210,7 @@ void detect_edp_sink_caps(struct dc_link *link) link->dpcd_caps.set_power_state_capable_edp = (general_edp_cap & DP_EDP_SET_POWER_CAP) ? true : false; - set_default_brightness(link); + set_default_brightness_aux(link); core_link_read_dpcd(link, DP_EDP_DPCD_REV, &link->dpcd_caps.edp_rev, diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c index ab047ff556a1..cb4129c0937a 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c @@ -50,11 +50,6 @@ static const uint8_t DP_VGA_LVDS_CONVERTER_ID_2[] = "sivarT"; /* Nutmeg */ static const uint8_t DP_VGA_LVDS_CONVERTER_ID_3[] = "dnomlA"; -static const unsigned int pwr_default_min_brightness_millinits = 1000; -static const unsigned int pwr_default_sdr_brightness_millinits = 270000; -static const unsigned int pwr_default_min_backlight_pwm = 0xC0C; -static const unsigned int pwr_default_max_backlight_pwm = 0xFFFF; - void dp_set_panel_mode(struct dc_link *link, enum dp_panel_mode panel_mode) { union dpcd_edp_config edp_config_set; @@ -313,7 +308,7 @@ static bool read_default_bl_aux(struct dc_link *link, uint32_t *backlight_millin return true; } -bool set_default_brightness(struct dc_link *link) +bool set_default_brightness_aux(struct dc_link *link) { uint32_t default_backlight; @@ -324,23 +319,8 @@ bool set_default_brightness(struct dc_link *link) if (default_backlight < 1000 || default_backlight > 5000000) default_backlight = 150000; - if (link->backlight_control_type == BACKLIGHT_CONTROL_VESA_AUX && - link->dc->caps.dmub_caps.aux_backlight_support) { - struct set_backlight_level_params backlight_level_params = { 0 }; - - backlight_level_params.aux_inst = link->ddc->ddc_pin->hw_info.ddc_channel; - backlight_level_params.control_type = BACKLIGHT_CONTROL_VESA_AUX; - backlight_level_params.backlight_pwm_u16_16 = default_backlight; - backlight_level_params.transition_time_in_ms = 0; - // filled in the driver BL default values - backlight_level_params.min_luminance = pwr_default_min_brightness_millinits; - backlight_level_params.max_luminance = pwr_default_sdr_brightness_millinits; - backlight_level_params.min_backlight_pwm = pwr_default_min_backlight_pwm; - backlight_level_params.max_backlight_pwm = pwr_default_max_backlight_pwm; - return edp_set_backlight_level(link, &backlight_level_params); - } else - return edp_set_backlight_level_nits(link, true, - default_backlight, 0); + return edp_set_backlight_level_nits(link, true, + default_backlight, 0); } return false; } diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h index 8780bbc4e8c5..8fdb76d9953e 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h @@ -29,7 +29,7 @@ enum dp_panel_mode dp_get_panel_mode(struct dc_link *link); void dp_set_panel_mode(struct dc_link *link, enum dp_panel_mode panel_mode); -bool set_default_brightness(struct dc_link *link); +bool set_default_brightness_aux(struct dc_link *link); bool is_smartmux_suported(struct dc_link *link); void edp_panel_backlight_power_on(struct dc_link *link, bool wait_for_hpd); int edp_get_backlight_level(const struct dc_link *link); From cdd9b2d7e4091cc549deadf3e160e41e795b8e26 Mon Sep 17 00:00:00 2001 From: Cruise Hung Date: Wed, 17 Dec 2025 18:11:43 +0800 Subject: [PATCH 44/69] drm/amd/display: Always update divider settings for DP tunnel [Why] When transitioning from 640x480 at RBRx1 to HBR3x1, both output pixel mode and pixel rate divider should update. The needs_divider_update flag was only for 8b10b and 128b132b transition. [How] For DP tunneling, always update divider settings. Reviewed-by: Jerry Zuo Signed-off-by: Cruise Hung Signed-off-by: Matthew Stewart Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../drm/amd/display/dc/link/accessories/link_dp_cts.c | 7 ++++++- .../amd/display/dc/resource/dcn31/dcn31_resource.c | 11 +++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c index 5a547d41d4a1..693d852b1c40 100644 --- a/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c +++ b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c @@ -70,6 +70,7 @@ static void dp_retrain_link_dp_test(struct dc_link *link, struct dc_state *state = link->dc->current_state; struct dc_stream_update stream_update = { 0 }; bool dpms_off = false; + bool needs_divider_update = false; bool was_hpo_acquired = resource_is_hpo_acquired(link->dc->current_state); bool is_hpo_acquired; uint8_t count; @@ -79,6 +80,10 @@ static void dp_retrain_link_dp_test(struct dc_link *link, int num_streams_on_link = 0; struct dc *dc = (struct dc *)link->dc; + needs_divider_update = (link->dc->link_srv->dp_get_encoding_format(link_setting) != + link->dc->link_srv->dp_get_encoding_format((const struct dc_link_settings *) &link->cur_link_settings)) + || link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA; + udelay(100); link_get_master_pipes_with_dpms_on(link, state, &count, pipes); @@ -95,7 +100,7 @@ static void dp_retrain_link_dp_test(struct dc_link *link, pipes[i]->stream_res.tg->funcs->disable_crtc(pipes[i]->stream_res.tg); } - if (link->dc->res_pool->funcs->update_dc_state_for_encoder_switch) { + if (needs_divider_update && link->dc->res_pool->funcs->update_dc_state_for_encoder_switch) { link->dc->res_pool->funcs->update_dc_state_for_encoder_switch(link, link_setting, count, *pipes, &audio_output[0]); diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c index 0d667b54ccf8..e853ea110310 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c @@ -2250,12 +2250,15 @@ enum dc_status dcn31_update_dc_state_for_encoder_switch(struct dc_link *link, int i; #if defined(CONFIG_DRM_AMD_DC_FP) - for (i = 0; i < state->stream_count; i++) - if (state->streams[i] && state->streams[i]->link && state->streams[i]->link == link) - link->dc->hwss.calculate_pix_rate_divider((struct dc *)link->dc, state, state->streams[i]); + if (link->dc->hwss.calculate_pix_rate_divider) { + for (i = 0; i < state->stream_count; i++) + if (state->streams[i] && state->streams[i]->link && state->streams[i]->link == link) + link->dc->hwss.calculate_pix_rate_divider((struct dc *)link->dc, state, state->streams[i]); + } for (i = 0; i < pipe_count; i++) { - link->dc->res_pool->funcs->build_pipe_pix_clk_params(&pipes[i]); + if (link->dc->res_pool->funcs->build_pipe_pix_clk_params) + link->dc->res_pool->funcs->build_pipe_pix_clk_params(&pipes[i]); // Setup audio if (pipes[i].stream_res.audio != NULL) From a036db3953140d5c2816b056aa3e73b8e98d9bc0 Mon Sep 17 00:00:00 2001 From: Ray Wu Date: Tue, 16 Dec 2025 18:09:45 +0800 Subject: [PATCH 45/69] drm/amd/display: disable replay when crc source is enabled [Why] IGT CRC tests fail on replay panels due to invalid CRC values captured when replay is active. [How] - Disable replay when CRC source is enabled; set flag to prevent unexpected re-enable - Reset flag when CRC source is disabled to allow replay Reviewed-by: ChiaHsuan (Tom) Chung Signed-off-by: Ray Wu Signed-off-by: Matthew Stewart Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 1 + .../drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c | 25 ++++++++++++++++--- .../amd/display/amdgpu_dm/amdgpu_dm_replay.c | 7 ++++++ 3 files changed, 30 insertions(+), 3 deletions(-) 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 ab363f2f6d47..f0f371718d03 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -815,6 +815,7 @@ struct amdgpu_dm_connector { int sr_skip_count; bool disallow_edp_enter_psr; + bool disallow_edp_enter_replay; /* Record progress status of mst*/ uint8_t mst_status; 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 327b20055729..5851f2d55dde 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 @@ -32,6 +32,7 @@ #include "dc.h" #include "amdgpu_securedisplay.h" #include "amdgpu_dm_psr.h" +#include "amdgpu_dm_replay.h" static const char *const pipe_crc_sources[] = { "none", @@ -502,6 +503,7 @@ int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc, { struct amdgpu_device *adev = drm_to_adev(crtc->dev); struct dc_stream_state *stream_state = dm_crtc_state->stream; + struct amdgpu_dm_connector *aconnector = NULL; bool enable = amdgpu_dm_is_valid_crc_source(source); int ret = 0; @@ -509,11 +511,22 @@ int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc, if (!stream_state) return -EINVAL; + /* Get connector from stream */ + aconnector = (struct amdgpu_dm_connector *)stream_state->dm_stream_context; + mutex_lock(&adev->dm.dc_lock); - /* For PSR1, check that the panel has exited PSR */ - if (stream_state->link->psr_settings.psr_version < DC_PSR_VERSION_SU_1) - amdgpu_dm_psr_wait_disable(stream_state); + + if (enable) { + /* For PSR1, check that the panel has exited PSR */ + if (stream_state->link->psr_settings.psr_version < DC_PSR_VERSION_SU_1) + amdgpu_dm_psr_wait_disable(stream_state); + + /* Set flag to disallow enter replay when CRC source is enabled */ + if (aconnector) + aconnector->disallow_edp_enter_replay = true; + amdgpu_dm_replay_disable(stream_state); + } /* Enable or disable CRTC CRC generation */ if (dm_is_crc_source_crtc(source) || source == AMDGPU_DM_PIPE_CRC_SOURCE_NONE) { @@ -536,6 +549,12 @@ int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc, DYN_EXPANSION_AUTO); } + if (!enable) { + /* Clear flag to allow enter replay when CRC source is disabled */ + if (aconnector) + aconnector->disallow_edp_enter_replay = false; + } + unlock: mutex_unlock(&adev->dm.dc_lock); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c index fb619a3336b7..8c150b001105 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c @@ -154,10 +154,17 @@ bool amdgpu_dm_replay_enable(struct dc_stream_state *stream, bool wait) { bool replay_active = true; struct dc_link *link = NULL; + struct amdgpu_dm_connector *aconnector = NULL; if (stream == NULL) return false; + /* Check if replay is disabled by connector flag */ + aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context; + if (!aconnector || aconnector->disallow_edp_enter_replay) { + return false; + } + link = stream->link; if (link) { From 5a113e15d15605c07d57d923c9f4a0d52d403ecc Mon Sep 17 00:00:00 2001 From: Peichen Huang Date: Mon, 15 Dec 2025 15:38:26 +0800 Subject: [PATCH 46/69] drm/amd/display: init code for external panel replay Prepare for supporting panel replay on external monitors. Reviewed-by: Robin Chen Reviewed-by: Wenjing Liu Signed-off-by: Peichen Huang Signed-off-by: Matthew Stewart Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../drm/amd/display/dc/dce/dmub_hw_lock_mgr.c | 2 +- .../gpu/drm/amd/display/dc/inc/link_service.h | 4 +- .../gpu/drm/amd/display/dc/link/link_dpms.c | 4 ++ .../drm/amd/display/dc/link/link_factory.c | 1 + .../dc/link/protocols/link_dp_panel_replay.c | 53 +++++++++++++------ .../dc/link/protocols/link_dp_panel_replay.h | 4 +- 6 files changed, 47 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_hw_lock_mgr.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_hw_lock_mgr.c index 5bfa2b0d2afd..7116fdd4c7ec 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_hw_lock_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_hw_lock_mgr.c @@ -69,7 +69,7 @@ bool dmub_hw_lock_mgr_does_link_require_lock(const struct dc *dc, const struct d if (link->psr_settings.psr_version == DC_PSR_VERSION_SU_1) return true; - if (link->replay_settings.replay_feature_enabled) + if (link->replay_settings.replay_feature_enabled && dc_is_embedded_signal(link->connector_signal)) return true; if (link->psr_settings.psr_version == DC_PSR_VERSION_1) { diff --git a/drivers/gpu/drm/amd/display/dc/inc/link_service.h b/drivers/gpu/drm/amd/display/dc/inc/link_service.h index 5885b4abdf38..57bb82e94942 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/link_service.h +++ b/drivers/gpu/drm/amd/display/dc/inc/link_service.h @@ -283,8 +283,6 @@ struct link_service { bool (*edp_set_replay_allow_active)(struct dc_link *dc_link, const bool *enable, bool wait, bool force_static, const unsigned int *power_opts); - bool (*dp_setup_replay)(struct dc_link *link, - const struct dc_stream_state *stream); bool (*edp_send_replay_cmd)(struct dc_link *link, enum replay_FW_Message_type msg, union dmub_replay_cmd_set *cmd_data); @@ -304,6 +302,8 @@ struct link_service { bool (*edp_receiver_ready_T9)(struct dc_link *link); bool (*edp_receiver_ready_T7)(struct dc_link *link); bool (*edp_power_alpm_dpcd_enable)(struct dc_link *link, bool enable); + bool (*dp_setup_replay)(struct dc_link *link, const struct dc_stream_state *stream); + bool (*dp_pr_get_panel_inst)(const struct dc *dc, const struct dc_link *link, unsigned int *inst_out); bool (*dp_pr_enable)(struct dc_link *link, bool enable); bool (*dp_pr_update_state)(struct dc_link *link, struct dmub_cmd_pr_update_state_data *update_state_data); bool (*dp_pr_set_general_cmd)(struct dc_link *link, struct dmub_cmd_pr_general_cmd_data *general_cmd_data); diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c index 7e46ea98952c..91742bde4dc2 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c @@ -46,6 +46,7 @@ #include "protocols/link_dp_capability.h" #include "protocols/link_dp_training.h" #include "protocols/link_edp_panel_control.h" +#include "protocols/link_dp_panel_replay.h" #include "protocols/link_dp_dpia_bw.h" #include "dm_helpers.h" @@ -2529,6 +2530,9 @@ void link_set_dpms_on( link_set_dsc_enable(pipe_ctx, true); } + if (link->replay_settings.config.replay_supported && !dc_is_embedded_signal(link->connector_signal)) + dp_setup_replay(link, stream); + status = enable_link(state, pipe_ctx); if (status != DC_OK) { diff --git a/drivers/gpu/drm/amd/display/dc/link/link_factory.c b/drivers/gpu/drm/amd/display/dc/link/link_factory.c index e185f2caad0c..5fbcf04c6251 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_factory.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_factory.c @@ -236,6 +236,7 @@ static void construct_link_service_edp_panel_control(struct link_service *link_s static void construct_link_service_dp_panel_replay(struct link_service *link_srv) { link_srv->dp_setup_replay = dp_setup_replay; + link_srv->dp_pr_get_panel_inst = dp_pr_get_panel_inst; link_srv->dp_pr_enable = dp_pr_enable; link_srv->dp_pr_update_state = dp_pr_update_state; link_srv->dp_pr_set_general_cmd = dp_pr_set_general_cmd; diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.c index fdbfa5103183..be441851d876 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.c @@ -75,7 +75,7 @@ static bool dp_setup_panel_replay(struct dc_link *link, const struct dc_stream_s if (!replay) return false; - if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) + if (!dp_pr_get_panel_inst(dc, link, &panel_inst)) return false; replay_context.aux_inst = link->ddc->ddc_pin->hw_info.ddc_channel; @@ -103,14 +103,18 @@ static bool dp_setup_panel_replay(struct dc_link *link, const struct dc_stream_s link->replay_settings.replay_feature_enabled = dp_pr_copy_settings(link, &replay_context); if (link->replay_settings.replay_feature_enabled) { - pr_config_1.bits.PANEL_REPLAY_ENABLE = 1; - pr_config_1.bits.PANEL_REPLAY_CRC_ENABLE = 1; - pr_config_1.bits.IRQ_HPD_ASSDP_MISSING = 1; - pr_config_1.bits.IRQ_HPD_VSCSDP_UNCORRECTABLE_ERROR = 1; - pr_config_1.bits.IRQ_HPD_RFB_ERROR = 1; - pr_config_1.bits.IRQ_HPD_ACTIVE_FRAME_CRC_ERROR = 1; - pr_config_1.bits.PANEL_REPLAY_SELECTIVE_UPDATE_ENABLE = 1; - pr_config_1.bits.PANEL_REPLAY_EARLY_TRANSPORT_ENABLE = 1; + if (dc_is_embedded_signal(link->connector_signal)) { + pr_config_1.bits.PANEL_REPLAY_ENABLE = 1; + pr_config_1.bits.PANEL_REPLAY_CRC_ENABLE = 1; + pr_config_1.bits.IRQ_HPD_ASSDP_MISSING = 1; + pr_config_1.bits.IRQ_HPD_VSCSDP_UNCORRECTABLE_ERROR = 1; + pr_config_1.bits.IRQ_HPD_RFB_ERROR = 1; + pr_config_1.bits.IRQ_HPD_ACTIVE_FRAME_CRC_ERROR = 1; + pr_config_1.bits.PANEL_REPLAY_SELECTIVE_UPDATE_ENABLE = 1; + pr_config_1.bits.PANEL_REPLAY_EARLY_TRANSPORT_ENABLE = 1; + } else { + pr_config_1.bits.PANEL_REPLAY_ENABLE = 1; + } pr_config_2.bits.SINK_REFRESH_RATE_UNLOCK_GRANTED = 0; @@ -147,6 +151,23 @@ static bool dp_setup_panel_replay(struct dc_link *link, const struct dc_stream_s return true; } + +bool dp_pr_get_panel_inst(const struct dc *dc, + const struct dc_link *link, + unsigned int *inst_out) +{ + if (dc_is_embedded_signal(link->connector_signal)) { + /* TODO: just get edp link panel inst for now, fix it */ + return dc_get_edp_link_panel_inst(dc, link, inst_out); + } else if (dc_is_dp_sst_signal(link->connector_signal)) { + /* TODO: just set to 1 for now, fix it */ + *inst_out = 1; + return true; + } + + return false; +} + bool dp_setup_replay(struct dc_link *link, const struct dc_stream_state *stream) { if (!link) @@ -165,7 +186,7 @@ bool dp_pr_enable(struct dc_link *link, bool enable) unsigned int panel_inst = 0; union dmub_rb_cmd cmd; - if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) + if (!dp_pr_get_panel_inst(dc, link, &panel_inst)) return false; if (link->replay_settings.replay_allow_active != enable) { @@ -192,16 +213,16 @@ bool dp_pr_copy_settings(struct dc_link *link, struct replay_context *replay_con union dmub_rb_cmd cmd; struct pipe_ctx *pipe_ctx = NULL; - if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) + if (!dp_pr_get_panel_inst(dc, link, &panel_inst)) return false; for (unsigned int i = 0; i < MAX_PIPES; i++) { if (dc->current_state->res_ctx.pipe_ctx[i].stream && dc->current_state->res_ctx.pipe_ctx[i].stream->link && dc->current_state->res_ctx.pipe_ctx[i].stream->link == link && - dc->current_state->res_ctx.pipe_ctx[i].stream->link->connector_signal == SIGNAL_TYPE_EDP) { + dc_is_dp_sst_signal(dc->current_state->res_ctx.pipe_ctx[i].stream->link->connector_signal)) { pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; - //TODO: refactor for multi edp support + /* todo: need update for MST */ break; } } @@ -255,7 +276,7 @@ bool dp_pr_update_state(struct dc_link *link, struct dmub_cmd_pr_update_state_da unsigned int panel_inst = 0; union dmub_rb_cmd cmd; - if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) + if (!dp_pr_get_panel_inst(dc, link, &panel_inst)) return false; memset(&cmd, 0, sizeof(cmd)); @@ -276,7 +297,7 @@ bool dp_pr_set_general_cmd(struct dc_link *link, struct dmub_cmd_pr_general_cmd_ unsigned int panel_inst = 0; union dmub_rb_cmd cmd; - if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) + if (!dp_pr_get_panel_inst(dc, link, &panel_inst)) return false; memset(&cmd, 0, sizeof(cmd)); @@ -298,7 +319,7 @@ bool dp_pr_get_state(const struct dc_link *link, uint64_t *state) uint32_t retry_count = 0; uint32_t replay_state = 0; - if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) + if (!dp_pr_get_panel_inst(dc, link, &panel_inst)) return false; do { diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.h index b936092edb85..5522d5911fd1 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.h +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.h @@ -27,8 +27,8 @@ #include "link_service.h" -bool dp_setup_replay(struct dc_link *link, - const struct dc_stream_state *stream); +bool dp_setup_replay(struct dc_link *link, const struct dc_stream_state *stream); +bool dp_pr_get_panel_inst(const struct dc *dc, const struct dc_link *link, unsigned int *inst_out); bool dp_pr_enable(struct dc_link *link, bool enable); bool dp_pr_copy_settings(struct dc_link *link, struct replay_context *replay_context); bool dp_pr_update_state(struct dc_link *link, struct dmub_cmd_pr_update_state_data *update_state_data); From cb958039323634631126cdbc94216b4037fee243 Mon Sep 17 00:00:00 2001 From: Peichen Huang Date: Wed, 24 Dec 2025 11:43:18 +0800 Subject: [PATCH 47/69] drm/amd/display: Add replay_events in replay settings Add a new field to replay_settings. Reviewed-by: Robin Chen Signed-off-by: Peichen Huang Signed-off-by: Matthew Stewart Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc_types.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index 5e71156d28e3..bb1387233bd8 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -1223,6 +1223,8 @@ struct replay_settings { uint32_t replay_desync_error_fail_count; /* The frame skip number dal send to DMUB */ uint16_t frame_skip_number; + /* Current Panel Replay event */ + uint32_t replay_events; }; /* To split out "global" and "per-panel" config settings. From 75372d75a4e23783583998ed99d5009d555850da Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Wed, 17 Dec 2025 13:21:59 -0500 Subject: [PATCH 48/69] drm/amd/display: Adjust PHY FSM transition to TX_EN-to-PLL_ON for TMDS on DCN35 [Why] A backport of the change made for DCN401 that addresses an issue where we turn off the PHY PLL when disabling TMDS output, which causes the OTG to remain stuck. The OTG being stuck can lead to a hang in the DCHVM's ability to ACK invalidations when it thinks the HUBP is still on but it's not receiving global sync. The transition to PLL_ON needs to be atomic as there's no guarantee that the thread isn't pre-empted or is able to complete before the IOMMU watchdog times out. [How] Backport the implementation from dcn401 back to dcn35. There's a functional difference in when the eDP output is disabled in dcn401 code so we don't want to utilize it directly. Reviewed-by: Yihan Zhu Signed-off-by: Nicholas Kazlauskas Signed-off-by: Matthew Stewart Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../amd/display/dc/hwss/dcn35/dcn35_hwseq.c | 52 +++++++++++++++++++ .../amd/display/dc/hwss/dcn35/dcn35_hwseq.h | 3 ++ .../amd/display/dc/hwss/dcn35/dcn35_init.c | 2 +- 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c index 1271bf55dac3..2675d7dca586 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c @@ -1727,3 +1727,55 @@ void dcn35_program_cursor_offload_now(struct dc *dc, const struct pipe_ctx *pipe { dc_dmub_srv_program_cursor_now(dc, pipe); } + +static void disable_link_output_symclk_on_tx_off(struct dc_link *link, enum dp_link_encoding link_encoding) +{ + struct dc *dc = link->ctx->dc; + struct pipe_ctx *pipe_ctx = NULL; + uint8_t i; + + for (i = 0; i < MAX_PIPES; i++) { + pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe_ctx->stream && pipe_ctx->stream->link == link && pipe_ctx->top_pipe == NULL) { + pipe_ctx->clock_source->funcs->program_pix_clk( + pipe_ctx->clock_source, + &pipe_ctx->stream_res.pix_clk_params, + link_encoding, + &pipe_ctx->pll_settings); + break; + } + } +} + +void dcn35_disable_link_output(struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal) +{ + struct dc *dc = link->ctx->dc; + const struct link_hwss *link_hwss = get_link_hwss(link, link_res); + struct dmcu *dmcu = dc->res_pool->dmcu; + + if (signal == SIGNAL_TYPE_EDP && + link->dc->hwss.edp_backlight_control && + !link->skip_implict_edp_power_control) + link->dc->hwss.edp_backlight_control(link, false); + else if (dmcu != NULL && dmcu->funcs->lock_phy) + dmcu->funcs->lock_phy(dmcu); + + if (dc_is_tmds_signal(signal) && link->phy_state.symclk_ref_cnts.otg > 0) { + disable_link_output_symclk_on_tx_off(link, DP_UNKNOWN_ENCODING); + link->phy_state.symclk_state = SYMCLK_ON_TX_OFF; + } else { + link_hwss->disable_link_output(link, link_res, signal); + link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF; + } + /* + * Add the logic to extract BOTH power up and power down sequences + * from enable/disable link output and only call edp panel control + * in enable_link_dp and disable_link_dp once. + */ + if (dmcu != NULL && dmcu->funcs->unlock_phy) + dmcu->funcs->unlock_phy(dmcu); + + dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY); +} diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h index 1ff41dba556c..e3459546a908 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h @@ -108,5 +108,8 @@ void dcn35_update_cursor_offload_pipe(struct dc *dc, const struct pipe_ctx *pipe void dcn35_notify_cursor_offload_drr_update(struct dc *dc, struct dc_state *context, const struct dc_stream_state *stream); void dcn35_program_cursor_offload_now(struct dc *dc, const struct pipe_ctx *pipe); +void dcn35_disable_link_output(struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal); #endif /* __DC_HWSS_DCN35_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c index 5a66c9db2670..81bd36f3381d 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c @@ -113,7 +113,7 @@ static const struct hw_sequencer_funcs dcn35_funcs = { .enable_lvds_link_output = dce110_enable_lvds_link_output, .enable_tmds_link_output = dce110_enable_tmds_link_output, .enable_dp_link_output = dce110_enable_dp_link_output, - .disable_link_output = dcn32_disable_link_output, + .disable_link_output = dcn35_disable_link_output, .z10_restore = dcn35_z10_restore, .z10_save_init = dcn31_z10_save_init, .set_disp_pattern_generator = dcn30_set_disp_pattern_generator, From e9306b69e77574c676ebf3eeaa428da685cc6a25 Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Fri, 2 Jan 2026 10:25:03 -0500 Subject: [PATCH 49/69] drm/amd/display: Add pwait status to DMCUB debug logging [Why] To know if DMCUB is idle at the time of the debug data being collected. [How] Extend the logging to include the field. It's already captured as part of each ASIC's get_diagnostic_data. Reviewed-by: Dillon Varone Signed-off-by: Nicholas Kazlauskas Signed-off-by: Matthew Stewart Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c | 1 + 1 file changed, 1 insertion(+) 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 602655dd1323..2dc6ae6b5bea 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c @@ -999,6 +999,7 @@ void dc_dmub_srv_log_diagnostic_data(struct dc_dmub_srv *dc_dmub_srv) DC_LOG_DEBUG(" is_traceport_en : %d", dc_dmub_srv->dmub->debug.is_traceport_en); DC_LOG_DEBUG(" is_cw0_en : %d", dc_dmub_srv->dmub->debug.is_cw0_enabled); DC_LOG_DEBUG(" is_cw6_en : %d", dc_dmub_srv->dmub->debug.is_cw6_enabled); + DC_LOG_DEBUG(" is_pwait : %d", dc_dmub_srv->dmub->debug.is_pwait); } static bool dc_dmub_should_update_cursor_data(struct pipe_ctx *pipe_ctx) From 869e3869b9303ba104f14b70814cc5b4bb7ad7a9 Mon Sep 17 00:00:00 2001 From: Aurabindo Pillai Date: Tue, 30 Dec 2025 15:14:26 -0500 Subject: [PATCH 50/69] drm/amd/display: switch to drm_dbg_kms() from DRM_DEBUG_KMS DRM_DEBUG_ class of macros are depricated. Recommended drm_dbg_kms() has the advantage of being able to distinguish the logs from devices in a multi-gpu environment. Where a pointer to struct amdgpu_device is available, use that to get the drm device. Reviewed-by: Sun peng (Leo) Li Signed-off-by: Aurabindo Pillai Signed-off-by: Matthew Stewart Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 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 3977a6cf341b..79ee98be0dd0 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1137,7 +1137,7 @@ static int amdgpu_dm_audio_component_get_eld(struct device *kdev, int port, mutex_unlock(&adev->dm.audio_lock); - DRM_DEBUG_KMS("Get ELD : idx=%d ret=%d en=%d\n", port, ret, *enabled); + drm_dbg_kms(adev_to_drm(adev), "Get ELD : idx=%d ret=%d en=%d\n", port, ret, *enabled); return ret; } @@ -1231,7 +1231,7 @@ static void amdgpu_dm_audio_eld_notify(struct amdgpu_device *adev, int pin) struct drm_audio_component *acomp = adev->dm.audio_component; if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) { - DRM_DEBUG_KMS("Notify ELD: %d\n", pin); + drm_dbg_kms(adev_to_drm(adev), "Notify ELD: %d\n", pin); acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, pin, -1); @@ -2377,7 +2377,7 @@ static int load_dmcu_fw(struct amdgpu_device *adev) } if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) { - DRM_DEBUG_KMS("dm: DMCU firmware not supported on direct or SMU loading\n"); + drm_dbg_kms(adev_to_drm(adev), "dm: DMCU firmware not supported on direct or SMU loading\n"); return 0; } @@ -2385,7 +2385,7 @@ static int load_dmcu_fw(struct amdgpu_device *adev) "%s", fw_name_dmcu); if (r == -ENODEV) { /* DMCU firmware is not necessary, so don't raise a fuss if it's missing */ - DRM_DEBUG_KMS("dm: DMCU firmware not found\n"); + drm_dbg_kms(adev_to_drm(adev), "dm: DMCU firmware not found\n"); adev->dm.fw_dmcu = NULL; return 0; } @@ -2409,7 +2409,7 @@ static int load_dmcu_fw(struct amdgpu_device *adev) adev->dm.dmcu_fw_version = le32_to_cpu(hdr->header.ucode_version); - DRM_DEBUG_KMS("PSP loading DMCU firmware\n"); + drm_dbg_kms(adev_to_drm(adev), "PSP loading DMCU firmware\n"); return 0; } @@ -4157,7 +4157,7 @@ static void schedule_hpd_rx_offload_work(struct amdgpu_device *adev, struct hpd_ offload_work->adev = adev; queue_work(offload_wq->wq, &offload_work->work); - DRM_DEBUG_KMS("queue work to handle hpd_rx offload work"); + drm_dbg_kms(adev_to_drm(adev), "queue work to handle hpd_rx offload work"); } static void handle_hpd_rx_irq(void *param) @@ -4986,7 +4986,7 @@ static void amdgpu_dm_update_backlight_caps(struct amdgpu_display_manager *dm, caps->min_input_signal < 0 || spread > AMDGPU_DM_DEFAULT_MAX_BACKLIGHT || spread < AMDGPU_DM_MIN_SPREAD) { - DRM_DEBUG_KMS("DM: Invalid backlight caps: min=%d, max=%d\n", + drm_dbg_kms(adev_to_drm(dm->adev), "DM: Invalid backlight caps: min=%d, max=%d\n", caps->min_input_signal, caps->max_input_signal); caps->caps_valid = false; } @@ -5515,7 +5515,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) } break; default: - DRM_DEBUG_KMS("Unsupported DCN IP version for outbox: 0x%X\n", + drm_dbg_kms(adev_to_drm(adev), "Unsupported DCN IP version for outbox: 0x%X\n", amdgpu_ip_version(adev, DCE_HWIP, 0)); } @@ -9628,7 +9628,7 @@ static void update_freesync_state_on_stream( new_stream->allow_freesync = mod_freesync_get_freesync_enabled(&vrr_params); if (new_crtc_state->freesync_vrr_info_changed) - DRM_DEBUG_KMS("VRR packet update: crtc=%u enabled=%d state=%d", + drm_dbg_kms(adev_to_drm(adev), "VRR packet update: crtc=%u enabled=%d state=%d", new_crtc_state->base.crtc->base.id, (int)new_crtc_state->base.vrr_enabled, (int)vrr_params.state); @@ -11574,7 +11574,7 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm, dc_stream_retain(new_stream); - DRM_DEBUG_ATOMIC("Enabling DRM crtc: %d\n", + drm_dbg_atomic(adev_to_drm(adev), "Enabling DRM crtc: %d\n", crtc->base.id); if (dc_state_add_stream( @@ -11804,14 +11804,14 @@ static int dm_check_cursor_fb(struct amdgpu_crtc *new_acrtc, if (fb->width > new_acrtc->max_cursor_width || fb->height > new_acrtc->max_cursor_height) { - DRM_DEBUG_ATOMIC("Bad cursor FB size %dx%d\n", + drm_dbg_atomic(adev_to_drm(adev), "Bad cursor FB size %dx%d\n", new_plane_state->fb->width, new_plane_state->fb->height); return -EINVAL; } if (new_plane_state->src_w != fb->width << 16 || new_plane_state->src_h != fb->height << 16) { - DRM_DEBUG_ATOMIC("Cropping not supported for cursor plane\n"); + drm_dbg_atomic(adev_to_drm(adev), "Cropping not supported for cursor plane\n"); return -EINVAL; } @@ -11819,7 +11819,7 @@ static int dm_check_cursor_fb(struct amdgpu_crtc *new_acrtc, pitch = fb->pitches[0] / fb->format->cpp[0]; if (fb->width != pitch) { - DRM_DEBUG_ATOMIC("Cursor FB width %d doesn't match pitch %d", + drm_dbg_atomic(adev_to_drm(adev), "Cursor FB width %d doesn't match pitch %d", fb->width, pitch); return -EINVAL; } @@ -11831,7 +11831,7 @@ static int dm_check_cursor_fb(struct amdgpu_crtc *new_acrtc, /* FB pitch is supported by cursor plane */ break; default: - DRM_DEBUG_ATOMIC("Bad cursor FB pitch %d px\n", pitch); + drm_dbg_atomic(adev_to_drm(adev), "Bad cursor FB pitch %d px\n", pitch); return -EINVAL; } @@ -11849,7 +11849,7 @@ static int dm_check_cursor_fb(struct amdgpu_crtc *new_acrtc, AMDGPU_TILING_GET(afb->tiling_flags, MICRO_TILE_MODE) == 0; } if (!linear) { - DRM_DEBUG_ATOMIC("Cursor FB not linear"); + drm_dbg_atomic(adev_to_drm(adev), "Cursor FB not linear"); return -EINVAL; } } From 71573db5ad74b2087a4688cd1dda73ff082620f6 Mon Sep 17 00:00:00 2001 From: Aurabindo Pillai Date: Tue, 30 Dec 2025 15:21:18 -0500 Subject: [PATCH 51/69] drm/amd/display: switch to drm_dbg_ macros instead of DRM_DEBUG_ variants Device pointer sources used: - connector->dev - when a DRM connector was available - old_plane_crtc->dev / new_plane_crtc->dev - for plane state functions - pass in drm_device - for the stream scaling function - aconnector->base.dev - for the VSDB parsing function Reviewed-by: Sun peng (Leo) Li Signed-off-by: Aurabindo Pillai Signed-off-by: Matthew Stewart Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 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 79ee98be0dd0..c0e9d549a8a4 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -6418,7 +6418,8 @@ static void fill_dc_dirty_rects(struct drm_plane *plane, &flip_addrs->dirty_rect_count, true); } -static void update_stream_scaling_settings(const struct drm_display_mode *mode, +static void update_stream_scaling_settings(struct drm_device *dev, + const struct drm_display_mode *mode, const struct dm_connector_state *dm_state, struct dc_stream_state *stream) { @@ -6468,8 +6469,8 @@ static void update_stream_scaling_settings(const struct drm_display_mode *mode, stream->src = src; stream->dst = dst; - DRM_DEBUG_KMS("Destination Rectangle x:%d y:%d width:%d height:%d\n", - dst.x, dst.y, dst.width, dst.height); + drm_dbg_kms(dev, "Destination Rectangle x:%d y:%d width:%d height:%d\n", + dst.x, dst.y, dst.width, dst.height); } @@ -7357,7 +7358,7 @@ create_stream_for_sink(struct drm_connector *connector, apply_dsc_policy_for_stream(aconnector, sink, stream, &dsc_caps); #endif - update_stream_scaling_settings(&mode, dm_state, stream); + update_stream_scaling_settings(dev, &mode, dm_state, stream); fill_audio_info( &stream->audio_info, @@ -8092,7 +8093,7 @@ create_validate_stream_for_sink(struct drm_connector *connector, dc_result = dm_validate_stream_and_context(adev->dm.dc, stream); if (dc_result != DC_OK) { - DRM_DEBUG_KMS("Pruned mode %d x %d (clk %d) %s %s -- %s\n", + drm_dbg_kms(connector->dev, "Pruned mode %d x %d (clk %d) %s %s -- %s\n", drm_mode->hdisplay, drm_mode->vdisplay, drm_mode->clock, @@ -8444,7 +8445,7 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder, drm_dp_atomic_find_time_slots(state, mst_mgr, mst_port, dm_new_connector_state->pbn); if (dm_new_connector_state->vcpi_slots < 0) { - DRM_DEBUG_ATOMIC("failed finding vcpi slots: %d\n", (int)dm_new_connector_state->vcpi_slots); + drm_dbg_atomic(connector->dev, "failed finding vcpi slots: %d\n", (int)dm_new_connector_state->vcpi_slots); return dm_new_connector_state->vcpi_slots; } return 0; @@ -10894,7 +10895,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) stream_update.stream = dm_new_crtc_state->stream; if (scaling_changed) { - update_stream_scaling_settings(&dm_new_con_state->base.crtc->mode, + update_stream_scaling_settings(dev, &dm_new_con_state->base.crtc->mode, dm_new_con_state, dm_new_crtc_state->stream); stream_update.src = dm_new_crtc_state->stream->src; @@ -11613,7 +11614,7 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm, /* Scaling or underscan settings */ if (is_scaling_state_different(dm_old_conn_state, dm_new_conn_state) || drm_atomic_crtc_needs_modeset(new_crtc_state)) - update_stream_scaling_settings( + update_stream_scaling_settings(adev_to_drm(adev), &new_crtc_state->mode, dm_new_conn_state, dm_new_crtc_state->stream); /* ABM settings */ @@ -11876,7 +11877,7 @@ static int dm_check_native_cursor_state(struct drm_crtc *new_plane_crtc, new_acrtc = to_amdgpu_crtc(new_plane_crtc); if (new_plane_state->src_x != 0 || new_plane_state->src_y != 0) { - DRM_DEBUG_ATOMIC("Cropping not supported for cursor plane\n"); + drm_dbg_atomic(new_plane_crtc->dev, "Cropping not supported for cursor plane\n"); return -EINVAL; } @@ -11975,7 +11976,7 @@ static int dm_update_plane_state(struct dc *dc, if (!dm_old_crtc_state->stream) return 0; - DRM_DEBUG_ATOMIC("Disabling DRM plane: %d on DRM crtc %d\n", + drm_dbg_atomic(old_plane_crtc->dev, "Disabling DRM plane: %d on DRM crtc %d\n", plane->base.id, old_plane_crtc->base.id); ret = dm_atomic_get_state(state, &dm_state); @@ -12028,7 +12029,7 @@ static int dm_update_plane_state(struct dc *dc, goto out; } - DRM_DEBUG_ATOMIC("Enabling DRM plane: %d on DRM crtc %d\n", + drm_dbg_atomic(new_plane_crtc->dev, "Enabling DRM plane: %d on DRM crtc %d\n", plane->base.id, new_plane_crtc->base.id); ret = fill_dc_plane_attributes( @@ -13120,7 +13121,7 @@ static int parse_amd_vsdb(struct amdgpu_dm_connector *aconnector, amd_vsdb->version == HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_VERSION_3) { vsdb_info->replay_mode = (amd_vsdb->feature_caps & AMD_VSDB_VERSION_3_FEATURECAP_REPLAYMODE) ? true : false; vsdb_info->amd_vsdb_version = HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_VERSION_3; - DRM_DEBUG_KMS("Panel supports Replay Mode: %d\n", vsdb_info->replay_mode); + drm_dbg_kms(aconnector->base.dev, "Panel supports Replay Mode: %d\n", vsdb_info->replay_mode); return true; } From 15acb306c9efb98eaf760c76e3b02a6b7e2b974f Mon Sep 17 00:00:00 2001 From: Taimur Hassan Date: Fri, 2 Jan 2026 16:30:05 -0500 Subject: [PATCH 52/69] drm/amd/display: [FW Promotion] Release 0.1.42.0 Summary for changes in firmware: * Fix 24/30FPS full screen video low residency * Fix 60Hz video playback freeze * Add Panel Replay command for VESA replay Signed-off-by: Taimur Hassan Signed-off-by: Matthew Stewart Tested-by: Dan Wheeler Acked-by: Leo Li Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) 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 04c79069670a..9d0852760e78 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -1091,7 +1091,10 @@ union dmub_fw_boot_options { uint32_t lower_hbr3_phy_ssc: 1; /**< 1 to lower hbr3 phy ssc to 0.125 percent */ uint32_t override_hbr3_pll_vco: 1; /**< 1 to override the hbr3 pll vco to 0 */ uint32_t disable_dpia_bw_allocation: 1; /**< 1 to disable the USB4 DPIA BW allocation */ - uint32_t reserved : 4; /**< reserved */ + uint32_t bootcrc_en_at_preos: 1; /**< 1 to run the boot time crc during warm/cold boot*/ + uint32_t bootcrc_en_at_S0i3: 1; /**< 1 to run the boot time crc during S0i3 boot*/ + uint32_t bootcrc_boot_mode: 1; /**< 1 for S0i3 resume and 0 for Warm/cold boot*/ + uint32_t reserved : 1; /**< reserved */ } bits; /**< boot bits */ uint32_t all; /**< 32-bit access to bits */ }; @@ -2638,7 +2641,7 @@ union dmub_fams2_global_feature_config { uint32_t enable_visual_confirm: 1; uint32_t allow_delay_check_mode: 2; uint32_t legacy_method_no_fams2 : 1; - uint32_t reserved: 23; + uint32_t reserved : 23; } bits; uint32_t all; }; @@ -4375,6 +4378,7 @@ enum dmub_cmd_replay_general_subtype { REPLAY_GENERAL_CMD_UPDATE_ERROR_STATUS, REPLAY_GENERAL_CMD_SET_LOW_RR_ACTIVATE, REPLAY_GENERAL_CMD_VIDEO_CONFERENCING, + REPLAY_GENERAL_CMD_SET_CONTINUOUSLY_RESYNC, }; struct dmub_alpm_auxless_data { From fff90bb3d4e56586e06d405b683af67d6271023b Mon Sep 17 00:00:00 2001 From: Taimur Hassan Date: Fri, 2 Jan 2026 16:33:41 -0500 Subject: [PATCH 53/69] drm/amd/display: Promote DC to 3.2.365 This version brings along the following updates: - Cleanup, refactoring of panel replay code to prepare for non-eDP replay - Switch to drm_dbg_macros instead of DRM_DEBUG variants - Add pwait status to DMCUB debug logging - Adjust PHY FSM transition to TX_EN-to-PLL_ON for TMDS on DCN35 - Always update divider settings for DP tunnel - correct clip x assignment in cursor programming - Bump the HDMI clock to 340MHz Signed-off-by: Taimur Hassan Signed-off-by: Matthew Stewart Tested-by: Dan Wheeler Acked-by: Leo Li 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 69fa7fc02fa8..fc3dd1054710 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -63,7 +63,7 @@ struct dcn_dsc_reg_state; struct dcn_optc_reg_state; struct dcn_dccg_reg_state; -#define DC_VER "3.2.364" +#define DC_VER "3.2.365" /** * MAX_SURFACES - representative of the upper bound of surfaces that can be piped to a single CRTC From 318b1c36d82a0cd2b06a4bb43272fa6f1bc8adc1 Mon Sep 17 00:00:00 2001 From: Vivek Das Mohapatra Date: Mon, 12 Jan 2026 15:28:56 +0000 Subject: [PATCH 54/69] drm/amd/display: Initialise backlight level values from hw Internal backlight levels are initialised from ACPI but the values are sometimes out of sync with the levels in effect until there has been a read from hardware (eg triggered by reading from sysfs). This means that the first drm_commit can cause the levels to be set to a different value than the actual starting one, which results in a sudden change in brightness. This path shows the problem (when the values are out of sync): amdgpu_dm_atomic_commit_tail() -> amdgpu_dm_commit_streams() -> amdgpu_dm_backlight_set_level(..., dm->brightness[n]) This patch calls the backlight ops get_brightness explicitly at the end of backlight registration to make sure dm->brightness[n] is in sync with the actual hardware levels. Fixes: 2fe87f54abdc ("drm/amd/display: Set default brightness according to ACPI") Signed-off-by: Vivek Das Mohapatra Reviewed-by: Mario Limonciello (AMD) Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) 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 c0e9d549a8a4..157efedda358 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -5279,6 +5279,8 @@ amdgpu_dm_register_backlight_device(struct amdgpu_dm_connector *aconnector) struct amdgpu_dm_backlight_caps *caps; char bl_name[16]; int min, max; + int real_brightness; + int init_brightness; if (aconnector->bl_idx == -1) return; @@ -5303,6 +5305,8 @@ amdgpu_dm_register_backlight_device(struct amdgpu_dm_connector *aconnector) } else props.brightness = props.max_brightness = MAX_BACKLIGHT_LEVEL; + init_brightness = props.brightness; + if (caps->data_points && !(amdgpu_dc_debug_mask & DC_DISABLE_CUSTOM_BRIGHTNESS_CURVE)) { drm_info(drm, "Using custom brightness curve\n"); props.scale = BACKLIGHT_SCALE_NON_LINEAR; @@ -5321,8 +5325,20 @@ amdgpu_dm_register_backlight_device(struct amdgpu_dm_connector *aconnector) if (IS_ERR(dm->backlight_dev[aconnector->bl_idx])) { drm_err(drm, "DM: Backlight registration failed!\n"); dm->backlight_dev[aconnector->bl_idx] = NULL; - } else + } else { + /* + * dm->brightness[x] can be inconsistent just after startup until + * ops.get_brightness is called. + */ + real_brightness = + amdgpu_dm_backlight_ops.get_brightness(dm->backlight_dev[aconnector->bl_idx]); + + if (real_brightness != init_brightness) { + dm->actual_brightness[aconnector->bl_idx] = real_brightness; + dm->brightness[aconnector->bl_idx] = real_brightness; + } drm_dbg_driver(drm, "DM: Registered Backlight device: %s\n", bl_name); + } } static int initialize_plane(struct amdgpu_display_manager *dm, From 42ea9cf2f16b7131cb7302acb3dac510968f8bdc Mon Sep 17 00:00:00 2001 From: Donet Tom Date: Mon, 12 Jan 2026 19:36:54 +0530 Subject: [PATCH 55/69] drm/amdkfd: Relax size checking during queue buffer get MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit HW-supported EOP buffer sizes are 4K and 32K. On systems that do not use 4K pages, the minimum buffer object (BO) allocation size is PAGE_SIZE (for example, 64K). During queue buffer acquisition, the driver currently checks the allocated BO size against the supported EOP buffer size. Since the allocated BO is larger than the expected size, this check fails, preventing queue creation. Relax the strict size validation and allow PAGE_SIZE-sized BOs to be used. Only the required 4K region of the buffer will be used as the EOP buffer and avoids queue creation failures on non-4K page systems. Acked-by: Christian König Suggested-by: Philip Yang Signed-off-by: Donet Tom Signed-off-by: Felix Kuehling Reviewed-by: Felix Kuehling Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_queue.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_queue.c b/drivers/gpu/drm/amd/amdkfd/kfd_queue.c index 1b465fdb2c64..d1978e3f68be 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_queue.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_queue.c @@ -278,8 +278,8 @@ int kfd_queue_acquire_buffers(struct kfd_process_device *pdd, struct queue_prope /* EOP buffer is not required for all ASICs */ if (properties->eop_ring_buffer_address) { - if (properties->eop_ring_buffer_size != topo_dev->node_props.eop_buffer_size) { - pr_debug("queue eop bo size 0x%x not equal to node eop buf size 0x%x\n", + if (properties->eop_ring_buffer_size < topo_dev->node_props.eop_buffer_size) { + pr_debug("queue eop bo size 0x%x is less than node eop buf size 0x%x\n", properties->eop_ring_buffer_size, topo_dev->node_props.eop_buffer_size); err = -EINVAL; @@ -287,7 +287,7 @@ int kfd_queue_acquire_buffers(struct kfd_process_device *pdd, struct queue_prope } err = kfd_queue_buffer_get(vm, (void *)properties->eop_ring_buffer_address, &properties->eop_buf_bo, - properties->eop_ring_buffer_size); + ALIGN(properties->eop_ring_buffer_size, PAGE_SIZE)); if (err) goto out_err_unreserve; } From fb361a520a5861368c6c36717ff1900a35dde093 Mon Sep 17 00:00:00 2001 From: Donet Tom Date: Mon, 12 Jan 2026 19:36:55 +0530 Subject: [PATCH 56/69] drm/amdkfd: Fix SVM map/unmap address conversion for non-4k page sizes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SVM range size is tracked using the system page size. The range start and end are aligned to system page-sized PFNs, so the total SVM range size equals the total number of pages in the SVM range multiplied by the system page size. The SVM range map/unmap functions pass these system page-sized PFN numbers to amdgpu_vm_update_range(), which expects PFNs based on the GPU page size (4K). On non-4K page systems, this mismatch causes only part of the SVM range to be mapped in the GPU page table, while the rest remains unmapped. If the GPU accesses an unmapped address within the same range, it results in a GPU page fault. To fix this, the required conversion has been added in both svm_range_map_to_gpu() and svm_range_unmap_from_gpu(), ensuring that all pages in the SVM range are correctly mapped on non-4K systems. Acked-by: Christian König Reviewed-by: Philip Yang Signed-off-by: Ritesh Harjani (IBM) Signed-off-by: Donet Tom Signed-off-by: Felix Kuehling Reviewed-by: Felix Kuehling Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 29 ++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index 1ed08388d364..35036d47657b 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -1355,11 +1355,16 @@ svm_range_unmap_from_gpu(struct amdgpu_device *adev, struct amdgpu_vm *vm, struct dma_fence **fence) { uint64_t init_pte_value = adev->gmc.init_pte_flags; + uint64_t gpu_start, gpu_end; - pr_debug("[0x%llx 0x%llx]\n", start, last); + /* Convert CPU page range to GPU page range */ + gpu_start = start * AMDGPU_GPU_PAGES_IN_CPU_PAGE; + gpu_end = (last + 1) * AMDGPU_GPU_PAGES_IN_CPU_PAGE - 1; - return amdgpu_vm_update_range(adev, vm, false, true, true, false, NULL, start, - last, init_pte_value, 0, 0, NULL, NULL, + pr_debug("CPU[0x%llx 0x%llx] -> GPU[0x%llx 0x%llx]\n", start, last, + gpu_start, gpu_end); + return amdgpu_vm_update_range(adev, vm, false, true, true, false, NULL, gpu_start, + gpu_end, init_pte_value, 0, 0, NULL, NULL, fence); } @@ -1439,6 +1444,9 @@ svm_range_map_to_gpu(struct kfd_process_device *pdd, struct svm_range *prange, last_start, last_start + npages - 1, readonly); for (i = offset; i < offset + npages; i++) { + uint64_t gpu_start; + uint64_t gpu_end; + last_domain = dma_addr[i] & SVM_RANGE_VRAM_DOMAIN; dma_addr[i] &= ~SVM_RANGE_VRAM_DOMAIN; @@ -1456,17 +1464,22 @@ svm_range_map_to_gpu(struct kfd_process_device *pdd, struct svm_range *prange, if (readonly) pte_flags &= ~AMDGPU_PTE_WRITEABLE; - pr_debug("svms 0x%p map [0x%lx 0x%llx] vram %d PTE 0x%llx\n", - prange->svms, last_start, prange->start + i, - (last_domain == SVM_RANGE_VRAM_DOMAIN) ? 1 : 0, - pte_flags); /* For dGPU mode, we use same vm_manager to allocate VRAM for * different memory partition based on fpfn/lpfn, we should use * same vm_manager.vram_base_offset regardless memory partition. */ + gpu_start = last_start * AMDGPU_GPU_PAGES_IN_CPU_PAGE; + gpu_end = (prange->start + i + 1) * AMDGPU_GPU_PAGES_IN_CPU_PAGE - 1; + + pr_debug("svms 0x%p map CPU[0x%lx 0x%llx] GPU[0x%llx 0x%llx] vram %d PTE 0x%llx\n", + prange->svms, last_start, prange->start + i, + gpu_start, gpu_end, + (last_domain == SVM_RANGE_VRAM_DOMAIN) ? 1 : 0, + pte_flags); + r = amdgpu_vm_update_range(adev, vm, false, false, flush_tlb, true, - NULL, last_start, prange->start + i, + NULL, gpu_start, gpu_end, pte_flags, (last_start - prange->start) << PAGE_SHIFT, bo_adev ? bo_adev->vm_manager.vram_base_offset : 0, From 6c160001661b6c4e20f5c31909c722741e14c2d8 Mon Sep 17 00:00:00 2001 From: Donet Tom Date: Mon, 12 Jan 2026 19:36:56 +0530 Subject: [PATCH 57/69] drm/amdkfd: Fix GART PTE for non-4K pagesize in svm_migrate_gart_map() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In svm_migrate_gart_map(), while migrating GART mapping, the number of bytes copied for the GART table only accounts for CPU pages. On non-4K systems, each CPU page can contain multiple GPU pages, and the GART requires one 8-byte PTE per GPU page. As a result, an incorrect size was passed to the DMA, causing only a partial update of the GART table. Fix this function to work correctly on non-4K page-size systems by accounting for the number of GPU pages per CPU page when calculating the number of bytes to be copied. Acked-by: Christian König Reviewed-by: Philip Yang Signed-off-by: Ritesh Harjani (IBM) Signed-off-by: Donet Tom Signed-off-by: Felix Kuehling Reviewed-by: Felix Kuehling Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_migrate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c index 4e0629cbd7f8..3df2bbd935e2 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c @@ -63,7 +63,7 @@ svm_migrate_gart_map(struct amdgpu_ring *ring, *gart_addr = adev->gmc.gart_start; num_dw = ALIGN(adev->mman.buffer_funcs->copy_num_dw, 8); - num_bytes = npages * 8; + num_bytes = npages * 8 * AMDGPU_GPU_PAGES_IN_CPU_PAGE; r = amdgpu_job_alloc_with_ib(adev, &entity->base, AMDGPU_FENCE_OWNER_UNDEFINED, From d81e52fc61fb98dc98f9fdb166ab21f502cb701c Mon Sep 17 00:00:00 2001 From: Yang Wang Date: Mon, 12 Jan 2026 17:48:26 +0800 Subject: [PATCH 58/69] drm/amd/pm: fix issue of missing '*' on pp_dpm_xxx nodes refine the code to fix '*' missing on pp_dpm_xxx series node. e.g.: missing '*' on navi10 pp_dpm_sclk $ cat /sys/class/drm/card0/device/pp_dpm_sclk 0: 300Mhz 1: 1930Mhz (missing symbol '*') Fixes: a08ea4bc7711 ("drm/amd/pm: Add a helper to show dpm table") Signed-off-by: Yang Wang Reviewed-by: Lijo Lazar Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 31 +++++++++++++------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c index 5b1f059105d6..24835600c1cd 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c @@ -1286,11 +1286,11 @@ int smu_cmn_print_dpm_clk_levels(struct smu_context *smu, struct smu_dpm_table *dpm_table, uint32_t cur_clk, char *buf, int *offset) { - uint32_t min_clk, level_index, count; - uint32_t freq_values[3] = { 0 }; + uint32_t min_clk, max_clk, level_index, count; + uint32_t freq_values[3]; + int size, lvl, i; bool is_fine_grained; bool is_deep_sleep; - int size, lvl, i; bool freq_match; if (!dpm_table || !buf) @@ -1301,6 +1301,7 @@ int smu_cmn_print_dpm_clk_levels(struct smu_context *smu, count = dpm_table->count; is_fine_grained = dpm_table->flags & SMU_DPM_TABLE_FINE_GRAINED; min_clk = SMU_DPM_TABLE_MIN(dpm_table); + max_clk = SMU_DPM_TABLE_MAX(dpm_table); /* Deep sleep - current clock < min_clock/2, TBD: cur_clk = 0 as GFXOFF */ is_deep_sleep = cur_clk < min_clk / 2; @@ -1321,22 +1322,22 @@ int smu_cmn_print_dpm_clk_levels(struct smu_context *smu, freq_match ? "*" : ""); } } else { + count = 2; freq_values[0] = min_clk; - freq_values[2] = SMU_DPM_TABLE_MAX(dpm_table); - freq_values[1] = cur_clk; + freq_values[1] = max_clk; - lvl = -1; if (!is_deep_sleep) { - lvl = 1; - if (smu_cmn_freqs_match(cur_clk, freq_values[0])) + if (smu_cmn_freqs_match(cur_clk, min_clk)) { lvl = 0; - else if (smu_cmn_freqs_match(cur_clk, freq_values[2])) - lvl = 2; - } - count = 3; - if (lvl != 1) { - count = 2; - freq_values[1] = freq_values[2]; + } else if (smu_cmn_freqs_match(cur_clk, max_clk)) { + lvl = 1; + } else { + /* NOTE: use index '1' to show current clock value */ + lvl = 1; + count = 3; + freq_values[1] = cur_clk; + freq_values[2] = max_clk; + } } for (i = 0; i < count; i++) { From 6cca686dfce79bf5bd5c1a680ed38a9f20669e39 Mon Sep 17 00:00:00 2001 From: Xiaogang Chen Date: Tue, 13 Jan 2026 20:45:14 -0600 Subject: [PATCH 59/69] drm/amdkfd: kfd driver supports hot unplug/replug amdgpu devices This patch allows kfd driver function correctly when AMD gpu devices got unplug/replug at run time. When an AMD gpu device got unplug kfd driver gracefully terminates existing kfd processes after stops all queues by sending SIGBUS to user process. After that user space can still use remaining AMD gpu devices. When all AMD gpu devices at system got removed kfd driver will not response new requests. Unplugged AMD gpu devices can be re-plugged. kfd driver will use added devices to function as usual. The purpose of this patch is having kfd driver behavior as expected during and after AMD gpu devices unplug/replug at run time. Signed-off-by: Xiaogang Chen Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 5 ++ drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h | 11 ++++ drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 1 + drivers/gpu/drm/amd/amdkfd/kfd_device.c | 76 +++++++++++++++++++++- drivers/gpu/drm/amd/amdkfd/kfd_events.c | 29 +++++++++ drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 2 + drivers/gpu/drm/amd/amdkfd/kfd_process.c | 12 +++- drivers/gpu/drm/amd/amdkfd/kfd_topology.c | 22 +++++++ 8 files changed, 156 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 67a01c4f3885..f958fef253da 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -248,6 +248,11 @@ void amdgpu_amdkfd_interrupt(struct amdgpu_device *adev, kgd2kfd_interrupt(adev->kfd.dev, ih_ring_entry); } +void amdgpu_amdkfd_teardown_processes(struct amdgpu_device *adev) +{ + kgd2kfd_teardown_processes(adev); +} + void amdgpu_amdkfd_suspend(struct amdgpu_device *adev, bool suspend_proc) { if (adev->kfd.dev) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h index da4575676335..eba9556ece9a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h @@ -158,6 +158,7 @@ struct amdkfd_process_info { int amdgpu_amdkfd_init(void); void amdgpu_amdkfd_fini(void); +void amdgpu_amdkfd_teardown_processes(struct amdgpu_device *adev); void amdgpu_amdkfd_suspend(struct amdgpu_device *adev, bool suspend_proc); int amdgpu_amdkfd_resume(struct amdgpu_device *adev, bool resume_proc); @@ -438,6 +439,8 @@ int kgd2kfd_stop_sched_all_nodes(struct kfd_dev *kfd); bool kgd2kfd_compute_active(struct kfd_dev *kfd, uint32_t node_id); bool kgd2kfd_vmfault_fast_path(struct amdgpu_device *adev, struct amdgpu_iv_entry *entry, bool retry_fault); +void kgd2kfd_lock_kfd(void); +void kgd2kfd_teardown_processes(struct amdgpu_device *adev); #else static inline int kgd2kfd_init(void) @@ -550,5 +553,13 @@ static inline bool kgd2kfd_vmfault_fast_path(struct amdgpu_device *adev, struct return false; } +static inline void kgd2kfd_lock_kfd(void) +{ +} + +static inline void kgd2kfd_teardown_processes(struct amdgpu_device *adev) +{ +} + #endif #endif /* AMDGPU_AMDKFD_H_INCLUDED */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 33135b185fed..b2deb6a74eb2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -3510,6 +3510,7 @@ static int amdgpu_device_ip_fini_early(struct amdgpu_device *adev) amdgpu_device_set_cg_state(adev, AMD_CG_STATE_UNGATE); amdgpu_amdkfd_suspend(adev, true); + amdgpu_amdkfd_teardown_processes(adev); amdgpu_userq_suspend(adev); /* Workaround for ASICs need to disable SMC first */ diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index db37c2949d19..640a9ab39fcd 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -973,6 +973,9 @@ void kgd2kfd_device_exit(struct kfd_dev *kfd) } kfree(kfd); + + /* after remove a kfd device unlock kfd driver */ + kgd2kfd_unlock_kfd(NULL); } int kgd2kfd_pre_reset(struct kfd_dev *kfd, @@ -1557,10 +1560,14 @@ int kgd2kfd_check_and_lock_kfd(struct kfd_dev *kfd) return r; } +/* unlock a kfd dev or kfd driver */ void kgd2kfd_unlock_kfd(struct kfd_dev *kfd) { mutex_lock(&kfd_processes_mutex); - --kfd->kfd_dev_lock; + if (kfd) + --kfd->kfd_dev_lock; + else + --kfd_locked; mutex_unlock(&kfd_processes_mutex); } @@ -1729,6 +1736,73 @@ bool kgd2kfd_vmfault_fast_path(struct amdgpu_device *adev, struct amdgpu_iv_entr return false; } +/* check if there is kfd process still uses adev */ +static bool kgd2kfd_check_device_idle(struct amdgpu_device *adev) +{ + struct kfd_process *p; + struct hlist_node *p_temp; + unsigned int temp; + struct kfd_node *dev; + + mutex_lock(&kfd_processes_mutex); + + if (hash_empty(kfd_processes_table)) { + mutex_unlock(&kfd_processes_mutex); + return true; + } + + /* check if there is device still use adev */ + hash_for_each_safe(kfd_processes_table, temp, p_temp, p, kfd_processes) { + for (int i = 0; i < p->n_pdds; i++) { + dev = p->pdds[i]->dev; + if (dev->adev == adev) { + mutex_unlock(&kfd_processes_mutex); + return false; + } + } + } + + mutex_unlock(&kfd_processes_mutex); + + return true; +} + +/** kgd2kfd_teardown_processes - gracefully tear down existing + * kfd processes that use adev + * + * @adev: amdgpu_device where kfd processes run on and will be + * teardown + * + */ +void kgd2kfd_teardown_processes(struct amdgpu_device *adev) +{ + struct hlist_node *p_temp; + struct kfd_process *p; + struct kfd_node *dev; + unsigned int temp; + + mutex_lock(&kfd_processes_mutex); + + if (hash_empty(kfd_processes_table)) { + mutex_unlock(&kfd_processes_mutex); + return; + } + + hash_for_each_safe(kfd_processes_table, temp, p_temp, p, kfd_processes) { + for (int i = 0; i < p->n_pdds; i++) { + dev = p->pdds[i]->dev; + if (dev->adev == adev) + kfd_signal_process_terminate_event(p); + } + } + + mutex_unlock(&kfd_processes_mutex); + + /* wait all kfd processes use adev terminate */ + while (!kgd2kfd_check_device_idle(adev)) + cond_resched(); +} + #if defined(CONFIG_DEBUG_FS) /* This function will send a package to HIQ to hang the HWS diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_events.c index 5a190dd6be4e..1ad312af8ff0 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_events.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_events.c @@ -1380,3 +1380,32 @@ void kfd_signal_poison_consumed_event(struct kfd_node *dev, u32 pasid) kfd_unref_process(p); } + +/* signal KFD_EVENT_TYPE_SIGNAL events from process p + * send signal SIGBUS to correspondent user space process + */ +void kfd_signal_process_terminate_event(struct kfd_process *p) +{ + struct kfd_event *ev; + u32 id; + + rcu_read_lock(); + + /* iterate from id 1 for KFD_EVENT_TYPE_SIGNAL events */ + id = 1; + idr_for_each_entry_continue(&p->event_idr, ev, id) + if (ev->type == KFD_EVENT_TYPE_SIGNAL) { + spin_lock(&ev->lock); + set_event(ev); + spin_unlock(&ev->lock); + } + + /* Send SIGBUS to p->lead_thread */ + dev_notice(kfd_device, + "Sending SIGBUS to process %d", + p->lead_thread->pid); + + send_sig(SIGBUS, p->lead_thread, 0); + + rcu_read_unlock(); +} diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index d798baa7e52e..eeeff9ffc1e3 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -1192,6 +1192,7 @@ static inline struct kfd_node *kfd_node_by_irq_ids(struct amdgpu_device *adev, } int kfd_topology_enum_kfd_devices(uint8_t idx, struct kfd_node **kdev); int kfd_numa_node_to_apic_id(int numa_node_id); +uint32_t kfd_gpu_node_num(void); /* Interrupts */ #define KFD_IRQ_FENCE_CLIENTID 0xff @@ -1547,6 +1548,7 @@ void kfd_signal_vm_fault_event(struct kfd_process_device *pdd, void kfd_signal_reset_event(struct kfd_node *dev); void kfd_signal_poison_consumed_event(struct kfd_node *dev, u32 pasid); +void kfd_signal_process_terminate_event(struct kfd_process *p); static inline void kfd_flush_tlb(struct kfd_process_device *pdd, enum TLB_FLUSH_TYPE type) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c index 593b3af10241..1f2d82730c44 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c @@ -949,6 +949,12 @@ struct kfd_process *kfd_create_process(struct task_struct *thread) */ mutex_lock(&kfd_processes_mutex); + if (kfd_gpu_node_num() <= 0) { + pr_warn("no gpu node! Cannot create KFD process"); + process = ERR_PTR(-EINVAL); + goto out; + } + if (kfd_is_locked(NULL)) { pr_debug("KFD is locked! Cannot create process"); process = ERR_PTR(-EINVAL); @@ -1235,7 +1241,6 @@ static void kfd_process_wq_release(struct work_struct *work) else ida_destroy(&p->id_table); - kfd_process_remove_sysfs(p); kfd_debugfs_remove_process(p); kfd_process_kunmap_signal_bo(p); @@ -1251,6 +1256,11 @@ static void kfd_process_wq_release(struct work_struct *work) put_task_struct(p->lead_thread); + /* the last step is removing process entries under /sys + * to indicate the process has been terminated. + */ + kfd_process_remove_sysfs(p); + kfree(p); } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c index 005a19602513..1ccd4514d3ee 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c @@ -2357,6 +2357,28 @@ int kfd_numa_node_to_apic_id(int numa_node_id) return kfd_cpumask_to_apic_id(cpumask_of_node(numa_node_id)); } +/* kfd_gpu_node_num - Return kfd gpu node number at system */ +uint32_t kfd_gpu_node_num(void) +{ + struct kfd_node *dev; + u8 gpu_num = 0; + u8 id = 0; + + while (kfd_topology_enum_kfd_devices(id, &dev) == 0) { + if (!dev || kfd_devcgroup_check_permission(dev)) { + /* Skip non GPU devices and devices to which the + * current process have no access to + */ + id++; + continue; + } + id++; + gpu_num++; + } + + return gpu_num; +} + #if defined(CONFIG_DEBUG_FS) int kfd_debugfs_hqds_by_device(struct seq_file *m, void *data) From e3a03d0ae16d6b56e893cce8e52b44140e1ed985 Mon Sep 17 00:00:00 2001 From: Yang Wang Date: Tue, 6 Jan 2026 14:42:40 +0800 Subject: [PATCH 60/69] drm/amd/pm: fix smu overdrive data type wrong issue on smu 14.0.2 resolving the issue of incorrect type definitions potentially causing calculation errors. Fixes: 54f7f3ca982a ("drm/amdgpu/swm14: Update power limit logic") Signed-off-by: Yang Wang Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c index 03c26d8248a3..faae1da81bd4 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c @@ -1632,8 +1632,9 @@ static int smu_v14_0_2_get_power_limit(struct smu_context *smu, table_context->power_play_table; PPTable_t *pptable = table_context->driver_pptable; CustomSkuTable_t *skutable = &pptable->CustomSkuTable; - uint32_t power_limit, od_percent_upper = 0, od_percent_lower = 0; + int16_t od_percent_upper = 0, od_percent_lower = 0; uint32_t msg_limit = pptable->SkuTable.MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC]; + uint32_t power_limit; if (smu_v14_0_get_current_power_limit(smu, &power_limit)) power_limit = smu->adev->pm.ac_power ? From bcd600ab7f2e8ebf7eb5b6ab28dd479341c389e0 Mon Sep 17 00:00:00 2001 From: Lang Yu Date: Wed, 17 Dec 2025 11:01:39 +0800 Subject: [PATCH 61/69] drm/amdkfd: Switch to using GC VERSION to decide LDS/Scratch base Next generation GC IP with 4-level page table needs to use the same LDS/Scratch base with 5-level page table, use GC VERSION to decide is more appropriate. Signed-off-by: Lang Yu Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c b/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c index 557a5ade329a..e8da0b4527dc 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c @@ -342,7 +342,7 @@ static void kfd_init_apertures_vi(struct kfd_process_device *pdd, uint8_t id) static void kfd_init_apertures_v9(struct kfd_process_device *pdd, uint8_t id) { - if (pdd->dev->adev->vm_manager.root_level == AMDGPU_VM_PDB3) + if (KFD_GC_VERSION(pdd->dev) >= IP_VERSION(12, 1, 0)) pdd->lds_base = pdd->dev->adev->gmc.shared_aperture_start; else pdd->lds_base = MAKE_LDS_APP_BASE_V9(); @@ -352,7 +352,7 @@ static void kfd_init_apertures_v9(struct kfd_process_device *pdd, uint8_t id) pdd->gpuvm_limit = pdd->dev->kfd->shared_resources.gpuvm_size - 1; - if (pdd->dev->adev->vm_manager.root_level == AMDGPU_VM_PDB3) + if (KFD_GC_VERSION(pdd->dev) >= IP_VERSION(12, 1, 0)) pdd->scratch_base = pdd->dev->adev->gmc.private_aperture_start; else pdd->scratch_base = MAKE_SCRATCH_APP_BASE_V9(); From f4db9913e4d3dabe9ff3ea6178f2c1bc286012b8 Mon Sep 17 00:00:00 2001 From: Prike Liang Date: Tue, 6 Jan 2026 17:00:57 +0800 Subject: [PATCH 62/69] drm/amdgpu: validate the flush_gpu_tlb_pasid() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Validate flush_gpu_tlb_pasid() availability before flushing tlb. Signed-off-by: Prike Liang Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c index 6d7b8bb953ae..0e67fa4338ff 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c @@ -780,6 +780,10 @@ int amdgpu_gmc_flush_gpu_tlb_pasid(struct amdgpu_device *adev, uint16_t pasid, return 0; if (!adev->gmc.flush_pasid_uses_kiq || !ring->sched.ready) { + + if (!adev->gmc.gmc_funcs->flush_gpu_tlb_pasid) + return 0; + if (adev->gmc.flush_tlb_needs_extra_type_2) adev->gmc.gmc_funcs->flush_gpu_tlb_pasid(adev, pasid, 2, all_hub, From 9163fe4d790fb4e16d6b0e23f55b43cddd3d4a65 Mon Sep 17 00:00:00 2001 From: Prike Liang Date: Fri, 9 Jan 2026 16:15:11 +0800 Subject: [PATCH 63/69] Revert "drm/amdgpu: don't attach the tlb fence for SI" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 820b3d376e8a102c6aeab737ec6edebbbb710e04. It’s better to validate VM TLB flushes in the flush‑TLB backend rather than in the generic VM layer. Reverting this patch depends on commit fa7c231fc2b0 ("drm/amdgpu: validate the flush_gpu_tlb_pasid()") being present in the tree. Signed-off-by: Prike Liang Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 0eccb31793ca..6a2ea200d90c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -1069,9 +1069,7 @@ amdgpu_vm_tlb_flush(struct amdgpu_vm_update_params *params, } /* Prepare a TLB flush fence to be attached to PTs */ - if (!params->unlocked && - /* SI doesn't support pasid or KIQ/MES */ - params->adev->family > AMDGPU_FAMILY_SI) { + if (!params->unlocked) { amdgpu_vm_tlb_fence_create(params->adev, vm, fence); /* Makes sure no PD/PT is freed before the flush */ From 22d6d1b5868665fa10de94d310ae77bd809eb5e9 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Mon, 12 Jan 2026 18:19:48 +0530 Subject: [PATCH 64/69] drm/amd/pm: Use emit clock levels in SMU v15.0.0 print_clk_levels is no longer used, use emit_clk_levels instead. Signed-off-by: Lijo Lazar Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- .../drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c index 95a693a4557c..b48444706c1e 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c @@ -883,15 +883,14 @@ static int smu_v15_0_common_get_dpm_level_count(struct smu_context *smu, return 0; } -static int smu_v15_0_0_print_clk_levels(struct smu_context *smu, - enum smu_clk_type clk_type, char *buf) +static int smu_v15_0_0_emit_clk_levels(struct smu_context *smu, + enum smu_clk_type clk_type, char *buf, + int *offset) { - int i, idx, ret = 0, size = 0; + int i, idx, ret = 0, size = *offset; uint32_t cur_value = 0, value = 0, count = 0; uint32_t min, max; - smu_cmn_get_sysfs_buf(&buf, &size); - switch (clk_type) { case SMU_OD_SCLK: size += sysfs_emit_at(buf, size, "%s:\n", "OD_SCLK"); @@ -915,19 +914,20 @@ static int smu_v15_0_0_print_clk_levels(struct smu_context *smu, case SMU_FCLK: ret = smu_v15_0_0_get_current_clk_freq(smu, clk_type, &cur_value); if (ret) - break; + return ret; ret = smu_v15_0_common_get_dpm_level_count(smu, clk_type, &count); if (ret) - break; + return ret; for (i = 0; i < count; i++) { idx = (clk_type == SMU_MCLK) ? (count - i - 1) : i; ret = smu_v15_0_common_get_dpm_freq_by_index(smu, clk_type, idx, &value); if (ret) - break; + return ret; - size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, value, + size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, + value, cur_value == value ? "*" : ""); } break; @@ -935,7 +935,7 @@ static int smu_v15_0_0_print_clk_levels(struct smu_context *smu, case SMU_SCLK: ret = smu_v15_0_0_get_current_clk_freq(smu, clk_type, &cur_value); if (ret) - break; + return ret; min = (smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq; max = (smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq; if (cur_value == max) @@ -946,9 +946,10 @@ static int smu_v15_0_0_print_clk_levels(struct smu_context *smu, i = 1; size += sysfs_emit_at(buf, size, "0: %uMhz %s\n", min, i == 0 ? "*" : ""); - size += sysfs_emit_at(buf, size, "1: %uMhz %s\n", - i == 1 ? cur_value : 1100, /* UMD PSTATE GFXCLK 1100 */ - i == 1 ? "*" : ""); + size += sysfs_emit_at( + buf, size, "1: %uMhz %s\n", + i == 1 ? cur_value : 1100, /* UMD PSTATE GFXCLK 1100 */ + i == 1 ? "*" : ""); size += sysfs_emit_at(buf, size, "2: %uMhz %s\n", max, i == 2 ? "*" : ""); break; @@ -956,7 +957,9 @@ static int smu_v15_0_0_print_clk_levels(struct smu_context *smu, break; } - return size; + *offset = size; + + return 0; } static int smu_v15_0_0_set_soft_freq_limited_range(struct smu_context *smu, @@ -1321,7 +1324,7 @@ static const struct pptable_funcs smu_v15_0_0_ppt_funcs = { .mode2_reset = smu_v15_0_0_mode2_reset, .get_dpm_ultimate_freq = smu_v15_0_common_get_dpm_ultimate_freq, .od_edit_dpm_table = smu_v15_0_od_edit_dpm_table, - .print_clk_levels = smu_v15_0_0_print_clk_levels, + .emit_clk_levels = smu_v15_0_0_emit_clk_levels, .force_clk_levels = smu_v15_0_0_force_clk_levels, .set_performance_level = smu_v15_0_common_set_performance_level, .set_fine_grain_gfx_freq_parameters = smu_v15_0_common_set_fine_grain_gfx_freq_parameters, From e921a5f7875da8e82cd8857269bdf60541f7a517 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Mon, 12 Jan 2026 18:22:58 +0530 Subject: [PATCH 65/69] drm/amd/pm: Deprecate print_clk_levels callback Use emit_clk_levels instead. Also, remove the unused helper function for getting sysfs buffer offset. Signed-off-by: Lijo Lazar Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 9 --------- drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h | 13 ------------- 2 files changed, 22 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h index 3efd5cca3d09..1def04826f10 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h @@ -829,15 +829,6 @@ struct pptable_funcs { */ int (*populate_umd_state_clk)(struct smu_context *smu); - /** - * @print_clk_levels: Print DPM clock levels for a clock domain - * to buffer. Star current level. - * - * Used for sysfs interfaces. - * Return: Number of characters written to the buffer - */ - int (*print_clk_levels)(struct smu_context *smu, enum smu_clk_type clk_type, char *buf); - /** * @emit_clk_levels: Print DPM clock levels for a clock domain * to buffer using sysfs_emit_at. Star current level. diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h index 4af587b42dda..92ad2ece7a36 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h @@ -187,19 +187,6 @@ int smu_cmn_get_combo_pptable(struct smu_context *smu); int smu_cmn_set_mp1_state(struct smu_context *smu, enum pp_mp1_state mp1_state); -/* - * Helper function to make sysfs_emit_at() happy. Align buf to - * the current page boundary and record the offset. - */ -static inline void smu_cmn_get_sysfs_buf(char **buf, int *offset) -{ - if (!*buf || !offset) - return; - - *offset = offset_in_page(*buf); - *buf -= *offset; -} - bool smu_cmn_is_audio_func_enabled(struct amdgpu_device *adev); void smu_cmn_generic_soc_policy_desc(struct smu_dpm_policy *policy); void smu_cmn_generic_plpd_policy_desc(struct smu_dpm_policy *policy); From 3fd20580b96a6e9da65b94ac3b58ee288239b731 Mon Sep 17 00:00:00 2001 From: Harish Kasiviswanathan Date: Sun, 11 Jan 2026 16:53:18 -0500 Subject: [PATCH 66/69] drm/amdkfd: No need to suspend whole MES to evict process Each queue of the process is individually removed and there is not need to suspend whole mes. Suspending mes stops kernel mode queues also causing unnecessary timeouts when running mixed work loads Fixes: 079ae5118e1f ("drm/amdkfd: fix suspend/resume all calls in mes based eviction path") Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4765 Signed-off-by: Harish Kasiviswanathan Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- .../gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index dc4b6d19dc10..28e8c4f46f69 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -1211,14 +1211,8 @@ static int evict_process_queues_cpsch(struct device_queue_manager *dqm, pr_debug_ratelimited("Evicting process pid %d queues\n", pdd->process->lead_thread->pid); - if (dqm->dev->kfd->shared_resources.enable_mes) { + if (dqm->dev->kfd->shared_resources.enable_mes) pdd->last_evict_timestamp = get_jiffies_64(); - retval = suspend_all_queues_mes(dqm); - if (retval) { - dev_err(dev, "Suspending all queues failed"); - goto out; - } - } /* Mark all queues as evicted. Deactivate all active queues on * the qpd. @@ -1248,10 +1242,6 @@ static int evict_process_queues_cpsch(struct device_queue_manager *dqm, KFD_UNMAP_QUEUES_FILTER_ALL_QUEUES : KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES, 0, USE_DEFAULT_GRACE_PERIOD); - } else { - retval = resume_all_queues_mes(dqm); - if (retval) - dev_err(dev, "Resuming all queues failed"); } out: From 8e051e38a8d45caf6a866d4ff842105b577953bb Mon Sep 17 00:00:00 2001 From: Srinivasan Shanmugam Date: Wed, 14 Jan 2026 16:14:53 +0530 Subject: [PATCH 67/69] drm/amdgpu/userq: Fix fence reference leak on queue teardown v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The user mode queue keeps a pointer to the most recent fence in userq->last_fence. This pointer holds an extra dma_fence reference. When the queue is destroyed, we free the fence driver and its xarray, but we forgot to drop the last_fence reference. Because of the missing dma_fence_put(), the last fence object can stay alive when the driver unloads. This leaves an allocated object in the amdgpu_userq_fence slab cache and triggers This is visible during driver unload as: BUG amdgpu_userq_fence: Objects remaining on __kmem_cache_shutdown() kmem_cache_destroy amdgpu_userq_fence: Slab cache still has objects Call Trace: kmem_cache_destroy amdgpu_userq_fence_slab_fini amdgpu_exit __do_sys_delete_module Fix this by putting userq->last_fence and clearing the pointer during amdgpu_userq_fence_driver_free(). This makes sure the fence reference is released and the slab cache is empty when the module exits. v2: Update to only release userq->last_fence with dma_fence_put() (Christian) Fixes: edc762a51c71 ("drm/amdgpu/userq: move some code around") Cc: Alex Deucher Cc: Christian König Signed-off-by: Srinivasan Shanmugam Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c index 3c6bd5531627..8d7420a9a113 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c @@ -141,6 +141,8 @@ static void amdgpu_userq_walk_and_drop_fence_drv(struct xarray *xa) void amdgpu_userq_fence_driver_free(struct amdgpu_usermode_queue *userq) { + dma_fence_put(userq->last_fence); + amdgpu_userq_walk_and_drop_fence_drv(&userq->fence_drv_xa); xa_destroy(&userq->fence_drv_xa); /* Drop the fence_drv reference held by user queue */ From 0cba5b27f1924e9248b096fc746a1210be9c32c8 Mon Sep 17 00:00:00 2001 From: Philip Yang Date: Wed, 26 Nov 2025 14:35:11 -0500 Subject: [PATCH 68/69] drm/amdkfd: Add domain parameter to alloc kernel BO To allocate kernel BO from VRAM domain for MQD in the following patch. No functional change because kernel BO allocate all from GTT domain. Rename amdgpu_amdkfd_alloc_gtt_mem to amdgpu_amdkfd_alloc_kernel_mem Rename amdgpu_amdkfd_free_gtt_mem to amdgpu_amdkfd_free_kernel_mem Rename mem_kfd_mem_obj gtt_mem to mem Signed-off-by: Philip Yang Reviewed-by: Kent Russell Reviewed-by: Felix Kuehling Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 10 +++++----- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h | 6 +++--- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c | 2 +- drivers/gpu/drm/amd/amdkfd/kfd_debug.c | 3 ++- drivers/gpu/drm/amd/amdkfd/kfd_device.c | 13 +++++++------ .../gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 7 ++++--- drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c | 14 +++++++------- drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c | 4 ++-- drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c | 9 +++++---- drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 2 +- drivers/gpu/drm/amd/amdkfd/kfd_process.c | 2 +- .../gpu/drm/amd/amdkfd/kfd_process_queue_manager.c | 12 +++++++----- 12 files changed, 45 insertions(+), 39 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index f958fef253da..15770e9a7e63 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -321,8 +321,8 @@ void amdgpu_amdkfd_gpu_reset(struct amdgpu_device *adev) &adev->kfd.reset_work); } -int amdgpu_amdkfd_alloc_gtt_mem(struct amdgpu_device *adev, size_t size, - void **mem_obj, uint64_t *gpu_addr, +int amdgpu_amdkfd_alloc_kernel_mem(struct amdgpu_device *adev, size_t size, + u32 domain, void **mem_obj, uint64_t *gpu_addr, void **cpu_ptr, bool cp_mqd_gfx9) { struct amdgpu_bo *bo = NULL; @@ -333,7 +333,7 @@ int amdgpu_amdkfd_alloc_gtt_mem(struct amdgpu_device *adev, size_t size, memset(&bp, 0, sizeof(bp)); bp.size = size; bp.byte_align = PAGE_SIZE; - bp.domain = AMDGPU_GEM_DOMAIN_GTT; + bp.domain = domain; bp.flags = AMDGPU_GEM_CREATE_CPU_GTT_USWC; bp.type = ttm_bo_type_kernel; bp.resv = NULL; @@ -356,7 +356,7 @@ int amdgpu_amdkfd_alloc_gtt_mem(struct amdgpu_device *adev, size_t size, goto allocate_mem_reserve_bo_failed; } - r = amdgpu_bo_pin(bo, AMDGPU_GEM_DOMAIN_GTT); + r = amdgpu_bo_pin(bo, domain); if (r) { dev_err(adev->dev, "(%d) failed to pin bo for amdkfd\n", r); goto allocate_mem_pin_bo_failed; @@ -393,7 +393,7 @@ int amdgpu_amdkfd_alloc_gtt_mem(struct amdgpu_device *adev, size_t size, return r; } -void amdgpu_amdkfd_free_gtt_mem(struct amdgpu_device *adev, void **mem_obj) +void amdgpu_amdkfd_free_kernel_mem(struct amdgpu_device *adev, void **mem_obj) { struct amdgpu_bo **bo = (struct amdgpu_bo **) mem_obj; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h index eba9556ece9a..cdbab7f8cee8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h @@ -241,10 +241,10 @@ int amdgpu_amdkfd_bo_validate_and_fence(struct amdgpu_bo *bo, } #endif /* Shared API */ -int amdgpu_amdkfd_alloc_gtt_mem(struct amdgpu_device *adev, size_t size, - void **mem_obj, uint64_t *gpu_addr, +int amdgpu_amdkfd_alloc_kernel_mem(struct amdgpu_device *adev, size_t size, + u32 domain, void **mem_obj, uint64_t *gpu_addr, void **cpu_ptr, bool mqd_gfx9); -void amdgpu_amdkfd_free_gtt_mem(struct amdgpu_device *adev, void **mem_obj); +void amdgpu_amdkfd_free_kernel_mem(struct amdgpu_device *adev, void **mem_obj); int amdgpu_amdkfd_alloc_gws(struct amdgpu_device *adev, size_t size, void **mem_obj); void amdgpu_amdkfd_free_gws(struct amdgpu_device *adev, void *mem_obj); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index 88fc430b9425..768998c82b43 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -2215,7 +2215,7 @@ int amdgpu_amdkfd_gpuvm_sync_memory( * @bo_gart: Return bo reference * * Before return, bo reference count is incremented. To release the reference and unpin/ - * unmap the BO, call amdgpu_amdkfd_free_gtt_mem. + * unmap the BO, call amdgpu_amdkfd_free_kernel_mem. */ int amdgpu_amdkfd_map_gtt_bo_to_gart(struct amdgpu_bo *bo, struct amdgpu_bo **bo_gart) { diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_debug.c b/drivers/gpu/drm/amd/amdkfd/kfd_debug.c index cd5a0b58c7d1..27176b2dc714 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_debug.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_debug.c @@ -357,8 +357,9 @@ int kfd_dbg_set_mes_debug_mode(struct kfd_process_device *pdd, bool sq_trap_en) return 0; if (!pdd->proc_ctx_cpu_ptr) { - r = amdgpu_amdkfd_alloc_gtt_mem(adev, + r = amdgpu_amdkfd_alloc_kernel_mem(adev, AMDGPU_MES_PROC_CTX_SIZE, + AMDGPU_GEM_DOMAIN_GTT, &pdd->proc_ctx_bo, &pdd->proc_ctx_gpu_addr, &pdd->proc_ctx_cpu_ptr, diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index 640a9ab39fcd..9a66ee661e57 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -820,12 +820,13 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd, /* add another 512KB for all other allocations on gart (HPD, fences) */ size += 512 * 1024; - if (amdgpu_amdkfd_alloc_gtt_mem( - kfd->adev, size, &kfd->gtt_mem, + if (amdgpu_amdkfd_alloc_kernel_mem( + kfd->adev, size, AMDGPU_GEM_DOMAIN_GTT, + &kfd->gtt_mem, &kfd->gtt_start_gpu_addr, &kfd->gtt_start_cpu_ptr, false)) { dev_err(kfd_device, "Could not allocate %d bytes\n", size); - goto alloc_gtt_mem_failure; + goto alloc_kernel_mem_failure; } dev_info(kfd_device, "Allocated %d bytes on gart\n", size); @@ -951,8 +952,8 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd, kfd_doorbell_error: kfd_gtt_sa_fini(kfd); kfd_gtt_sa_init_error: - amdgpu_amdkfd_free_gtt_mem(kfd->adev, &kfd->gtt_mem); -alloc_gtt_mem_failure: + amdgpu_amdkfd_free_kernel_mem(kfd->adev, &kfd->gtt_mem); +alloc_kernel_mem_failure: dev_err(kfd_device, "device %x:%x NOT added due to errors\n", kfd->adev->pdev->vendor, kfd->adev->pdev->device); @@ -969,7 +970,7 @@ void kgd2kfd_device_exit(struct kfd_dev *kfd) kfd_doorbell_fini(kfd); ida_destroy(&kfd->doorbell_ida); kfd_gtt_sa_fini(kfd); - amdgpu_amdkfd_free_gtt_mem(kfd->adev, &kfd->gtt_mem); + amdgpu_amdkfd_free_kernel_mem(kfd->adev, &kfd->gtt_mem); } kfree(kfd); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index 28e8c4f46f69..b542de9d50d1 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -2899,8 +2899,9 @@ static int allocate_hiq_sdma_mqd(struct device_queue_manager *dqm) (dqm->mqd_mgrs[KFD_MQD_TYPE_HIQ]->mqd_size * NUM_XCC(dqm->dev->xcc_mask)); - retval = amdgpu_amdkfd_alloc_gtt_mem(dev->adev, size, - &(mem_obj->gtt_mem), &(mem_obj->gpu_addr), + retval = amdgpu_amdkfd_alloc_kernel_mem(dev->adev, size, + AMDGPU_GEM_DOMAIN_GTT, + &(mem_obj->mem), &(mem_obj->gpu_addr), (void *)&(mem_obj->cpu_ptr), false); return retval; @@ -2911,7 +2912,7 @@ static void deallocate_hiq_sdma_mqd(struct kfd_node *dev, { WARN(!mqd, "No hiq sdma mqd trunk to free"); - amdgpu_amdkfd_free_gtt_mem(dev->adev, &mqd->gtt_mem); + amdgpu_amdkfd_free_kernel_mem(dev->adev, &mqd->mem); } struct device_queue_manager *device_queue_manager_init(struct kfd_node *dev) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c index d9ae854b6908..f78b249e1a41 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c @@ -54,7 +54,7 @@ struct kfd_mem_obj *allocate_hiq_mqd(struct kfd_node *dev, struct queue_properti if (!mqd_mem_obj) return NULL; - mqd_mem_obj->gtt_mem = dev->dqm->hiq_sdma_mqd.gtt_mem; + mqd_mem_obj->mem = dev->dqm->hiq_sdma_mqd.mem; mqd_mem_obj->gpu_addr = dev->dqm->hiq_sdma_mqd.gpu_addr; mqd_mem_obj->cpu_ptr = dev->dqm->hiq_sdma_mqd.cpu_ptr; @@ -79,7 +79,7 @@ struct kfd_mem_obj *allocate_sdma_mqd(struct kfd_node *dev, offset += dev->dqm->mqd_mgrs[KFD_MQD_TYPE_HIQ]->mqd_size * NUM_XCC(dev->xcc_mask); - mqd_mem_obj->gtt_mem = (void *)((uint64_t)dev->dqm->hiq_sdma_mqd.gtt_mem + mqd_mem_obj->mem = (void *)((uint64_t)dev->dqm->hiq_sdma_mqd.mem + offset); mqd_mem_obj->gpu_addr = dev->dqm->hiq_sdma_mqd.gpu_addr + offset; mqd_mem_obj->cpu_ptr = (uint32_t *)((uint64_t) @@ -91,7 +91,7 @@ struct kfd_mem_obj *allocate_sdma_mqd(struct kfd_node *dev, void free_mqd_hiq_sdma(struct mqd_manager *mm, void *mqd, struct kfd_mem_obj *mqd_mem_obj) { - WARN_ON(!mqd_mem_obj->gtt_mem); + WARN_ON(!mqd_mem_obj->mem); kfree(mqd_mem_obj); } @@ -224,8 +224,8 @@ int kfd_destroy_mqd_cp(struct mqd_manager *mm, void *mqd, void kfd_free_mqd_cp(struct mqd_manager *mm, void *mqd, struct kfd_mem_obj *mqd_mem_obj) { - if (mqd_mem_obj->gtt_mem) { - amdgpu_amdkfd_free_gtt_mem(mm->dev->adev, &mqd_mem_obj->gtt_mem); + if (mqd_mem_obj->mem) { + amdgpu_amdkfd_free_kernel_mem(mm->dev->adev, &mqd_mem_obj->mem); kfree(mqd_mem_obj); } else { kfd_gtt_sa_free(mm->dev, mqd_mem_obj); @@ -280,8 +280,8 @@ void kfd_get_hiq_xcc_mqd(struct kfd_node *dev, struct kfd_mem_obj *mqd_mem_obj, offset = kfd_hiq_mqd_stride(dev) * virtual_xcc_id; - mqd_mem_obj->gtt_mem = (virtual_xcc_id == 0) ? - dev->dqm->hiq_sdma_mqd.gtt_mem : NULL; + mqd_mem_obj->mem = (virtual_xcc_id == 0) ? + dev->dqm->hiq_sdma_mqd.mem : NULL; mqd_mem_obj->gpu_addr = dev->dqm->hiq_sdma_mqd.gpu_addr + offset; mqd_mem_obj->cpu_ptr = (uint32_t *)((uintptr_t) dev->dqm->hiq_sdma_mqd.cpu_ptr + offset); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c index a06b4e89af8a..558216395a4d 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c @@ -454,8 +454,8 @@ static void get_xcc_mqd(struct kfd_mem_obj *mqd_mem_obj, struct kfd_mem_obj *xcc_mqd_mem_obj, uint64_t offset) { - xcc_mqd_mem_obj->gtt_mem = (offset == 0) ? - mqd_mem_obj->gtt_mem : NULL; + xcc_mqd_mem_obj->mem = (offset == 0) ? + mqd_mem_obj->mem : NULL; xcc_mqd_mem_obj->gpu_addr = mqd_mem_obj->gpu_addr + offset; xcc_mqd_mem_obj->cpu_ptr = (uint32_t *)((uintptr_t)mqd_mem_obj->cpu_ptr + offset); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c index 2e9b6bcf2704..d234db138182 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c @@ -135,11 +135,12 @@ static struct kfd_mem_obj *allocate_mqd(struct kfd_node *node, mqd_mem_obj = kzalloc(sizeof(struct kfd_mem_obj), GFP_KERNEL); if (!mqd_mem_obj) return NULL; - retval = amdgpu_amdkfd_alloc_gtt_mem(node->adev, + retval = amdgpu_amdkfd_alloc_kernel_mem(node->adev, (ALIGN(q->ctl_stack_size, PAGE_SIZE) + ALIGN(sizeof(struct v9_mqd), PAGE_SIZE)) * NUM_XCC(node->xcc_mask), - &(mqd_mem_obj->gtt_mem), + AMDGPU_GEM_DOMAIN_GTT, + &(mqd_mem_obj->mem), &(mqd_mem_obj->gpu_addr), (void *)&(mqd_mem_obj->cpu_ptr), true); @@ -665,8 +666,8 @@ static void get_xcc_mqd(struct kfd_mem_obj *mqd_mem_obj, struct kfd_mem_obj *xcc_mqd_mem_obj, uint64_t offset) { - xcc_mqd_mem_obj->gtt_mem = (offset == 0) ? - mqd_mem_obj->gtt_mem : NULL; + xcc_mqd_mem_obj->mem = (offset == 0) ? + mqd_mem_obj->mem : NULL; xcc_mqd_mem_obj->gpu_addr = mqd_mem_obj->gpu_addr + offset; xcc_mqd_mem_obj->cpu_ptr = (uint32_t *)((uintptr_t)mqd_mem_obj->cpu_ptr + offset); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index eeeff9ffc1e3..9849b54f54ba 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -252,7 +252,7 @@ struct kfd_mem_obj { uint32_t range_end; uint64_t gpu_addr; uint32_t *cpu_ptr; - void *gtt_mem; + void *mem; }; struct kfd_vmid_info { diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c index 1f2d82730c44..8511fbebf327 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c @@ -1137,7 +1137,7 @@ static void kfd_process_destroy_pdds(struct kfd_process *p) if (pdd->dev->kfd->shared_resources.enable_mes && pdd->proc_ctx_cpu_ptr) - amdgpu_amdkfd_free_gtt_mem(pdd->dev->adev, + amdgpu_amdkfd_free_kernel_mem(pdd->dev->adev, &pdd->proc_ctx_bo); /* * before destroying pdd, make sure to report availability diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c index a399770aa411..449be58e884c 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c @@ -210,8 +210,8 @@ static void pqm_clean_queue_resource(struct process_queue_manager *pqm, } if (dev->kfd->shared_resources.enable_mes) { - amdgpu_amdkfd_free_gtt_mem(dev->adev, &pqn->q->gang_ctx_bo); - amdgpu_amdkfd_free_gtt_mem(dev->adev, (void **)&pqn->q->wptr_bo_gart); + amdgpu_amdkfd_free_kernel_mem(dev->adev, &pqn->q->gang_ctx_bo); + amdgpu_amdkfd_free_kernel_mem(dev->adev, (void **)&pqn->q->wptr_bo_gart); } } @@ -265,8 +265,9 @@ static int init_user_queue(struct process_queue_manager *pqm, (*q)->process = pqm->process; if (dev->kfd->shared_resources.enable_mes) { - retval = amdgpu_amdkfd_alloc_gtt_mem(dev->adev, + retval = amdgpu_amdkfd_alloc_kernel_mem(dev->adev, AMDGPU_MES_GANG_CTX_SIZE, + AMDGPU_GEM_DOMAIN_GTT, &(*q)->gang_ctx_bo, &(*q)->gang_ctx_gpu_addr, &(*q)->gang_ctx_cpu_ptr, @@ -298,7 +299,7 @@ static int init_user_queue(struct process_queue_manager *pqm, return 0; free_gang_ctx_bo: - amdgpu_amdkfd_free_gtt_mem(dev->adev, &(*q)->gang_ctx_bo); + amdgpu_amdkfd_free_kernel_mem(dev->adev, &(*q)->gang_ctx_bo); cleanup: uninit_queue(*q); *q = NULL; @@ -368,8 +369,9 @@ int pqm_create_queue(struct process_queue_manager *pqm, /* Allocate proc_ctx_bo only if MES is enabled and this is the first queue */ if (!pdd->proc_ctx_cpu_ptr && dev->kfd->shared_resources.enable_mes) { - retval = amdgpu_amdkfd_alloc_gtt_mem(dev->adev, + retval = amdgpu_amdkfd_alloc_kernel_mem(dev->adev, AMDGPU_MES_PROC_CTX_SIZE, + AMDGPU_GEM_DOMAIN_GTT, &pdd->proc_ctx_bo, &pdd->proc_ctx_gpu_addr, &pdd->proc_ctx_cpu_ptr, From 6a681cd9034587fe3550868bacfbd639d1c6891f Mon Sep 17 00:00:00 2001 From: Ivan Lipski Date: Tue, 13 Jan 2026 17:29:59 -0500 Subject: [PATCH 69/69] drm/amd/display: Add an hdmi_hpd_debounce_delay_ms module [Why&How] Right now, the HDMI HPD filter is enabled by default at 1500ms. We want to disable it by default, as most modern displays with HDMI do not require it for DPMS mode. The HPD can instead be enabled as a driver parameter with a custom delay value in ms (up to 5000ms). Fixes: c918e75e1ed9 ("drm/amd/display: Add an HPD filter for HDMI") Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4859 Signed-off-by: Ivan Lipski Reviewed-by: Mario Limonciello (AMD) Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 2 ++ drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 11 +++++++++++ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 15 ++++++++++++--- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 5 ++++- 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 11a36c132905..9c11535c44c6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -269,6 +269,8 @@ extern int amdgpu_rebar; extern int amdgpu_wbrf; extern int amdgpu_user_queue; +extern uint amdgpu_hdmi_hpd_debounce_delay_ms; + #define AMDGPU_VM_MAX_NUM_CTX 4096 #define AMDGPU_SG_THRESHOLD (256*1024*1024) #define AMDGPU_WAIT_IDLE_TIMEOUT_IN_MS 3000 diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index bb8d9256fae0..d6d0a6e34c6b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -247,6 +247,7 @@ int amdgpu_damage_clips = -1; /* auto */ int amdgpu_umsch_mm_fwlog; int amdgpu_rebar = -1; /* auto */ int amdgpu_user_queue = -1; +uint amdgpu_hdmi_hpd_debounce_delay_ms; DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0, "DRM_UT_CORE", @@ -1123,6 +1124,16 @@ module_param_named(rebar, amdgpu_rebar, int, 0444); MODULE_PARM_DESC(user_queue, "Enable user queues (-1 = auto (default), 0 = disable, 1 = enable, 2 = enable UQs and disable KQs)"); module_param_named(user_queue, amdgpu_user_queue, int, 0444); +/* + * DOC: hdmi_hpd_debounce_delay_ms (uint) + * HDMI HPD disconnect debounce delay in milliseconds. + * + * Used to filter short disconnect->reconnect HPD toggles some HDMI sinks + * generate while entering/leaving power save. Set to 0 to disable by default. + */ +MODULE_PARM_DESC(hdmi_hpd_debounce_delay_ms, "HDMI HPD disconnect debounce delay in milliseconds (0 to disable (by default), 1500 is common)"); +module_param_named(hdmi_hpd_debounce_delay_ms, amdgpu_hdmi_hpd_debounce_delay_ms, uint, 0644); + /* These devices are not supported by amdgpu. * They are supported by the mach64, r128, radeon drivers */ 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 157efedda358..cb13a2b0de62 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -8961,9 +8961,18 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm, mutex_init(&aconnector->hpd_lock); mutex_init(&aconnector->handle_mst_msg_ready); - aconnector->hdmi_hpd_debounce_delay_ms = AMDGPU_DM_HDMI_HPD_DEBOUNCE_MS; - INIT_DELAYED_WORK(&aconnector->hdmi_hpd_debounce_work, hdmi_hpd_debounce_work); - aconnector->hdmi_prev_sink = NULL; + /* + * If HDMI HPD debounce delay is set, use the minimum between selected + * value and AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS + */ + if (amdgpu_hdmi_hpd_debounce_delay_ms) { + aconnector->hdmi_hpd_debounce_delay_ms = min(amdgpu_hdmi_hpd_debounce_delay_ms, + AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS); + INIT_DELAYED_WORK(&aconnector->hdmi_hpd_debounce_work, hdmi_hpd_debounce_work); + aconnector->hdmi_prev_sink = NULL; + } else { + aconnector->hdmi_hpd_debounce_delay_ms = 0; + } /* * configure support HPD hot plug connector_>polled default value is 0 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 f0f371718d03..115efd8ec68b 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -59,7 +59,10 @@ #define AMDGPU_HDR_MULT_DEFAULT (0x100000000LL) -#define AMDGPU_DM_HDMI_HPD_DEBOUNCE_MS 1500 +/* + * Maximum HDMI HPD debounce delay in milliseconds + */ +#define AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS 5000 /* #include "include/amdgpu_dal_power_if.h" #include "amdgpu_dm_irq.h"