From 31b153315b8702d0249aa44d83d9fbf42c5c7a79 Mon Sep 17 00:00:00 2001 From: Perry Yuan Date: Wed, 28 Jan 2026 13:54:31 +0800 Subject: [PATCH 01/51] drm/amdgpu: ensure no_hw_access is visible before MMIO Add a full memory barrier after clearing no_hw_access in amdgpu_device_mode1_reset() so subsequent PCI state restore access cannot observe stale state on other CPUs. Fixes: 7edb503fe4b6 ("drm/amd/pm: Disable MMIO access during SMU Mode 1 reset") Signed-off-by: Perry Yuan Reviewed-by: Yifan Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index c7f44422939f..c1ffc63e23ab 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -5733,6 +5733,9 @@ int amdgpu_device_mode1_reset(struct amdgpu_device *adev) /* enable mmio access after mode 1 reset completed */ adev->no_hw_access = false; + /* ensure no_hw_access is updated before we access hw */ + smp_mb(); + amdgpu_device_load_pci_state(adev->pdev); ret = amdgpu_psp_wait_for_bootloader(adev); if (ret) From 949adb4789fe3c24eea01d9c2efe94ab92694a0d Mon Sep 17 00:00:00 2001 From: Bhuvanachandra Pinninti Date: Wed, 17 Dec 2025 18:50:11 +0530 Subject: [PATCH 02/51] drm/amd/display: Migrate DCCG register access from hwseq to dccg component. [why] Direct DCCG register access in hwseq layer was creating register conflicts. [how] Migrated DCCG registers from hwseq to dccg component. Reviewed-by: Martin Leung Signed-off-by: Bhuvanachandra Pinninti Signed-off-by: Wayne Lin Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../amd/display/dc/dccg/dcn20/dcn20_dccg.c | 54 ++++++++++++++++++- .../amd/display/dc/dccg/dcn20/dcn20_dccg.h | 18 +++++-- .../amd/display/dc/hwss/dcn10/dcn10_hwseq.c | 5 +- .../amd/display/dc/hwss/dcn20/dcn20_hwseq.c | 29 +++------- .../amd/display/dc/hwss/dcn201/dcn201_hwseq.c | 5 +- .../amd/display/dc/hwss/dcn21/dcn21_hwseq.c | 9 ++-- .../amd/display/dc/hwss/dcn30/dcn30_hwseq.c | 5 +- .../amd/display/dc/hwss/dcn31/dcn31_hwseq.c | 5 +- .../amd/display/dc/hwss/dcn32/dcn32_hwseq.c | 5 +- .../amd/display/dc/hwss/dcn35/dcn35_hwseq.c | 3 +- .../amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 5 +- drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h | 4 ++ 12 files changed, 98 insertions(+), 49 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn20/dcn20_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn20/dcn20_dccg.c index 33d8bd91cb01..50b98822b6fd 100644 --- a/drivers/gpu/drm/amd/display/dc/dccg/dcn20/dcn20_dccg.c +++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn20/dcn20_dccg.c @@ -131,6 +131,54 @@ void dccg2_otg_drop_pixel(struct dccg *dccg, void dccg2_init(struct dccg *dccg) { + struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); + + /* Hardcoded register values for DCN20 + * These are specific to 100Mhz refclk + * Different ASICs with different refclk may override this in their own init + */ + REG_WRITE(MICROSECOND_TIME_BASE_DIV, 0x00120264); + REG_WRITE(MILLISECOND_TIME_BASE_DIV, 0x001186a0); + REG_WRITE(DISPCLK_FREQ_CHANGE_CNTL, 0x0e01003c); + + if (REG(REFCLK_CNTL)) + REG_WRITE(REFCLK_CNTL, 0); +} + +void dccg2_refclk_setup(struct dccg *dccg) +{ + struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); + + /* REFCLK programming that must occur after hubbub initialization */ + if (REG(REFCLK_CNTL)) + REG_WRITE(REFCLK_CNTL, 0); +} + +bool dccg2_is_s0i3_golden_init_wa_done(struct dccg *dccg) +{ + struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); + + return REG_READ(MICROSECOND_TIME_BASE_DIV) == 0x00120464; +} + +void dccg2_allow_clock_gating(struct dccg *dccg, bool allow) +{ + struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); + + if (allow) { + REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); + REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); + } else { + REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0xFFFFFFFF); + REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0xFFFFFFFF); + } +} + +void dccg2_enable_memory_low_power(struct dccg *dccg, bool enable) +{ + struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); + + REG_UPDATE(DC_MEM_GLOBAL_PWR_REQ_CNTL, DC_MEM_GLOBAL_PWR_REQ_DIS, enable ? 0 : 1); } static const struct dccg_funcs dccg2_funcs = { @@ -139,7 +187,11 @@ static const struct dccg_funcs dccg2_funcs = { .set_fifo_errdet_ovr_en = dccg2_set_fifo_errdet_ovr_en, .otg_add_pixel = dccg2_otg_add_pixel, .otg_drop_pixel = dccg2_otg_drop_pixel, - .dccg_init = dccg2_init + .dccg_init = dccg2_init, + .refclk_setup = dccg2_refclk_setup, /* Deprecated - for backward compatibility only */ + .allow_clock_gating = dccg2_allow_clock_gating, + .enable_memory_low_power = dccg2_enable_memory_low_power, + .is_s0i3_golden_init_wa_done = dccg2_is_s0i3_golden_init_wa_done }; struct dccg *dccg2_create( diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn20/dcn20_dccg.h b/drivers/gpu/drm/amd/display/dc/dccg/dcn20/dcn20_dccg.h index 8bdffd9ff31b..237a684ded86 100644 --- a/drivers/gpu/drm/amd/display/dc/dccg/dcn20/dcn20_dccg.h +++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn20/dcn20_dccg.h @@ -46,7 +46,9 @@ DCCG_SRII(PIXEL_RATE_CNTL, OTG, 2),\ DCCG_SRII(PIXEL_RATE_CNTL, OTG, 3),\ DCCG_SRII(PIXEL_RATE_CNTL, OTG, 4),\ - DCCG_SRII(PIXEL_RATE_CNTL, OTG, 5) + DCCG_SRII(PIXEL_RATE_CNTL, OTG, 5),\ + SR(DCCG_GATE_DISABLE_CNTL),\ + SR(DCCG_GATE_DISABLE_CNTL2) #define DCCG_SF(reg_name, field_name, post_fix)\ .field_name = reg_name ## __ ## field_name ## post_fix @@ -81,7 +83,8 @@ DCCG_SFII(OTG, PIXEL_RATE_CNTL, OTG, ADD_PIXEL, 0, mask_sh),\ DCCG_SFII(OTG, PIXEL_RATE_CNTL, OTG, ADD_PIXEL, 1, mask_sh),\ DCCG_SFII(OTG, PIXEL_RATE_CNTL, OTG, DROP_PIXEL, 0, mask_sh),\ - DCCG_SFII(OTG, PIXEL_RATE_CNTL, OTG, DROP_PIXEL, 1, mask_sh) + DCCG_SFII(OTG, PIXEL_RATE_CNTL, OTG, DROP_PIXEL, 1, mask_sh),\ + DCCG_SF(DC_MEM_GLOBAL_PWR_REQ_CNTL, DC_MEM_GLOBAL_PWR_REQ_DIS, mask_sh) @@ -130,7 +133,8 @@ type DISPCLK_CHG_FWD_CORR_DISABLE;\ type DISPCLK_FREQ_CHANGE_CNTL;\ type OTG_ADD_PIXEL[MAX_PIPES];\ - type OTG_DROP_PIXEL[MAX_PIPES]; + type OTG_DROP_PIXEL[MAX_PIPES];\ + type DC_MEM_GLOBAL_PWR_REQ_DIS; #define DCCG3_REG_FIELD_LIST(type) \ type HDMICHARCLK0_EN;\ @@ -515,6 +519,14 @@ void dccg2_otg_drop_pixel(struct dccg *dccg, void dccg2_init(struct dccg *dccg); +void dccg2_refclk_setup(struct dccg *dccg); + +bool dccg2_is_s0i3_golden_init_wa_done(struct dccg *dccg); + +void dccg2_allow_clock_gating(struct dccg *dccg, bool allow); + +void dccg2_enable_memory_low_power(struct dccg *dccg, bool enable); + struct dccg *dccg2_create( struct dc_context *ctx, const struct dccg_registers *regs, 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 c1586364ecd4..f89b2f5a9bbd 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 @@ -1885,9 +1885,8 @@ void dcn10_init_hw(struct dc *dc) if (!dc->debug.disable_clock_gate) { /* enable all DCN clock gating */ - REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); - - REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); + if (dc->res_pool->dccg && dc->res_pool->dccg->funcs && dc->res_pool->dccg->funcs->allow_clock_gating) + dc->res_pool->dccg->funcs->allow_clock_gating(dc->res_pool->dccg, true); REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); } diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c index a76436dcbe40..87a1dc27def4 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c @@ -357,26 +357,10 @@ void dcn20_enable_power_gating_plane( void dcn20_dccg_init(struct dce_hwseq *hws) { - /* - * set MICROSECOND_TIME_BASE_DIV - * 100Mhz refclk -> 0x120264 - * 27Mhz refclk -> 0x12021b - * 48Mhz refclk -> 0x120230 - * - */ - REG_WRITE(MICROSECOND_TIME_BASE_DIV, 0x120264); + struct dc *dc = hws->ctx->dc; - /* - * set MILLISECOND_TIME_BASE_DIV - * 100Mhz refclk -> 0x1186a0 - * 27Mhz refclk -> 0x106978 - * 48Mhz refclk -> 0x10bb80 - * - */ - REG_WRITE(MILLISECOND_TIME_BASE_DIV, 0x1186a0); - - /* This value is dependent on the hardware pipeline delay so set once per SOC */ - REG_WRITE(DISPCLK_FREQ_CHANGE_CNTL, 0xe01003c); + if (dc->res_pool->dccg && dc->res_pool->dccg->funcs && dc->res_pool->dccg->funcs->dccg_init) + dc->res_pool->dccg->funcs->dccg_init(dc->res_pool->dccg); } void dcn20_disable_vga( @@ -3155,8 +3139,11 @@ void dcn20_fpga_init_hw(struct dc *dc) REG_WRITE(RBBMIF_TIMEOUT_DIS_2, 0xFFFFFFFF); dcn10_hubbub_global_timer_enable(dc->res_pool->hubbub, true, 2); - if (REG(REFCLK_CNTL)) - REG_WRITE(REFCLK_CNTL, 0); + + hws->funcs.dccg_init(hws); + + if (dc->res_pool->dccg && dc->res_pool->dccg->funcs && dc->res_pool->dccg->funcs->refclk_setup) + dc->res_pool->dccg->funcs->refclk_setup(dc->res_pool->dccg); // diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.c index 482053c4ad22..7cd225a6cf6c 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.c @@ -364,9 +364,8 @@ void dcn201_init_hw(struct dc *dc) if (!dc->debug.disable_clock_gate) { /* enable all DCN clock gating */ - REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); - - REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); + if (dc->res_pool->dccg && dc->res_pool->dccg->funcs && dc->res_pool->dccg->funcs->allow_clock_gating) + dc->res_pool->dccg->funcs->allow_clock_gating(dc->res_pool->dccg, true); REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); } diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.c index e2269211553c..062745389d9a 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.c @@ -33,6 +33,7 @@ #include "vmid.h" #include "reg_helper.h" #include "hw/clk_mgr.h" +#include "hw/dccg.h" #include "dc_dmub_srv.h" #include "abm.h" #include "link_service.h" @@ -87,12 +88,10 @@ int dcn21_init_sys_ctx(struct dce_hwseq *hws, struct dc *dc, struct dc_phy_addr_ bool dcn21_s0i3_golden_init_wa(struct dc *dc) { - struct dce_hwseq *hws = dc->hwseq; - uint32_t value = 0; + if (dc->res_pool->dccg && dc->res_pool->dccg->funcs && dc->res_pool->dccg->funcs->is_s0i3_golden_init_wa_done) + return !dc->res_pool->dccg->funcs->is_s0i3_golden_init_wa_done(dc->res_pool->dccg); - value = REG_READ(MICROSECOND_TIME_BASE_DIV); - - return value != 0x00120464; + return false; } void dcn21_exit_optimized_pwr_state( diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c index c02ddada723f..3ff15ec9dc17 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c @@ -798,9 +798,8 @@ void dcn30_init_hw(struct dc *dc) if (!dc->debug.disable_clock_gate) { /* enable all DCN clock gating */ - REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); - - REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); + if (dc->res_pool->dccg && dc->res_pool->dccg->funcs && dc->res_pool->dccg->funcs->allow_clock_gating) + dc->res_pool->dccg->funcs->allow_clock_gating(dc->res_pool->dccg, true); REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); } diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c index 2adbcc105aa6..91a672a46289 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c @@ -249,9 +249,8 @@ void dcn31_init_hw(struct dc *dc) if (!dc->debug.disable_clock_gate) { /* enable all DCN clock gating */ - REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); - - REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); + if (dc->res_pool->dccg && dc->res_pool->dccg->funcs && dc->res_pool->dccg->funcs->allow_clock_gating) + dc->res_pool->dccg->funcs->allow_clock_gating(dc->res_pool->dccg, true); REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); } diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c index 3cd44c6602b3..3f76fba7dccc 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c @@ -959,9 +959,8 @@ void dcn32_init_hw(struct dc *dc) if (!dc->debug.disable_clock_gate) { /* enable all DCN clock gating */ - REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); - - REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); + if (dc->res_pool->dccg && dc->res_pool->dccg->funcs && dc->res_pool->dccg->funcs->allow_clock_gating) + dc->res_pool->dccg->funcs->allow_clock_gating(dc->res_pool->dccg, true); REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); } 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 f7e16fee7594..1c7263f9ef51 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 @@ -288,7 +288,8 @@ void dcn35_init_hw(struct dc *dc) } if (dc->debug.disable_mem_low_power) { - REG_UPDATE(DC_MEM_GLOBAL_PWR_REQ_CNTL, DC_MEM_GLOBAL_PWR_REQ_DIS, 1); + if (dc->res_pool->dccg && dc->res_pool->dccg->funcs && dc->res_pool->dccg->funcs->enable_memory_low_power) + dc->res_pool->dccg->funcs->enable_memory_low_power(dc->res_pool->dccg, false); } if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks) dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub); 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 86400938abd2..567ed207d7cd 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 @@ -324,9 +324,8 @@ void dcn401_init_hw(struct dc *dc) if (!dc->debug.disable_clock_gate) { /* enable all DCN clock gating */ - REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); - - REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); + if (dc->res_pool->dccg && dc->res_pool->dccg->funcs && dc->res_pool->dccg->funcs->allow_clock_gating) + dc->res_pool->dccg->funcs->allow_clock_gating(dc->res_pool->dccg, true); REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); } 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 1e6ffd86a4c0..a26d31ab7cba 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h @@ -224,6 +224,9 @@ struct dccg_funcs { void (*otg_drop_pixel)(struct dccg *dccg, uint32_t otg_inst); void (*dccg_init)(struct dccg *dccg); + void (*refclk_setup)(struct dccg *dccg); /* Deprecated - for backward compatibility only */ + void (*allow_clock_gating)(struct dccg *dccg, bool allow); + void (*enable_memory_low_power)(struct dccg *dccg, bool enable); void (*set_dpstreamclk_root_clock_gating)( struct dccg *dccg, int dp_hpo_inst, @@ -334,6 +337,7 @@ struct dccg_funcs { 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); + bool (*is_s0i3_golden_init_wa_done)(struct dccg *dccg); }; #endif //__DAL_DCCG_H__ From eee8227dd18868bb16dbf72e2ab11d1a9008b874 Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin Date: Fri, 16 Jan 2026 22:17:15 -0500 Subject: [PATCH 03/51] drm/amd/display: Add lpddr5 handling to dml2.1 [Why & How] Memory bandwidth calculations work differently than for ddr. Add lpddr5 handling. Reviewed-by: Charlene Liu Signed-off-by: Dmytro Laktyushkin Signed-off-by: Wayne Lin Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../dml21/inc/dml_top_soc_parameter_types.h | 3 + .../src/dml2_core/dml2_core_dcn4_calcs.c | 26 ++++++-- .../dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c | 59 ++++++++++++------- .../src/inc/dml2_internal_shared_types.h | 1 + 4 files changed, 64 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_soc_parameter_types.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_soc_parameter_types.h index 1fbc520c2540..c4cce870877a 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_soc_parameter_types.h +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_soc_parameter_types.h @@ -115,9 +115,12 @@ struct dml2_dram_params { unsigned int channel_width_bytes; unsigned int channel_count; unsigned int transactions_per_clock; + bool alt_clock_bw_conversion; }; +#define ENABLE_WCK struct dml2_soc_state_table { + struct dml2_clk_table wck_ratio; struct dml2_clk_table uclk; struct dml2_clk_table fclk; struct dml2_clk_table dcfclk; diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c index 01b87be24ce3..37699cc9e5c1 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c @@ -7077,10 +7077,21 @@ static void calculate_excess_vactive_bandwidth_required( } } -static double uclk_khz_to_dram_bw_mbps(unsigned long uclk_khz, const struct dml2_dram_params *dram_config) +static double uclk_khz_to_dram_bw_mbps(unsigned long uclk_khz, const struct dml2_dram_params *dram_config, const struct dml2_mcg_dram_bw_to_min_clk_table *dram_bw_table) { double bw_mbps = 0; - bw_mbps = ((double)uclk_khz * dram_config->channel_count * dram_config->channel_width_bytes * dram_config->transactions_per_clock) / 1000.0; + int i; + + if (!dram_config->alt_clock_bw_conversion) + bw_mbps = ((double)uclk_khz * dram_config->channel_count * dram_config->channel_width_bytes * dram_config->transactions_per_clock) / 1000.0; + else + for (i = 0; i < dram_bw_table->num_entries; i++) + if (dram_bw_table->entries[i].min_uclk_khz >= uclk_khz) { + bw_mbps = (double)dram_bw_table->entries[i].pre_derate_dram_bw_kbps / 1000.0; + break; + } + + ASSERT(bw_mbps > 0); return bw_mbps; } @@ -7964,7 +7975,9 @@ static bool dml_core_mode_support(struct dml2_core_calcs_mode_support_ex *in_out mode_lib->ms.max_dispclk_freq_mhz = (double)min_clk_table->max_ss_clocks_khz.dispclk / 1000; mode_lib->ms.max_dscclk_freq_mhz = (double)min_clk_table->max_clocks_khz.dscclk / 1000; mode_lib->ms.max_dppclk_freq_mhz = (double)min_clk_table->max_ss_clocks_khz.dppclk / 1000; - mode_lib->ms.uclk_freq_mhz = dram_bw_kbps_to_uclk_mhz(min_clk_table->dram_bw_table.entries[in_out_params->min_clk_index].pre_derate_dram_bw_kbps, &mode_lib->soc.clk_table.dram_config); + mode_lib->ms.uclk_freq_mhz = (double)min_clk_table->dram_bw_table.entries[in_out_params->min_clk_index].min_uclk_khz / 1000.0; + if (!mode_lib->ms.uclk_freq_mhz) + mode_lib->ms.uclk_freq_mhz = dram_bw_kbps_to_uclk_mhz(min_clk_table->dram_bw_table.entries[in_out_params->min_clk_index].pre_derate_dram_bw_kbps, &mode_lib->soc.clk_table.dram_config); mode_lib->ms.dram_bw_mbps = ((double)min_clk_table->dram_bw_table.entries[in_out_params->min_clk_index].pre_derate_dram_bw_kbps / 1000); mode_lib->ms.max_dram_bw_mbps = ((double)min_clk_table->dram_bw_table.entries[min_clk_table->dram_bw_table.num_entries - 1].pre_derate_dram_bw_kbps / 1000); mode_lib->ms.qos_param_index = get_qos_param_index((unsigned int) (mode_lib->ms.uclk_freq_mhz * 1000.0), mode_lib->soc.qos_parameters.qos_params.dcn4x.per_uclk_dpm_params); @@ -10407,7 +10420,7 @@ static bool dml_core_mode_programming(struct dml2_core_calcs_mode_programming_ex mode_lib->mp.Dcfclk = programming->min_clocks.dcn4x.active.dcfclk_khz / 1000.0; mode_lib->mp.FabricClock = programming->min_clocks.dcn4x.active.fclk_khz / 1000.0; - mode_lib->mp.dram_bw_mbps = uclk_khz_to_dram_bw_mbps(programming->min_clocks.dcn4x.active.uclk_khz, &mode_lib->soc.clk_table.dram_config); + mode_lib->mp.dram_bw_mbps = uclk_khz_to_dram_bw_mbps(programming->min_clocks.dcn4x.active.uclk_khz, &mode_lib->soc.clk_table.dram_config, &min_clk_table->dram_bw_table); mode_lib->mp.uclk_freq_mhz = programming->min_clocks.dcn4x.active.uclk_khz / 1000.0; mode_lib->mp.GlobalDPPCLK = programming->min_clocks.dcn4x.dpprefclk_khz / 1000.0; s->SOCCLK = (double)programming->min_clocks.dcn4x.socclk_khz / 1000; @@ -10485,7 +10498,10 @@ static bool dml_core_mode_programming(struct dml2_core_calcs_mode_programming_ex DML_LOG_VERBOSE("DML::%s: SOCCLK = %f\n", __func__, s->SOCCLK); DML_LOG_VERBOSE("DML::%s: min_clk_index = %0d\n", __func__, in_out_params->min_clk_index); DML_LOG_VERBOSE("DML::%s: min_clk_table min_fclk_khz = %ld\n", __func__, min_clk_table->dram_bw_table.entries[in_out_params->min_clk_index].min_fclk_khz); - DML_LOG_VERBOSE("DML::%s: min_clk_table uclk_mhz = %f\n", __func__, dram_bw_kbps_to_uclk_mhz(min_clk_table->dram_bw_table.entries[in_out_params->min_clk_index].pre_derate_dram_bw_kbps, &mode_lib->soc.clk_table.dram_config)); + if (min_clk_table->dram_bw_table.entries[in_out_params->min_clk_index].min_uclk_khz) + DML_LOG_VERBOSE("DML::%s: min_clk_table uclk_mhz = %f\n", __func__, min_clk_table->dram_bw_table.entries[in_out_params->min_clk_index].min_uclk_khz / 1000.0); + else + DML_LOG_VERBOSE("DML::%s: min_clk_table uclk_mhz = %f\n", __func__, dram_bw_kbps_to_uclk_mhz(min_clk_table->dram_bw_table.entries[in_out_params->min_clk_index].pre_derate_dram_bw_kbps, &mode_lib->soc.clk_table.dram_config)); for (k = 0; k < mode_lib->mp.num_active_pipes; ++k) { DML_LOG_VERBOSE("DML::%s: pipe=%d is in plane=%d\n", __func__, k, mode_lib->mp.pipe_plane[k]); DML_LOG_VERBOSE("DML::%s: Per-plane DPPPerSurface[%0d] = %d\n", __func__, k, mode_lib->mp.NoOfDPP[k]); diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c index 22969a533a7b..5c713f2e6eca 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c @@ -7,14 +7,24 @@ #include "dml_top_types.h" #include "lib_float_math.h" -static double dram_bw_kbps_to_uclk_khz(unsigned long long bandwidth_kbps, const struct dml2_dram_params *dram_config) +static double dram_bw_kbps_to_uclk_khz(unsigned long long bandwidth_kbps, const struct dml2_dram_params *dram_config, struct dml2_mcg_dram_bw_to_min_clk_table *dram_bw_table) { double uclk_khz = 0; - unsigned long uclk_mbytes_per_tick = 0; - uclk_mbytes_per_tick = dram_config->channel_count * dram_config->channel_width_bytes * dram_config->transactions_per_clock; + if (!dram_config->alt_clock_bw_conversion) { + unsigned long uclk_bytes_per_tick = 0; - uclk_khz = (double)bandwidth_kbps / uclk_mbytes_per_tick; + uclk_bytes_per_tick = dram_config->channel_count * dram_config->channel_width_bytes * dram_config->transactions_per_clock; + uclk_khz = (double)bandwidth_kbps / uclk_bytes_per_tick; + } else { + int i; + /* For lpddr5 bytes per tick changes with mpstate, use table to find uclk*/ + for (i = 0; i < dram_bw_table->num_entries; i++) + if (dram_bw_table->entries[i].pre_derate_dram_bw_kbps >= bandwidth_kbps) { + uclk_khz = dram_bw_table->entries[i].min_uclk_khz; + break; + } + } return uclk_khz; } @@ -34,7 +44,7 @@ static void get_minimum_clocks_for_latency(struct dml2_dpmm_map_mode_to_soc_dpm_ *dcfclk = in_out->min_clk_table->dram_bw_table.entries[min_clock_index_for_latency].min_dcfclk_khz; *fclk = in_out->min_clk_table->dram_bw_table.entries[min_clock_index_for_latency].min_fclk_khz; *uclk = dram_bw_kbps_to_uclk_khz(in_out->min_clk_table->dram_bw_table.entries[min_clock_index_for_latency].pre_derate_dram_bw_kbps, - &in_out->soc_bb->clk_table.dram_config); + &in_out->soc_bb->clk_table.dram_config, &in_out->min_clk_table->dram_bw_table); } static unsigned long dml_round_up(double a) @@ -53,14 +63,18 @@ static void calculate_system_active_minimums(struct dml2_dpmm_map_mode_to_soc_dp double min_uclk_latency, min_fclk_latency, min_dcfclk_latency; const struct dml2_core_mode_support_result *mode_support_result = &in_out->display_cfg->mode_support_result; - min_uclk_avg = dram_bw_kbps_to_uclk_khz(mode_support_result->global.active.average_bw_dram_kbps, &in_out->soc_bb->clk_table.dram_config); - min_uclk_avg = (double)min_uclk_avg / ((double)in_out->soc_bb->qos_parameters.derate_table.system_active_average.dram_derate_percent_pixel / 100); + min_uclk_avg = dram_bw_kbps_to_uclk_khz(mode_support_result->global.active.average_bw_dram_kbps + / ((double)in_out->soc_bb->qos_parameters.derate_table.system_active_average.dram_derate_percent_pixel / 100), + &in_out->soc_bb->clk_table.dram_config, &in_out->min_clk_table->dram_bw_table); - min_uclk_urgent = dram_bw_kbps_to_uclk_khz(mode_support_result->global.active.urgent_bw_dram_kbps, &in_out->soc_bb->clk_table.dram_config); if (in_out->display_cfg->display_config.hostvm_enable) - min_uclk_urgent = (double)min_uclk_urgent / ((double)in_out->soc_bb->qos_parameters.derate_table.system_active_urgent.dram_derate_percent_pixel_and_vm / 100); + min_uclk_urgent = dram_bw_kbps_to_uclk_khz(mode_support_result->global.active.urgent_bw_dram_kbps + / ((double)in_out->soc_bb->qos_parameters.derate_table.system_active_urgent.dram_derate_percent_pixel_and_vm / 100), + &in_out->soc_bb->clk_table.dram_config, &in_out->min_clk_table->dram_bw_table); else - min_uclk_urgent = (double)min_uclk_urgent / ((double)in_out->soc_bb->qos_parameters.derate_table.system_active_urgent.dram_derate_percent_pixel / 100); + min_uclk_urgent = dram_bw_kbps_to_uclk_khz(mode_support_result->global.active.urgent_bw_dram_kbps + / ((double)in_out->soc_bb->qos_parameters.derate_table.system_active_urgent.dram_derate_percent_pixel / 100), + &in_out->soc_bb->clk_table.dram_config, &in_out->min_clk_table->dram_bw_table); min_uclk_bw = min_uclk_urgent > min_uclk_avg ? min_uclk_urgent : min_uclk_avg; @@ -97,11 +111,13 @@ static void calculate_svp_prefetch_minimums(struct dml2_dpmm_map_mode_to_soc_dpm const struct dml2_core_mode_support_result *mode_support_result = &in_out->display_cfg->mode_support_result; /* assumes DF throttling is enabled */ - min_uclk_avg = dram_bw_kbps_to_uclk_khz(mode_support_result->global.svp_prefetch.average_bw_dram_kbps, &in_out->soc_bb->clk_table.dram_config); - min_uclk_avg = (double)min_uclk_avg / ((double)in_out->soc_bb->qos_parameters.derate_table.dcn_mall_prefetch_average.dram_derate_percent_pixel / 100); + min_uclk_avg = dram_bw_kbps_to_uclk_khz(mode_support_result->global.svp_prefetch.average_bw_dram_kbps + / ((double)in_out->soc_bb->qos_parameters.derate_table.dcn_mall_prefetch_average.dram_derate_percent_pixel / 100), + &in_out->soc_bb->clk_table.dram_config, &in_out->min_clk_table->dram_bw_table); - min_uclk_urgent = dram_bw_kbps_to_uclk_khz(mode_support_result->global.svp_prefetch.urgent_bw_dram_kbps, &in_out->soc_bb->clk_table.dram_config); - min_uclk_urgent = (double)min_uclk_urgent / ((double)in_out->soc_bb->qos_parameters.derate_table.dcn_mall_prefetch_urgent.dram_derate_percent_pixel / 100); + min_uclk_urgent = dram_bw_kbps_to_uclk_khz(mode_support_result->global.svp_prefetch.urgent_bw_dram_kbps + / ((double)in_out->soc_bb->qos_parameters.derate_table.dcn_mall_prefetch_urgent.dram_derate_percent_pixel / 100), + &in_out->soc_bb->clk_table.dram_config, &in_out->min_clk_table->dram_bw_table); min_uclk_bw = min_uclk_urgent > min_uclk_avg ? min_uclk_urgent : min_uclk_avg; @@ -128,11 +144,13 @@ static void calculate_svp_prefetch_minimums(struct dml2_dpmm_map_mode_to_soc_dpm in_out->programming->min_clocks.dcn4x.svp_prefetch.dcfclk_khz = dml_round_up(min_dcfclk_bw > min_dcfclk_latency ? min_dcfclk_bw : min_dcfclk_latency); /* assumes DF throttling is disabled */ - min_uclk_avg = dram_bw_kbps_to_uclk_khz(mode_support_result->global.svp_prefetch.average_bw_dram_kbps, &in_out->soc_bb->clk_table.dram_config); - min_uclk_avg = (double)min_uclk_avg / ((double)in_out->soc_bb->qos_parameters.derate_table.system_active_average.dram_derate_percent_pixel / 100); + min_uclk_avg = dram_bw_kbps_to_uclk_khz(mode_support_result->global.svp_prefetch.average_bw_dram_kbps + / ((double)in_out->soc_bb->qos_parameters.derate_table.system_active_average.dram_derate_percent_pixel / 100), + &in_out->soc_bb->clk_table.dram_config, &in_out->min_clk_table->dram_bw_table); - min_uclk_urgent = dram_bw_kbps_to_uclk_khz(mode_support_result->global.svp_prefetch.urgent_bw_dram_kbps, &in_out->soc_bb->clk_table.dram_config); - min_uclk_urgent = (double)min_uclk_urgent / ((double)in_out->soc_bb->qos_parameters.derate_table.system_active_urgent.dram_derate_percent_pixel / 100); + min_uclk_urgent = dram_bw_kbps_to_uclk_khz(mode_support_result->global.svp_prefetch.urgent_bw_dram_kbps + / ((double)in_out->soc_bb->qos_parameters.derate_table.system_active_urgent.dram_derate_percent_pixel / 100), + &in_out->soc_bb->clk_table.dram_config, &in_out->min_clk_table->dram_bw_table); min_uclk_bw = min_uclk_urgent > min_uclk_avg ? min_uclk_urgent : min_uclk_avg; @@ -167,8 +185,9 @@ static void calculate_idle_minimums(struct dml2_dpmm_map_mode_to_soc_dpm_params_ double min_uclk_latency, min_fclk_latency, min_dcfclk_latency; const struct dml2_core_mode_support_result *mode_support_result = &in_out->display_cfg->mode_support_result; - min_uclk_avg = dram_bw_kbps_to_uclk_khz(mode_support_result->global.active.average_bw_dram_kbps, &in_out->soc_bb->clk_table.dram_config); - min_uclk_avg = (double)min_uclk_avg / ((double)in_out->soc_bb->qos_parameters.derate_table.system_idle_average.dram_derate_percent_pixel / 100); + min_uclk_avg = dram_bw_kbps_to_uclk_khz(mode_support_result->global.active.average_bw_dram_kbps + / ((double)in_out->soc_bb->qos_parameters.derate_table.system_idle_average.dram_derate_percent_pixel / 100), + &in_out->soc_bb->clk_table.dram_config, &in_out->min_clk_table->dram_bw_table); min_fclk_avg = (double)mode_support_result->global.active.average_bw_sdp_kbps / in_out->soc_bb->fabric_datapath_to_dcn_data_return_bytes; min_fclk_avg = (double)min_fclk_avg / ((double)in_out->soc_bb->qos_parameters.derate_table.system_idle_average.fclk_derate_percent / 100); diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/inc/dml2_internal_shared_types.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/inc/dml2_internal_shared_types.h index 1a6c0727cd2a..a6bd75f30d20 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/inc/dml2_internal_shared_types.h +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/inc/dml2_internal_shared_types.h @@ -16,6 +16,7 @@ struct dram_bw_to_min_clk_table_entry { unsigned long long pre_derate_dram_bw_kbps; + unsigned long min_uclk_khz; unsigned long min_fclk_khz; unsigned long min_dcfclk_khz; }; From 9a42510d6bc75324f1636f8e654d31ff08257a9a Mon Sep 17 00:00:00 2001 From: Peichen Huang Date: Fri, 9 Jan 2026 17:04:25 +0800 Subject: [PATCH 04/51] drm/amd/display: External panel replay fsm control [WHY] To correctly control external panel replay fsm. [HOW] 1. External panel replay is 1-A option only now. 2. Update cursor update and dirty rects commands for external panel replay support. 3. Add external panel replay support flag in dc. Reviewed-by: Robin Chen Signed-off-by: Peichen Huang Signed-off-by: Wayne Lin Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 19 +++++-- drivers/gpu/drm/amd/display/dc/dc.h | 1 + drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c | 15 ++++-- drivers/gpu/drm/amd/display/dc/dc_types.h | 2 +- .../dc/link/protocols/link_dp_panel_replay.c | 52 +++++++++++++++++++ 5 files changed, 80 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index cb85b7ac2697..4305691ba45e 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -3860,7 +3860,7 @@ void dc_dmub_update_dirty_rect(struct dc *dc, if (!dc_dmub_should_send_dirty_rect_cmd(dc, stream)) return; - if (!dc_get_edp_link_panel_inst(dc, stream->link, &panel_inst)) + if (!dc->config.frame_update_cmd_version2 && !dc_get_edp_link_panel_inst(dc, stream->link, &panel_inst)) return; memset(&cmd, 0x0, sizeof(cmd)); @@ -3880,7 +3880,11 @@ void dc_dmub_update_dirty_rect(struct dc *dc, if (srf_updates[i].surface->flip_immediate) continue; - update_dirty_rect->cmd_version = DMUB_CMD_PSR_CONTROL_VERSION_1; + if (dc->config.frame_update_cmd_version2) + update_dirty_rect->cmd_version = DMUB_CMD_CURSOR_UPDATE_VERSION_2; + else + update_dirty_rect->cmd_version = DMUB_CMD_CURSOR_UPDATE_VERSION_1; + update_dirty_rect->dirty_rect_count = flip_addr->dirty_rect_count; memcpy(update_dirty_rect->src_dirty_rects, flip_addr->dirty_rects, sizeof(flip_addr->dirty_rects)); @@ -3894,6 +3898,7 @@ void dc_dmub_update_dirty_rect(struct dc *dc, update_dirty_rect->panel_inst = panel_inst; update_dirty_rect->pipe_idx = j; + update_dirty_rect->otg_inst = pipe_ctx->stream_res.tg->inst; dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_NO_WAIT); } } @@ -3916,7 +3921,7 @@ static void build_dmub_update_dirty_rect( if (!dc_dmub_should_send_dirty_rect_cmd(dc, stream)) return; - if (!dc_get_edp_link_panel_inst(dc, stream->link, &panel_inst)) + if (!dc->config.frame_update_cmd_version2 && !dc_get_edp_link_panel_inst(dc, stream->link, &panel_inst)) return; memset(&cmd, 0x0, sizeof(cmd)); @@ -3935,7 +3940,12 @@ static void build_dmub_update_dirty_rect( /* Do not send in immediate flip mode */ if (srf_updates[i].surface->flip_immediate) continue; - update_dirty_rect->cmd_version = DMUB_CMD_PSR_CONTROL_VERSION_1; + + if (dc->config.frame_update_cmd_version2) + update_dirty_rect->cmd_version = DMUB_CMD_CURSOR_UPDATE_VERSION_2; + else + update_dirty_rect->cmd_version = DMUB_CMD_CURSOR_UPDATE_VERSION_1; + update_dirty_rect->dirty_rect_count = flip_addr->dirty_rect_count; memcpy(update_dirty_rect->src_dirty_rects, flip_addr->dirty_rects, sizeof(flip_addr->dirty_rects)); @@ -3948,6 +3958,7 @@ static void build_dmub_update_dirty_rect( continue; update_dirty_rect->panel_inst = panel_inst; update_dirty_rect->pipe_idx = j; + update_dirty_rect->otg_inst = pipe_ctx->stream_res.tg->inst; dc_dmub_cmd[*dmub_cmd_count].dmub_cmd = cmd; dc_dmub_cmd[*dmub_cmd_count].wait_type = DM_DMUB_WAIT_TYPE_NO_WAIT; (*dmub_cmd_count)++; diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index ab19b6230945..ce2eceba2ab7 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -560,6 +560,7 @@ struct dc_config { bool enable_dpia_pre_training; bool unify_link_enc_assignment; bool enable_cursor_offload; + bool frame_update_cmd_version2; struct spl_sharpness_range dcn_sharpness_range; struct spl_sharpness_range dcn_override_sharpness_range; }; 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 dc1b3f6c22c9..e4dd5ca70987 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c @@ -1034,12 +1034,19 @@ static void dc_build_cursor_update_payload0( struct pipe_ctx *pipe_ctx, uint8_t p_idx, struct dmub_cmd_update_cursor_payload0 *payload) { + struct dc *dc = pipe_ctx->stream->ctx->dc; struct hubp *hubp = pipe_ctx->plane_res.hubp; unsigned int panel_inst = 0; - if (!dc_get_edp_link_panel_inst(hubp->ctx->dc, - pipe_ctx->stream->link, &panel_inst)) - return; + if (dc->config.frame_update_cmd_version2 == true) { + /* Don't need panel_inst for command version2 */ + payload->cmd_version = DMUB_CMD_CURSOR_UPDATE_VERSION_2; + } else { + if (!dc_get_edp_link_panel_inst(hubp->ctx->dc, + pipe_ctx->stream->link, &panel_inst)) + return; + payload->cmd_version = DMUB_CMD_CURSOR_UPDATE_VERSION_1; + } /* Payload: Cursor Rect is built from position & attribute * x & y are obtained from postion @@ -1052,8 +1059,8 @@ static void dc_build_cursor_update_payload0( payload->enable = hubp->pos.cur_ctl.bits.cur_enable; payload->pipe_idx = p_idx; - payload->cmd_version = DMUB_CMD_PSR_CONTROL_VERSION_1; payload->panel_inst = panel_inst; + payload->otg_inst = pipe_ctx->stream_res.tg->inst; } static void dc_build_cursor_position_update_payload0( diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index 0e953059ff6d..2e38b6840c71 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -1230,7 +1230,7 @@ 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 */ + /* Current Panel Replay events */ uint32_t replay_events; }; 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 bbd6f93f5c98..cc3b44cf7662 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 @@ -35,6 +35,46 @@ #define DP_SINK_PR_ENABLE_AND_CONFIGURATION 0x37B +static unsigned int dp_pr_calc_num_static_frames(unsigned int vsync_rate_hz) +{ + // at least 2 frames for static screen + unsigned int num_frames = 2; + + // get number of frames for at least 50ms + if (vsync_rate_hz > 40) + num_frames = (vsync_rate_hz + 10) / 20; + + return num_frames; +} + +static void dp_pr_set_static_screen_param(struct dc_link *link) +{ + struct dc_static_screen_params params = {0}; + struct dc *dc = link->ctx->dc; + // only support DP sst for now + if (!dc_is_dp_sst_signal(link->connector_signal)) + return; + + for (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 == link) { + struct dc_stream_state *stream = dc->current_state->res_ctx.pipe_ctx[i].stream; + unsigned int vsync_rate_hz = div64_u64(div64_u64( + (stream->timing.pix_clk_100hz * (u64)100), + stream->timing.v_total), + stream->timing.h_total); + + params.triggers.cursor_update = true; + params.triggers.overlay_update = true; + params.triggers.surface_update = true; + params.num_frames = dp_pr_calc_num_static_frames(vsync_rate_hz); + + dc_stream_set_static_screen_params(dc, &stream, 1, ¶ms); + break; + } + } +} + static bool dp_setup_panel_replay(struct dc_link *link, const struct dc_stream_state *stream) { /* To-do: Setup Replay */ @@ -159,6 +199,9 @@ bool dp_pr_get_panel_inst(const struct dc *dc, if (!dc || !link || !inst_out) return false; + if (dc->config.frame_update_cmd_version2 == false) + return dc_get_edp_link_panel_inst(dc, link, inst_out); + if (!dc_is_dp_sst_signal(link->connector_signal)) /* only supoprt DP sst (eDP included) for now */ return false; @@ -199,6 +242,9 @@ bool dp_pr_enable(struct dc_link *link, bool enable) if (!dp_pr_get_panel_inst(dc, link, &panel_inst)) return false; + if (enable && !dc_is_embedded_signal(link->connector_signal)) + dp_pr_set_static_screen_param(link); + if (link->replay_settings.replay_allow_active != enable) { //for sending PR enable commands to DMUB memset(&cmd, 0, sizeof(cmd)); @@ -276,6 +322,12 @@ bool dp_pr_copy_settings(struct dc_link *link, struct replay_context *replay_con pipe_ctx->stream->timing.v_border_top + pipe_ctx->stream->timing.v_border_bottom) / pipe_ctx->stream->timing.dsc_cfg.num_slices_v; + if (dc_is_embedded_signal(link->connector_signal)) + cmd.pr_copy_settings.data.main_link_activity_option = 0x03;//OPTION_1C; + else + // For external DP, use option 1-A + cmd.pr_copy_settings.data.main_link_activity_option = 0x01;//OPTION_1A; + dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); return true; } From 8488fb054ea8a603921fe0a05bfc2bd43e64c5bc Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Mon, 19 Jan 2026 16:09:50 -0500 Subject: [PATCH 05/51] drm/amd/display: Make DCN35 OTG disable w/a reusable The logic for the OTG disable workaround is particularly complex and should be leveraged going forward instead of reimplementing and maintaining it for multiple ASIC. Reviewed-by: Ovidiu Bunea Signed-off-by: Nicholas Kazlauskas Signed-off-by: Wayne Lin Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c | 2 +- .../gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.h | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c index 72558cc55a9a..7abe6811e4df 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c @@ -186,7 +186,7 @@ static int dcn35_get_active_display_cnt_wa( return display_count; } -static void dcn35_disable_otg_wa(struct clk_mgr *clk_mgr_base, struct dc_state *context, +void dcn35_disable_otg_wa(struct clk_mgr *clk_mgr_base, struct dc_state *context, bool safe_to_lower, bool disable) { struct dc *dc = clk_mgr_base->ctx->dc; diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.h index a12a9bf90806..83e2263563fe 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.h +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.h @@ -64,4 +64,10 @@ void dcn351_clk_mgr_construct(struct dc_context *ctx, struct clk_mgr_dcn35 *clk_mgr, struct pp_smu_funcs *pp_smu, struct dccg *dccg); + +void dcn35_disable_otg_wa(struct clk_mgr *clk_mgr_base, + struct dc_state *context, + bool safe_to_lower, + bool disable); + #endif //__DCN35_CLK_MGR_H__ From b8285d2ee73758386252cc3a67839bc463dfa1cc Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Wed, 14 Jan 2026 14:55:38 -0500 Subject: [PATCH 06/51] drm/amd/display: Make DSC FGCG a DSC block level function [Why] FGCG shouldn't be called at the DC resource level as part of DSC creation because dc_create is intended for SW init, not HW init, and register access is not guaranteed to work at this phase. [How] Add a set_fgcg function at the DSC interface level. Existing ASIC can continue using the function in DC resource to retain current compatibility but further development should favor calling the function pointer during init_hw (if it exists). Reviewed-by: Dillon Varone Signed-off-by: Nicholas Kazlauskas Signed-off-by: Wayne Lin Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dsc/dsc.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/display/dc/dsc/dsc.h b/drivers/gpu/drm/amd/display/dc/dsc/dsc.h index 81c83d5fe042..ad7ef83694ea 100644 --- a/drivers/gpu/drm/amd/display/dc/dsc/dsc.h +++ b/drivers/gpu/drm/amd/display/dc/dsc/dsc.h @@ -115,6 +115,7 @@ struct dsc_funcs { void (*dsc_disconnect)(struct display_stream_compressor *dsc); void (*dsc_wait_disconnect_pending_clear)(struct display_stream_compressor *dsc); void (*dsc_get_single_enc_caps)(struct dsc_enc_caps *dsc_enc_caps, unsigned int max_dscclk_khz); + void (*set_fgcg)(struct display_stream_compressor *dsc, bool enable); }; #endif From 2ac80621e0efcc145f15a05a60f185d26290c4bd Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Fri, 16 Jan 2026 16:49:46 -0500 Subject: [PATCH 07/51] drm/amd/display: Make some DCN35 DCCG symbols non-static In order to have few DCN35 functions be leveraged for future ASIC implementations. Expose them to the dcn35_dccg.h header. Reviewed-by: Ovidiu Bunea Signed-off-by: Nicholas Kazlauskas Signed-off-by: Wayne Lin Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../amd/display/dc/dccg/dcn35/dcn35_dccg.c | 30 +++++++------------ .../amd/display/dc/dccg/dcn35/dcn35_dccg.h | 17 +++++++++++ 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c index bd2f528137b2..838c6617c029 100644 --- a/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c +++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c @@ -1105,7 +1105,7 @@ static void dccg35_enable_dpstreamclk_new(struct dccg *dccg, dccg35_set_dpstreamclk_src_new(dccg, src, inst); } -static void dccg35_trigger_dio_fifo_resync(struct dccg *dccg) +void dccg35_trigger_dio_fifo_resync(struct dccg *dccg) { struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); uint32_t dispclk_rdivider_value = 0; @@ -1114,6 +1114,7 @@ static void dccg35_trigger_dio_fifo_resync(struct dccg *dccg) if (dispclk_rdivider_value != 0) REG_UPDATE(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_WDIVIDER, dispclk_rdivider_value); } + static void dccg35_wait_for_dentist_change_done( struct dccg *dccg) { @@ -1151,8 +1152,7 @@ static void dcn35_set_dppclk_enable(struct dccg *dccg, } -static void dccg35_update_dpp_dto(struct dccg *dccg, int dpp_inst, - int req_dppclk) +void dccg35_update_dpp_dto(struct dccg *dccg, int dpp_inst, int req_dppclk) { struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); @@ -1498,11 +1498,7 @@ static void dccg35_set_dpstreamclk( __func__, dp_hpo_inst, (src == REFCLK) ? 0 : 1, otg_inst); } - -static void dccg35_set_dpstreamclk_root_clock_gating( - struct dccg *dccg, - int dp_hpo_inst, - bool enable) +void dccg35_set_dpstreamclk_root_clock_gating(struct dccg *dccg, int dp_hpo_inst, bool enable) { struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); @@ -1669,10 +1665,7 @@ static void dccg35_set_valid_pixel_rate( dccg35_set_dtbclk_dto(dccg, &dto_params); } -static void dccg35_dpp_root_clock_control( - struct dccg *dccg, - unsigned int dpp_inst, - bool clock_on) +void dccg35_dpp_root_clock_control(struct dccg *dccg, unsigned int dpp_inst, bool clock_on) { struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); @@ -1704,9 +1697,7 @@ static void dccg35_dpp_root_clock_control( DC_LOG_DEBUG("%s: dpp_inst(%d) clock_on = %d\n", __func__, dpp_inst, clock_on); } -static void dccg35_disable_symclk32_se( - struct dccg *dccg, - int hpo_se_inst) +void dccg35_disable_symclk32_se(struct dccg *dccg, int hpo_se_inst) { struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); @@ -1813,7 +1804,7 @@ void dccg35_enable_global_fgcg_rep(struct dccg *dccg, bool value) REG_UPDATE(DCCG_GLOBAL_FGCG_REP_CNTL, DCCG_GLOBAL_FGCG_REP_DIS, !value); } -static void dccg35_enable_dscclk(struct dccg *dccg, int inst) +void dccg35_enable_dscclk(struct dccg *dccg, int inst) { struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); @@ -1860,8 +1851,7 @@ static void dccg35_enable_dscclk(struct dccg *dccg, int inst) udelay(10); } -static void dccg35_disable_dscclk(struct dccg *dccg, - int inst) +void dccg35_disable_dscclk(struct dccg *dccg, int inst) { struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); @@ -1906,7 +1896,7 @@ static void dccg35_disable_dscclk(struct dccg *dccg, udelay(10); } -static void dccg35_enable_symclk_se(struct dccg *dccg, uint32_t stream_enc_inst, uint32_t link_enc_inst) +void dccg35_enable_symclk_se(struct dccg *dccg, uint32_t stream_enc_inst, uint32_t link_enc_inst) { struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); @@ -2013,7 +2003,7 @@ static uint8_t dccg35_get_number_enabled_symclk_fe_connected_to_be(struct dccg * return num_enabled_symclk_fe; } -static void dccg35_disable_symclk_se(struct dccg *dccg, uint32_t stream_enc_inst, uint32_t link_enc_inst) +void dccg35_disable_symclk_se(struct dccg *dccg, uint32_t stream_enc_inst, uint32_t link_enc_inst) { uint8_t num_enabled_symclk_fe = 0; struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.h b/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.h index 7b9c36456cd9..554700287c1a 100644 --- a/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.h +++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.h @@ -249,8 +249,25 @@ struct dccg *dccg35_create( void dccg35_init(struct dccg *dccg); +void dccg35_trigger_dio_fifo_resync(struct dccg *dccg); + +void dccg35_update_dpp_dto(struct dccg *dccg, int dpp_inst, int req_dppclk); + void dccg35_enable_global_fgcg_rep(struct dccg *dccg, bool value); void dccg35_root_gate_disable_control(struct dccg *dccg, uint32_t pipe_idx, uint32_t disable_clock_gating); +void dccg35_set_dpstreamclk_root_clock_gating(struct dccg *dccg, int dp_hpo_inst, bool enable); + +void dccg35_set_hdmistreamclk_root_clock_gating(struct dccg *dccg, bool enable); + +void dccg35_dpp_root_clock_control(struct dccg *dccg, unsigned int dpp_inst, bool clock_on); + +void dccg35_disable_symclk32_se(struct dccg *dccg, int hpo_se_inst); + +void dccg35_enable_dscclk(struct dccg *dccg, int inst); +void dccg35_disable_dscclk(struct dccg *dccg, int inst); + +void dccg35_enable_symclk_se(struct dccg *dccg, uint32_t stream_enc_inst, uint32_t link_enc_inst); +void dccg35_disable_symclk_se(struct dccg *dccg, uint32_t stream_enc_inst, uint32_t link_enc_inst); #endif //__DCN35_DCCG_H__ From 9ef84a307582a92ef055ef0bd3db10fd8ac75960 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Wed, 14 Jan 2026 17:20:31 -0700 Subject: [PATCH 08/51] drm/amd/display: Fix writeback on DCN 3.2+ [WHAT] 1. Set no scaling for writeback as they are hardcoded in DCN3.2+. 2. Set no fast plane update for writeback commits. Reviewed-by: Harry Wentland Signed-off-by: Alex Hung Signed-off-by: Wayne Lin Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 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 0b4fc654e76f..56332f3f95ef 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -10662,10 +10662,10 @@ static void dm_set_writeback(struct amdgpu_display_manager *dm, wb_info->dwb_params.capture_rate = dwb_capture_rate_0; - wb_info->dwb_params.scaler_taps.h_taps = 4; - wb_info->dwb_params.scaler_taps.v_taps = 4; - wb_info->dwb_params.scaler_taps.h_taps_c = 2; - wb_info->dwb_params.scaler_taps.v_taps_c = 2; + wb_info->dwb_params.scaler_taps.h_taps = 1; + wb_info->dwb_params.scaler_taps.v_taps = 1; + wb_info->dwb_params.scaler_taps.h_taps_c = 1; + wb_info->dwb_params.scaler_taps.v_taps_c = 1; wb_info->dwb_params.subsample_position = DWB_INTERSTITIAL_SUBSAMPLING; wb_info->mcif_buf_params.luma_pitch = afb->base.pitches[0]; @@ -11681,6 +11681,8 @@ static bool should_reset_plane(struct drm_atomic_state *state, struct drm_crtc_state *old_crtc_state, *new_crtc_state; struct dm_crtc_state *old_dm_crtc_state, *new_dm_crtc_state; struct amdgpu_device *adev = drm_to_adev(plane->dev); + struct drm_connector_state *new_con_state; + struct drm_connector *connector; int i; /* @@ -11691,6 +11693,15 @@ static bool should_reset_plane(struct drm_atomic_state *state, state->allow_modeset) return true; + /* Check for writeback commit */ + for_each_new_connector_in_state(state, connector, new_con_state, i) { + if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) + continue; + + if (new_con_state->writeback_job) + return true; + } + if (amdgpu_in_reset(adev) && state->allow_modeset) return true; From bb4099c7d90043673c8089ae1dce0d6c7d393f13 Mon Sep 17 00:00:00 2001 From: Ray Wu Date: Tue, 20 Jan 2026 16:29:38 +0800 Subject: [PATCH 09/51] drm/amd/display: Fix IGT link training failure on Replay panel [Why] IGT link-training-configs test fails to set the link rate on Replay panels because some link rate types are not supported in debugfs. As a result, debugfs treats these link rates as invalid, causing the IGT test to fail. [How] Add missing link rate types to resolve this issue. Reviewed-by: ChiaHsuan Chung Signed-off-by: Ray Wu Signed-off-by: Wayne Lin Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index b9ed29ec60dc..5fb573214f18 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -302,8 +302,11 @@ static ssize_t dp_link_settings_write(struct file *f, const char __user *buf, switch (param[1]) { case LINK_RATE_LOW: + case LINK_RATE_RATE_2: + case LINK_RATE_RATE_3: case LINK_RATE_HIGH: case LINK_RATE_RBR2: + case LINK_RATE_RATE_6: case LINK_RATE_HIGH2: case LINK_RATE_HIGH3: case LINK_RATE_UHBR10: From 0054d5a57a98c1a6783ffd9c8b7ceda8f8bb46d1 Mon Sep 17 00:00:00 2001 From: Ian Chen Date: Wed, 3 Dec 2025 16:59:07 +0800 Subject: [PATCH 10/51] drm/amd/display: Add oem panel config for new features [WHAT] Add oem panel config for below features: - CACP_v2 - Adaptive VariBright - Replay_FrameSkipping - Replay_teamsOpt - Ramless Idle Opt Reviewed-by: Robin Chen Signed-off-by: Ian Chen Signed-off-by: Wayne Lin Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc_types.h | 25 ++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index 2e38b6840c71..bddb16bb76d4 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -1256,7 +1256,7 @@ struct dc_panel_config { unsigned int max_nonboost_brightness_millinits; unsigned int min_brightness_millinits; } nits_brightness; - /* PSR */ + /* PSR/Replay */ struct psr { bool disable_psr; bool disallow_psrsu; @@ -1266,6 +1266,8 @@ struct dc_panel_config { bool rc_allow_fullscreen_VPB; bool read_psrcap_again; unsigned int replay_enable_option; + bool enable_frame_skipping; + bool enable_teams_optimization; } psr; /* ABM */ struct varib { @@ -1282,6 +1284,27 @@ struct dc_panel_config { struct ilr { bool optimize_edp_link_rate; /* eDP ILR */ } ilr; + /* Adaptive VariBright*/ + struct adaptive_vb { + bool disable_adaptive_vb; + unsigned int default_abm_vb_levels; // default value = 0xDCAA6414 + unsigned int default_cacp_vb_levels; + unsigned int default_abm_vb_hdr_levels; // default value = 0xB4805A40 + unsigned int default_cacp_vb_hdr_levels; + unsigned int abm_scaling_factors; // default value = 0x23210012 + unsigned int cacp_scaling_factors; + unsigned int battery_life_configures; // default value = 0x0A141E + unsigned int abm_backlight_adaptive_pwl_1; // default value = 0x6A4F7244 + unsigned int abm_backlight_adaptive_pwl_2; // default value = 0x4C615659 + unsigned int abm_backlight_adaptive_pwl_3; // default value = 0x0064 + unsigned int cacp_backlight_adaptive_pwl_1; + unsigned int cacp_backlight_adaptive_pwl_2; + unsigned int cacp_backlight_adaptive_pwl_3; + } adaptive_vb; + /* Ramless Idle Opt*/ + struct rio { + bool disable_rio; + } rio; }; #define MAX_SINKS_PER_LINK 4 From e121ccca8a4a5dd6fb5d395de6ef31ebfce7fb38 Mon Sep 17 00:00:00 2001 From: Ray Wu Date: Tue, 20 Jan 2026 16:55:43 +0800 Subject: [PATCH 11/51] drm/amd/display: Fix IGT ILR link training failure on Replay panel [Why & How] Fix the IGT ilr_link-training-configs test failure by directly using the supported link rates from DPCD. Reviewed-by: ChiaHsuan Chung Signed-off-by: Ray Wu Signed-off-by: Wayne Lin Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index 5fb573214f18..cfe35442dfcb 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -46,6 +46,7 @@ #include "amdgpu_dm_psr.h" #endif +#define MULTIPLIER_TO_LR 270000 struct dmub_debugfs_trace_header { uint32_t entry_count; uint32_t reserved[3]; @@ -3507,6 +3508,10 @@ static ssize_t edp_ilr_write(struct file *f, const char __user *buf, uint8_t param_nums = 0; long param[2]; bool valid_input = true; + uint8_t supported_link_rates[16] = {0}; + uint32_t entry = 0; + uint32_t link_rate_in_khz = 0; + uint8_t dpcd_rev = 0; if (size == 0) return -EINVAL; @@ -3551,6 +3556,20 @@ static ssize_t edp_ilr_write(struct file *f, const char __user *buf, return size; } + if (!dm_helpers_dp_read_dpcd(link->ctx, link, DP_SUPPORTED_LINK_RATES, + supported_link_rates, sizeof(supported_link_rates))) + return -EINVAL; + + dpcd_rev = link->dpcd_caps.dpcd_rev.raw; + if (dpcd_rev < DP_DPCD_REV_13 || + (supported_link_rates[entry + 1] == 0 && supported_link_rates[entry] == 0)) { + return size; + } + + entry = param[1] * 2; + link_rate_in_khz = (supported_link_rates[entry + 1] * 0x100 + + supported_link_rates[entry]) * 200; + /* save user force lane_count, link_rate to preferred settings * spread spectrum will not be changed */ @@ -3558,7 +3577,7 @@ static ssize_t edp_ilr_write(struct file *f, const char __user *buf, prefer_link_settings.lane_count = param[0]; prefer_link_settings.use_link_rate_set = true; prefer_link_settings.link_rate_set = param[1]; - prefer_link_settings.link_rate = link->dpcd_caps.edp_supported_link_rates[param[1]]; + prefer_link_settings.link_rate = link_rate_in_khz / MULTIPLIER_TO_LR; mutex_lock(&adev->dm.dc_lock); dc_link_set_preferred_training_settings(dc, &prefer_link_settings, From 9d6bd60695806782bec8562ab73aefafce067f05 Mon Sep 17 00:00:00 2001 From: Wenjing Liu Date: Tue, 20 Jan 2026 22:40:07 +0000 Subject: [PATCH 12/51] drm/amd/display: Fix a NULL pointer dereference in dcn20_hwseq.c [why] hws->funcs.dccg_init is accessed without checking if it is NULL, which may lead to a NULL pointer dereference. [how] Add a NULL check before calling dccg_init. Reviewed-by: Nicholas Kazlauskas Signed-off-by: Wenjing Liu Signed-off-by: Wayne Lin Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c index 87a1dc27def4..307e8f8060e6 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c @@ -3140,7 +3140,8 @@ void dcn20_fpga_init_hw(struct dc *dc) dcn10_hubbub_global_timer_enable(dc->res_pool->hubbub, true, 2); - hws->funcs.dccg_init(hws); + if (hws->funcs.dccg_init) + hws->funcs.dccg_init(hws); if (dc->res_pool->dccg && dc->res_pool->dccg->funcs && dc->res_pool->dccg->funcs->refclk_setup) dc->res_pool->dccg->funcs->refclk_setup(dc->res_pool->dccg); From 08a01ec306dbd0e096be8ee0cebb0e6a3b5fa413 Mon Sep 17 00:00:00 2001 From: Nicholas Carbones Date: Tue, 6 Jan 2026 17:35:51 -0500 Subject: [PATCH 13/51] drm/amd/display: Add Gfx Base Case For Linear Tiling Handling [Why] Post-driver cases always use linear tiling yet there is no dedicated Gfx handling for this condition. [How] Add DcGfxBase/DalGfxBase to gfx version enums and set tiling to linear when it is used. Also, enforce the use of proper tiling format as tiling information is used. Reviewed-by: Dillon Varone Signed-off-by: Nicholas Carbones Signed-off-by: Wayne Lin Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 1 + drivers/gpu/drm/amd/display/dc/core/dc.c | 1 + drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c | 7 +++++++ drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 1 + drivers/gpu/drm/amd/display/dc/dc_hw_types.h | 3 ++- drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c | 3 +++ drivers/gpu/drm/amd/display/dc/dce110/dce110_mem_input_v.c | 3 +++ drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c | 1 + drivers/gpu/drm/amd/display/dc/hubp/dcn10/dcn10_hubp.c | 2 ++ drivers/gpu/drm/amd/display/dc/hubp/dcn20/dcn20_hubp.c | 2 ++ drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.c | 2 ++ drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c | 7 ++++++- .../amd/display/dc/resource/dcn32/dcn32_resource_helpers.c | 3 ++- 13 files changed, 33 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 56332f3f95ef..ca40166ca924 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -8032,6 +8032,7 @@ static enum dc_status dm_validate_stream_and_context(struct dc *dc, dc_plane_state->plane_size.chroma_size.height = stream->src.height; dc_plane_state->plane_size.chroma_size.width = stream->src.width; dc_plane_state->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB8888; + dc_plane_state->tiling_info.gfxversion = DcGfxVersion9; dc_plane_state->tiling_info.gfx9.swizzle = DC_SW_UNKNOWN; dc_plane_state->rotation = ROTATION_ANGLE_0; dc_plane_state->is_tiling_rotated = false; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 4305691ba45e..441b7e0a3b22 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -2768,6 +2768,7 @@ static struct surface_update_descriptor get_plane_info_update_type(const struct case DcGfxVersion7: case DcGfxVersion8: case DcGfxVersionUnknown: + case DcGfxBase: default: break; } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c index 052d573408c3..a13d9d7dd6c5 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c @@ -2065,6 +2065,13 @@ void get_surface_tile_visual_confirm_color( while (bottom_pipe_ctx->bottom_pipe != NULL) bottom_pipe_ctx = bottom_pipe_ctx->bottom_pipe; + if (bottom_pipe_ctx->plane_state->tiling_info.gfxversion == DcGfxBase) { + /* LINEAR Surface - set border color to red */ + color->color_r_cr = color_value; + return; + } + + ASSERT(bottom_pipe_ctx->plane_state->tiling_info.gfxversion == DcGfxVersion9); switch (bottom_pipe_ctx->plane_state->tiling_info.gfx9.swizzle) { case DC_SW_LINEAR: /* LINEAR Surface - set border color to red */ diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index 848c267ef11e..b4e5a79e9749 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -4434,6 +4434,7 @@ enum dc_status dc_validate_global_state( if (dc->res_pool->funcs->patch_unknown_plane_state && pipe_ctx->plane_state && + pipe_ctx->plane_state->tiling_info.gfxversion == DcGfxVersion9 && pipe_ctx->plane_state->tiling_info.gfx9.swizzle == DC_SW_UNKNOWN) { result = dc->res_pool->funcs->patch_unknown_plane_state(pipe_ctx->plane_state); if (result != DC_OK) 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 cfa569a7bff1..7121629da38e 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h @@ -342,7 +342,8 @@ enum swizzle_mode_addr3_values { }; enum dc_gfxversion { - DcGfxVersion7 = 0, + DcGfxBase = 0, + DcGfxVersion7, DcGfxVersion8, DcGfxVersion9, DcGfxVersion10, diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c b/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c index 1c2009e38aa1..5df58fadc862 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c @@ -100,6 +100,7 @@ static enum mi_bits_per_pixel get_mi_bpp( static enum mi_tiling_format get_mi_tiling( struct dc_tiling_info *tiling_info) { + ASSERT(tiling_info->gfxversion == DcGfxVersion8); switch (tiling_info->gfx8.array_mode) { case DC_ARRAY_1D_TILED_THIN1: case DC_ARRAY_1D_TILED_THICK: @@ -433,6 +434,7 @@ static void program_tiling( struct dce_mem_input *dce_mi, const struct dc_tiling_info *info) { if (dce_mi->masks->GRPH_SW_MODE) { /* GFX9 */ + ASSERT(info->gfxversion == DcGfxVersion9); REG_UPDATE_6(GRPH_CONTROL, GRPH_SW_MODE, info->gfx9.swizzle, GRPH_NUM_BANKS, log_2(info->gfx9.num_banks), @@ -447,6 +449,7 @@ static void program_tiling( } if (dce_mi->masks->GRPH_MICRO_TILE_MODE) { /* GFX8 */ + ASSERT(info->gfxversion == DcGfxVersion8); REG_UPDATE_9(GRPH_CONTROL, GRPH_NUM_BANKS, info->gfx8.num_banks, GRPH_BANK_WIDTH, info->gfx8.bank_width, diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_mem_input_v.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_mem_input_v.c index 2c43c2422638..67cfca3361fb 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_mem_input_v.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_mem_input_v.c @@ -165,6 +165,8 @@ static void program_tiling( const struct dc_tiling_info *info, const enum surface_pixel_format pixel_format) { + ASSERT(info->gfxversion == DcGfxVersion8); + uint32_t value = 0; set_reg_field_value(value, info->gfx8.num_banks, @@ -541,6 +543,7 @@ static const unsigned int *get_dvmm_hw_setting( else bpp = bpp_8; + ASSERT(tiling_info->gfxversion == DcGfxVersion8); switch (tiling_info->gfx8.array_mode) { case DC_ARRAY_1D_TILED_THIN1: case DC_ARRAY_1D_TILED_THICK: diff --git a/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c b/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c index 74962791302f..71eeee02c0fa 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c @@ -1006,6 +1006,7 @@ bool dcn_validate_bandwidth( v->source_pixel_format[input_idx] = tl_pixel_format_to_bw_defs( pipe->plane_state->format); + ASSERT(pipe->plane_state->tiling_info.gfxversion == DcGfxVersion9); v->source_surface_mode[input_idx] = tl_sw_mode_to_bw_defs( pipe->plane_state->tiling_info.gfx9.swizzle); v->lb_bit_per_pixel[input_idx] = tl_lb_bpp_to_int(pipe->plane_res.scl_data.lb_params.depth); diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn10/dcn10_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn10/dcn10_hubp.c index 6378e3fd7249..e697d9bf1b44 100644 --- a/drivers/gpu/drm/amd/display/dc/hubp/dcn10/dcn10_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn10/dcn10_hubp.c @@ -145,6 +145,8 @@ void hubp1_program_tiling( { struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); + ASSERT(info->gfxversion == DcGfxVersion9); + REG_UPDATE_6(DCSURF_ADDR_CONFIG, NUM_PIPES, log_2(info->gfx9.num_pipes), NUM_BANKS, log_2(info->gfx9.num_banks), diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn20/dcn20_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn20/dcn20_hubp.c index 92288de4cc10..4715e60e812a 100644 --- a/drivers/gpu/drm/amd/display/dc/hubp/dcn20/dcn20_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn20/dcn20_hubp.c @@ -313,6 +313,8 @@ static void hubp2_program_tiling( const struct dc_tiling_info *info, const enum surface_pixel_format pixel_format) { + ASSERT(info->gfxversion == DcGfxVersion9); + REG_UPDATE_3(DCSURF_ADDR_CONFIG, NUM_PIPES, log_2(info->gfx9.num_pipes), PIPE_INTERLEAVE, info->gfx9.pipe_interleave, diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.c index 0cc6f4558989..207c2f86b7d7 100644 --- a/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.c @@ -321,6 +321,8 @@ void hubp3_program_tiling( const struct dc_tiling_info *info, const enum surface_pixel_format pixel_format) { + ASSERT(info->gfxversion == DcGfxVersion9); + REG_UPDATE_4(DCSURF_ADDR_CONFIG, NUM_PIPES, log_2(info->gfx9.num_pipes), PIPE_INTERLEAVE, info->gfx9.pipe_interleave, diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c index c205500290ec..861e940250af 100644 --- a/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c @@ -589,7 +589,12 @@ void hubp401_program_tiling( * * DIM_TYPE field in DCSURF_TILING for Display is always 1 (2D dimension) which is HW default. */ - REG_UPDATE(DCSURF_TILING_CONFIG, SW_MODE, info->gfx_addr3.swizzle); + if (info->gfxversion == DcGfxAddr3) { + REG_UPDATE(DCSURF_TILING_CONFIG, SW_MODE, info->gfx_addr3.swizzle); + } else { + /* linear */ + REG_UPDATE(DCSURF_TILING_CONFIG, SW_MODE, 0); + } } void hubp401_program_size( diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource_helpers.c b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource_helpers.c index f5a4e97c40ce..7d99f5d79e6d 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource_helpers.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource_helpers.c @@ -401,7 +401,8 @@ void dcn32_set_det_allocations(struct dc *dc, struct dc_state *context, */ if (pipe_cnt == 1) { pipes[0].pipe.src.det_size_override = DCN3_2_MAX_DET_SIZE; - if (pipe->plane_state && !disable_unbounded_requesting && pipe->plane_state->tiling_info.gfx9.swizzle != DC_SW_LINEAR) { + if (pipe->plane_state && !disable_unbounded_requesting && pipe->plane_state->tiling_info.gfxversion != DcGfxBase && + !(pipe->plane_state->tiling_info.gfxversion == DcGfxVersion9 && pipe->plane_state->tiling_info.gfx9.swizzle == DC_SW_LINEAR)) { if (!is_dual_plane(pipe->plane_state->format)) { pipes[0].pipe.src.det_size_override = DCN3_2_DEFAULT_DET_SIZE; pipes[0].pipe.src.unbounded_req_mode = true; From c2d2ccc85faf8cc6934d50c18e43097eb453ade2 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 29 Jan 2026 13:47:22 -0600 Subject: [PATCH 14/51] drm/amd: Set minimum version for set_hw_resource_1 on gfx11 to 0x52 commit f81cd793119e ("drm/amd/amdgpu: Fix MES init sequence") caused a dependency on new enough MES firmware to use amdgpu. This was fixed on most gfx11 and gfx12 hardware with commit 0180e0a5dd5c ("drm/amdgpu/mes: add compatibility checks for set_hw_resource_1"), but this left out that GC 11.0.4 had breakage at MES 0x51. Bump the requirement to 0x52 instead. Reported-by: danijel@nausys.com Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4576 Fixes: f81cd793119e ("drm/amd/amdgpu: Fix MES init sequence") Reviewed-by: Alex Deucher Signed-off-by: Mario Limonciello Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/mes_v11_0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c index 81bf9385d55a..09ebb13ca5e8 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c @@ -1673,7 +1673,7 @@ static int mes_v11_0_hw_init(struct amdgpu_ip_block *ip_block) if (r) goto failure; - if ((adev->mes.sched_version & AMDGPU_MES_VERSION_MASK) >= 0x50) { + if ((adev->mes.sched_version & AMDGPU_MES_VERSION_MASK) >= 0x52) { r = mes_v11_0_set_hw_resources_1(&adev->mes); if (r) { DRM_ERROR("failed mes_v11_0_set_hw_resources_1, r=%d\n", r); From b82f0759346617b2cb84d8cc2d4a179795d4efd0 Mon Sep 17 00:00:00 2001 From: Bhuvanachandra Pinninti Date: Thu, 8 Jan 2026 18:37:57 +0530 Subject: [PATCH 15/51] drm/amd/display: Migrate DIO registers access from hwseq to dio component. [why] Direct DIO registers access in hwseq layer was creating register conflicts. [how] Migrated DIO registers from hwseq to dio component. Reviewed-by: Jun Lei Signed-off-by: Bhuvanachandra Pinninti Signed-off-by: Wayne Lin Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dio/Makefile | 2 +- .../drm/amd/display/dc/dio/dcn10/dcn10_dio.c | 47 +++++++++++++++++++ .../drm/amd/display/dc/dio/dcn10/dcn10_dio.h | 42 +++++++++++++++++ .../amd/display/dc/hwss/dcn10/dcn10_hwseq.c | 4 +- .../amd/display/dc/hwss/dcn201/dcn201_hwseq.c | 5 +- .../amd/display/dc/hwss/dcn30/dcn30_hwseq.c | 4 +- .../amd/display/dc/hwss/dcn31/dcn31_hwseq.c | 10 ++-- .../amd/display/dc/hwss/dcn32/dcn32_hwseq.c | 4 +- .../amd/display/dc/hwss/dcn35/dcn35_hwseq.c | 10 ++-- .../amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 4 +- .../gpu/drm/amd/display/dc/inc/core_types.h | 2 + drivers/gpu/drm/amd/display/dc/inc/hw/dio.h | 22 +++++++++ .../dc/resource/dcn401/dcn401_resource.c | 41 ++++++++++++++++ 13 files changed, 179 insertions(+), 18 deletions(-) create mode 100644 drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_dio.c create mode 100644 drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_dio.h create mode 100644 drivers/gpu/drm/amd/display/dc/inc/hw/dio.h diff --git a/drivers/gpu/drm/amd/display/dc/dio/Makefile b/drivers/gpu/drm/amd/display/dc/dio/Makefile index 0dfd480976f7..02eec03dc204 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dio/Makefile @@ -27,7 +27,7 @@ ifdef CONFIG_DRM_AMD_DC_FP ############################################################################### # DCN10 ############################################################################### -DIO_DCN10 = dcn10_link_encoder.o dcn10_stream_encoder.o +DIO_DCN10 = dcn10_link_encoder.o dcn10_stream_encoder.o dcn10_dio.o AMD_DAL_DIO_DCN10 = $(addprefix $(AMDDALPATH)/dc/dio/dcn10/,$(DIO_DCN10)) diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_dio.c b/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_dio.c new file mode 100644 index 000000000000..edcf4e67483b --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_dio.c @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: MIT +// +// Copyright 2025 Advanced Micro Devices, Inc. + +#include "dc_hw_types.h" +#include "dm_services.h" +#include "reg_helper.h" +#include "dcn10_dio.h" + +#define CTX \ + dio10->base.ctx +#define REG(reg)\ + dio10->regs->reg + +#undef FN +#define FN(reg_name, field_name) \ + dio10->shifts->field_name, dio10->masks->field_name + +static void dcn10_dio_mem_pwr_ctrl(struct dio *dio, bool enable_i2c_light_sleep) +{ + struct dcn10_dio *dio10 = TO_DCN10_DIO(dio); + + /* power AFMT HDMI memory */ + REG_WRITE(DIO_MEM_PWR_CTRL, 0); + + if (enable_i2c_light_sleep) + REG_UPDATE(DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, 1); +} + +static const struct dio_funcs dcn10_dio_funcs = { + .mem_pwr_ctrl = dcn10_dio_mem_pwr_ctrl, +}; + +void dcn10_dio_construct( + struct dcn10_dio *dio10, + struct dc_context *ctx, + const struct dcn_dio_registers *regs, + const struct dcn_dio_shift *shifts, + const struct dcn_dio_mask *masks) +{ + dio10->base.ctx = ctx; + dio10->base.funcs = &dcn10_dio_funcs; + + dio10->regs = regs; + dio10->shifts = shifts; + dio10->masks = masks; +} diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_dio.h b/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_dio.h new file mode 100644 index 000000000000..369c5996326e --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_dio.h @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT +// +// Copyright 2025 Advanced Micro Devices, Inc. + +#ifndef __DCN10_DIO_H__ +#define __DCN10_DIO_H__ + +#include "dio.h" + +#define TO_DCN10_DIO(dio_base) \ + container_of(dio_base, struct dcn10_dio, base) + +#define DIO_REG_LIST_DCN10()\ + SR(DIO_MEM_PWR_CTRL) + +struct dcn_dio_registers { + uint32_t DIO_MEM_PWR_CTRL; +}; + +struct dcn_dio_shift { + uint8_t I2C_LIGHT_SLEEP_FORCE; +}; + +struct dcn_dio_mask { + uint32_t I2C_LIGHT_SLEEP_FORCE; +}; + +struct dcn10_dio { + struct dio base; + const struct dcn_dio_registers *regs; + const struct dcn_dio_shift *shifts; + const struct dcn_dio_mask *masks; +}; + +void dcn10_dio_construct( + struct dcn10_dio *dio10, + struct dc_context *ctx, + const struct dcn_dio_registers *regs, + const struct dcn_dio_shift *shifts, + const struct dcn_dio_mask *masks); + +#endif /* __DCN10_DIO_H__ */ 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 f89b2f5a9bbd..5243177c1faa 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 @@ -50,6 +50,7 @@ #include "link_hwss.h" #include "dpcd_defs.h" #include "dsc.h" +#include "dio/dcn10/dcn10_dio.h" #include "dce/dmub_psr.h" #include "dc_dmub_srv.h" #include "dce/dmub_hw_lock_mgr.h" @@ -1881,7 +1882,8 @@ void dcn10_init_hw(struct dc *dc) /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ if (!is_optimized_init_done) - REG_WRITE(DIO_MEM_PWR_CTRL, 0); + if (dc->res_pool->dio && dc->res_pool->dio->funcs->mem_pwr_ctrl) + dc->res_pool->dio->funcs->mem_pwr_ctrl(dc->res_pool->dio, false); if (!dc->debug.disable_clock_gate) { /* enable all DCN clock gating */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.c index 7cd225a6cf6c..ce18d75fd991 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.c @@ -40,6 +40,8 @@ #include "clk_mgr.h" #include "reg_helper.h" #include "dcn10/dcn10_hubbub.h" +#include "dio/dcn10/dcn10_dio.h" + #define CTX \ hws->ctx @@ -360,7 +362,8 @@ void dcn201_init_hw(struct dc *dc) } /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ - REG_WRITE(DIO_MEM_PWR_CTRL, 0); + if (dc->res_pool->dio && dc->res_pool->dio->funcs->mem_pwr_ctrl) + dc->res_pool->dio->funcs->mem_pwr_ctrl(dc->res_pool->dio, false); if (!dc->debug.disable_clock_gate) { /* enable all DCN clock gating */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c index 3ff15ec9dc17..d58f2cf2615c 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c @@ -53,6 +53,7 @@ #include "dcn30/dcn30_resource.h" #include "link_service.h" #include "dc_state_priv.h" +#include "dio/dcn10/dcn10_dio.h" #define TO_DCN_DCCG(dccg)\ container_of(dccg, struct dcn_dccg, base) @@ -794,7 +795,8 @@ void dcn30_init_hw(struct dc *dc) } /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ - REG_WRITE(DIO_MEM_PWR_CTRL, 0); + if (dc->res_pool->dio && dc->res_pool->dio->funcs->mem_pwr_ctrl) + dc->res_pool->dio->funcs->mem_pwr_ctrl(dc->res_pool->dio, false); if (!dc->debug.disable_clock_gate) { /* enable all DCN clock gating */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c index 91a672a46289..db2f7cbb12ff 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c @@ -53,6 +53,7 @@ #include "dcn30/dcn30_vpg.h" #include "dce/dce_i2c_hw.h" #include "dce/dmub_abm_lcd.h" +#include "dio/dcn10/dcn10_dio.h" #define DC_LOGGER_INIT(logger) @@ -237,12 +238,9 @@ void dcn31_init_hw(struct dc *dc) abms[i]->funcs->abm_init(abms[i], backlight, user_level); } - /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ - REG_WRITE(DIO_MEM_PWR_CTRL, 0); - - // Set i2c to light sleep until engine is setup - if (dc->debug.enable_mem_low_power.bits.i2c) - REG_UPDATE(DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, 1); + /* Power on DIO memory (AFMT HDMI) and set I2C to light sleep */ + if (dc->res_pool->dio && dc->res_pool->dio->funcs->mem_pwr_ctrl) + dc->res_pool->dio->funcs->mem_pwr_ctrl(dc->res_pool->dio, dc->debug.enable_mem_low_power.bits.i2c); if (hws->funcs.setup_hpo_hw_control) hws->funcs.setup_hpo_hw_control(hws, false); diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c index 3f76fba7dccc..37300e12e645 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c @@ -52,6 +52,7 @@ #include "link_service.h" #include "../dcn20/dcn20_hwseq.h" #include "dc_state_priv.h" +#include "dio/dcn10/dcn10_dio.h" #define DC_LOGGER_INIT(logger) @@ -955,7 +956,8 @@ void dcn32_init_hw(struct dc *dc) } /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ - REG_WRITE(DIO_MEM_PWR_CTRL, 0); + if (dc->res_pool->dio && dc->res_pool->dio->funcs->mem_pwr_ctrl) + dc->res_pool->dio->funcs->mem_pwr_ctrl(dc->res_pool->dio, false); if (!dc->debug.disable_clock_gate) { /* enable all DCN clock gating */ 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 1c7263f9ef51..b5a4cefbd35f 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 @@ -53,6 +53,7 @@ #include "dcn30/dcn30_vpg.h" #include "dce/dce_i2c_hw.h" #include "dsc.h" +#include "dio/dcn10/dcn10_dio.h" #include "dcn20/dcn20_optc.h" #include "dcn30/dcn30_cm_common.h" #include "dcn31/dcn31_hwseq.h" @@ -272,12 +273,9 @@ void dcn35_init_hw(struct dc *dc) } } - /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ - REG_WRITE(DIO_MEM_PWR_CTRL, 0); - - // Set i2c to light sleep until engine is setup - if (dc->debug.enable_mem_low_power.bits.i2c) - REG_UPDATE(DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, 0); + /* Power on DIO memory (AFMT HDMI) and optionally disable I2C light sleep */ + if (dc->res_pool->dio && dc->res_pool->dio->funcs->mem_pwr_ctrl) + dc->res_pool->dio->funcs->mem_pwr_ctrl(dc->res_pool->dio, !dc->debug.enable_mem_low_power.bits.i2c); if (hws->funcs.setup_hpo_hw_control) hws->funcs.setup_hpo_hw_control(hws, false); 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 567ed207d7cd..9cda39d0ed95 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 @@ -39,6 +39,7 @@ #include "dc_state_priv.h" #include "link_enc_cfg.h" #include "../hw_sequencer.h" +#include "dio/dcn10/dcn10_dio.h" #define DC_LOGGER_INIT(logger) @@ -320,7 +321,8 @@ void dcn401_init_hw(struct dc *dc) } /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ - REG_WRITE(DIO_MEM_PWR_CTRL, 0); + if (dc->res_pool->dio && dc->res_pool->dio->funcs->mem_pwr_ctrl) + dc->res_pool->dio->funcs->mem_pwr_ctrl(dc->res_pool->dio, false); if (!dc->debug.disable_clock_gate) { /* enable all DCN clock gating */ diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h index 61d8ef759aca..43579b0e1482 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h @@ -35,6 +35,7 @@ #include "hubp.h" #include "mpc.h" #include "dwb.h" +#include "hw/dio.h" #include "mcif_wb.h" #include "panel_cntl.h" #include "dmub/inc/dmub_cmd.h" @@ -250,6 +251,7 @@ struct resource_pool { struct timing_generator *timing_generators[MAX_PIPES]; struct stream_encoder *stream_enc[MAX_PIPES * 2]; struct hubbub *hubbub; + struct dio *dio; struct mpc *mpc; struct pp_smu_funcs *pp_smu; struct dce_aux *engines[MAX_PIPES]; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dio.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dio.h new file mode 100644 index 000000000000..532bf54cf2c4 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dio.h @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT +// +// Copyright 2025 Advanced Micro Devices, Inc. + +#ifndef __DC_DIO_H__ +#define __DC_DIO_H__ + +#include "dc_types.h" + +struct dc_context; +struct dio; + +struct dio_funcs { + void (*mem_pwr_ctrl)(struct dio *dio, bool enable_i2c_light_sleep); +}; + +struct dio { + const struct dio_funcs *funcs; + struct dc_context *ctx; +}; + +#endif /* __DC_DIO_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c index 1cdbb65da4a3..df3acf589582 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c @@ -21,6 +21,7 @@ #include "dcn401/dcn401_hubbub.h" #include "dcn401/dcn401_mpc.h" #include "dcn401/dcn401_hubp.h" +#include "dio/dcn10/dcn10_dio.h" #include "irq/dcn401/irq_service_dcn401.h" #include "dcn401/dcn401_dpp.h" #include "dcn401/dcn401_optc.h" @@ -634,6 +635,22 @@ static const struct dcn20_vmid_mask vmid_masks = { DCN20_VMID_MASK_SH_LIST(_MASK) }; +#define dio_regs_init() \ + DIO_REG_LIST_DCN10() + +static struct dcn_dio_registers dio_regs; + +#define DIO_MASK_SH_LIST_DCN401(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST_DCN401(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST_DCN401(_MASK) +}; + static const struct resource_caps res_cap_dcn4_01 = { .num_timing_generator = 4, .num_opp = 4, @@ -881,6 +898,22 @@ static struct hubbub *dcn401_hubbub_create(struct dc_context *ctx) return &hubbub2->base; } +static struct dio *dcn401_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc(sizeof(struct dcn10_dio), GFP_KERNEL); + + if (!dio10) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT dio_regs + dio_regs_init(); + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct hubp *dcn401_hubp_create( struct dc_context *ctx, uint32_t inst) @@ -2071,6 +2104,14 @@ static bool dcn401_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn401_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + /* HUBPs, DPPs, OPPs, TGs, ABMs */ for (i = 0, j = 0; i < pool->base.res_cap->num_timing_generator; i++) { From 0b39cb143d214fac7e30696ac1c53fad563fbb1a Mon Sep 17 00:00:00 2001 From: Zheng Austin Date: Mon, 19 Jan 2026 17:46:39 -0500 Subject: [PATCH 16/51] drm/amd/display: Match expected data types [Why/How] Data types should match what is expected. Update/cast data accordingly. Also change ASSERT to use DML_ASSERT instead Reviewed-by: Dillon Varone Signed-off-by: Zheng Austin Signed-off-by: Wayne Lin Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../src/dml2_core/dml2_core_dcn4_calcs.c | 4 +-- .../dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c | 34 +++++++++---------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c index 37699cc9e5c1..ca5ac3c0deb5 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c @@ -7080,7 +7080,7 @@ static void calculate_excess_vactive_bandwidth_required( static double uclk_khz_to_dram_bw_mbps(unsigned long uclk_khz, const struct dml2_dram_params *dram_config, const struct dml2_mcg_dram_bw_to_min_clk_table *dram_bw_table) { double bw_mbps = 0; - int i; + unsigned int i; if (!dram_config->alt_clock_bw_conversion) bw_mbps = ((double)uclk_khz * dram_config->channel_count * dram_config->channel_width_bytes * dram_config->transactions_per_clock) / 1000.0; @@ -7091,7 +7091,7 @@ static double uclk_khz_to_dram_bw_mbps(unsigned long uclk_khz, const struct dml2 break; } - ASSERT(bw_mbps > 0); + DML_ASSERT(bw_mbps > 0); return bw_mbps; } diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c index 5c713f2e6eca..9d7741fd0adb 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c @@ -17,7 +17,7 @@ static double dram_bw_kbps_to_uclk_khz(unsigned long long bandwidth_kbps, const uclk_bytes_per_tick = dram_config->channel_count * dram_config->channel_width_bytes * dram_config->transactions_per_clock; uclk_khz = (double)bandwidth_kbps / uclk_bytes_per_tick; } else { - int i; + unsigned int i; /* For lpddr5 bytes per tick changes with mpstate, use table to find uclk*/ for (i = 0; i < dram_bw_table->num_entries; i++) if (dram_bw_table->entries[i].pre_derate_dram_bw_kbps >= bandwidth_kbps) { @@ -63,17 +63,17 @@ static void calculate_system_active_minimums(struct dml2_dpmm_map_mode_to_soc_dp double min_uclk_latency, min_fclk_latency, min_dcfclk_latency; const struct dml2_core_mode_support_result *mode_support_result = &in_out->display_cfg->mode_support_result; - min_uclk_avg = dram_bw_kbps_to_uclk_khz(mode_support_result->global.active.average_bw_dram_kbps - / ((double)in_out->soc_bb->qos_parameters.derate_table.system_active_average.dram_derate_percent_pixel / 100), + min_uclk_avg = dram_bw_kbps_to_uclk_khz((unsigned long long)(mode_support_result->global.active.average_bw_dram_kbps + / ((double)in_out->soc_bb->qos_parameters.derate_table.system_active_average.dram_derate_percent_pixel / 100)), &in_out->soc_bb->clk_table.dram_config, &in_out->min_clk_table->dram_bw_table); if (in_out->display_cfg->display_config.hostvm_enable) - min_uclk_urgent = dram_bw_kbps_to_uclk_khz(mode_support_result->global.active.urgent_bw_dram_kbps - / ((double)in_out->soc_bb->qos_parameters.derate_table.system_active_urgent.dram_derate_percent_pixel_and_vm / 100), + min_uclk_urgent = dram_bw_kbps_to_uclk_khz((unsigned long long)(mode_support_result->global.active.urgent_bw_dram_kbps + / ((double)in_out->soc_bb->qos_parameters.derate_table.system_active_urgent.dram_derate_percent_pixel_and_vm / 100)), &in_out->soc_bb->clk_table.dram_config, &in_out->min_clk_table->dram_bw_table); else - min_uclk_urgent = dram_bw_kbps_to_uclk_khz(mode_support_result->global.active.urgent_bw_dram_kbps - / ((double)in_out->soc_bb->qos_parameters.derate_table.system_active_urgent.dram_derate_percent_pixel / 100), + min_uclk_urgent = dram_bw_kbps_to_uclk_khz((unsigned long long)(mode_support_result->global.active.urgent_bw_dram_kbps + / ((double)in_out->soc_bb->qos_parameters.derate_table.system_active_urgent.dram_derate_percent_pixel / 100)), &in_out->soc_bb->clk_table.dram_config, &in_out->min_clk_table->dram_bw_table); min_uclk_bw = min_uclk_urgent > min_uclk_avg ? min_uclk_urgent : min_uclk_avg; @@ -111,12 +111,12 @@ static void calculate_svp_prefetch_minimums(struct dml2_dpmm_map_mode_to_soc_dpm const struct dml2_core_mode_support_result *mode_support_result = &in_out->display_cfg->mode_support_result; /* assumes DF throttling is enabled */ - min_uclk_avg = dram_bw_kbps_to_uclk_khz(mode_support_result->global.svp_prefetch.average_bw_dram_kbps - / ((double)in_out->soc_bb->qos_parameters.derate_table.dcn_mall_prefetch_average.dram_derate_percent_pixel / 100), + min_uclk_avg = dram_bw_kbps_to_uclk_khz((unsigned long long)(mode_support_result->global.svp_prefetch.average_bw_dram_kbps + / ((double)in_out->soc_bb->qos_parameters.derate_table.dcn_mall_prefetch_average.dram_derate_percent_pixel / 100)), &in_out->soc_bb->clk_table.dram_config, &in_out->min_clk_table->dram_bw_table); - min_uclk_urgent = dram_bw_kbps_to_uclk_khz(mode_support_result->global.svp_prefetch.urgent_bw_dram_kbps - / ((double)in_out->soc_bb->qos_parameters.derate_table.dcn_mall_prefetch_urgent.dram_derate_percent_pixel / 100), + min_uclk_urgent = dram_bw_kbps_to_uclk_khz((unsigned long long)(mode_support_result->global.svp_prefetch.urgent_bw_dram_kbps + / ((double)in_out->soc_bb->qos_parameters.derate_table.dcn_mall_prefetch_urgent.dram_derate_percent_pixel / 100)), &in_out->soc_bb->clk_table.dram_config, &in_out->min_clk_table->dram_bw_table); min_uclk_bw = min_uclk_urgent > min_uclk_avg ? min_uclk_urgent : min_uclk_avg; @@ -144,12 +144,12 @@ static void calculate_svp_prefetch_minimums(struct dml2_dpmm_map_mode_to_soc_dpm in_out->programming->min_clocks.dcn4x.svp_prefetch.dcfclk_khz = dml_round_up(min_dcfclk_bw > min_dcfclk_latency ? min_dcfclk_bw : min_dcfclk_latency); /* assumes DF throttling is disabled */ - min_uclk_avg = dram_bw_kbps_to_uclk_khz(mode_support_result->global.svp_prefetch.average_bw_dram_kbps - / ((double)in_out->soc_bb->qos_parameters.derate_table.system_active_average.dram_derate_percent_pixel / 100), + min_uclk_avg = dram_bw_kbps_to_uclk_khz((unsigned long long)(mode_support_result->global.svp_prefetch.average_bw_dram_kbps + / ((double)in_out->soc_bb->qos_parameters.derate_table.system_active_average.dram_derate_percent_pixel / 100)), &in_out->soc_bb->clk_table.dram_config, &in_out->min_clk_table->dram_bw_table); - min_uclk_urgent = dram_bw_kbps_to_uclk_khz(mode_support_result->global.svp_prefetch.urgent_bw_dram_kbps - / ((double)in_out->soc_bb->qos_parameters.derate_table.system_active_urgent.dram_derate_percent_pixel / 100), + min_uclk_urgent = dram_bw_kbps_to_uclk_khz((unsigned long long)(mode_support_result->global.svp_prefetch.urgent_bw_dram_kbps + / ((double)in_out->soc_bb->qos_parameters.derate_table.system_active_urgent.dram_derate_percent_pixel / 100)), &in_out->soc_bb->clk_table.dram_config, &in_out->min_clk_table->dram_bw_table); min_uclk_bw = min_uclk_urgent > min_uclk_avg ? min_uclk_urgent : min_uclk_avg; @@ -185,8 +185,8 @@ static void calculate_idle_minimums(struct dml2_dpmm_map_mode_to_soc_dpm_params_ double min_uclk_latency, min_fclk_latency, min_dcfclk_latency; const struct dml2_core_mode_support_result *mode_support_result = &in_out->display_cfg->mode_support_result; - min_uclk_avg = dram_bw_kbps_to_uclk_khz(mode_support_result->global.active.average_bw_dram_kbps - / ((double)in_out->soc_bb->qos_parameters.derate_table.system_idle_average.dram_derate_percent_pixel / 100), + min_uclk_avg = dram_bw_kbps_to_uclk_khz((unsigned long long)(mode_support_result->global.active.average_bw_dram_kbps + / ((double)in_out->soc_bb->qos_parameters.derate_table.system_idle_average.dram_derate_percent_pixel / 100)), &in_out->soc_bb->clk_table.dram_config, &in_out->min_clk_table->dram_bw_table); min_fclk_avg = (double)mode_support_result->global.active.average_bw_sdp_kbps / in_out->soc_bb->fabric_datapath_to_dcn_data_return_bytes; From 1a77ecec8b35258c45b6963698e5dc378c67ef32 Mon Sep 17 00:00:00 2001 From: Chenyu Chen Date: Thu, 22 Jan 2026 17:19:07 +0800 Subject: [PATCH 17/51] drm/amd/display: Add CRC 32-bit mode support for DCN3.6+ [Why] DCN 3.6+ hardware supports CRC-32 polynomial in addition to the legacy CRC-16. Enable 32-bit CRC values per color component for improvement of precision in display validation. [How] When userspace sets crc_poly_mode (0=CRC-16, 1=CRC-32) via the debugfs interface, the value is stored in dm_irq_params.crc_poly_mode. When CRC source configuration triggers amdgpu_dm_crtc_configure_crc_source(), crc_poly_mode is retrieved from dm_irq_params and passed to dc_stream_configure_crc(). In the DC layer, dc_stream_configure_crc() sets crc_poly_mode into the crc_params structure and passes it to optc35_configure_crc(). If the hardware supports the OTG_CRC_POLY_SEL register, the register is programmed to select CRC-16 or CRC-32 polynomial. When reading CRC values, optc35_get_crc() checks whether CRC32 register masks are available. If present, it reads 32-bit CRC values from OTG_CRC0/1_DATA_R32/G32/B32 registers; otherwise, it falls back to reading 16-bit CRC values from legacy OTG_CRC0/1_DATA_RG/B registers. Reviewed-by: ChiaHsuan Chung Signed-off-by: Chenyu Chen Signed-off-by: Wayne Lin Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c | 15 ++- .../amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 46 +++++++++ .../display/amdgpu_dm/amdgpu_dm_irq_params.h | 1 + drivers/gpu/drm/amd/display/dc/core/dc.c | 4 +- drivers/gpu/drm/amd/display/dc/dc_stream.h | 3 +- .../amd/display/dc/inc/hw/timing_generator.h | 7 ++ .../amd/display/dc/optc/dcn10/dcn10_optc.h | 19 +++- .../amd/display/dc/optc/dcn35/dcn35_optc.c | 96 ++++++++++++++++++- .../amd/display/dc/optc/dcn35/dcn35_optc.h | 10 ++ .../dc/resource/dcn36/dcn36_resource.c | 12 ++- 10 files changed, 203 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c index 5851f2d55dde..1b03f2bf8d7a 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 @@ -506,6 +506,7 @@ int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc, struct amdgpu_dm_connector *aconnector = NULL; bool enable = amdgpu_dm_is_valid_crc_source(source); int ret = 0; + enum crc_poly_mode crc_poly_mode = CRC_POLY_MODE_16; /* Configuration will be deferred to stream enable. */ if (!stream_state) @@ -528,10 +529,18 @@ int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc, amdgpu_dm_replay_disable(stream_state); } + /* CRC polynomial selection only support for DCN3.6+ except DCN4.0.1 */ + if ((amdgpu_ip_version(adev, DCE_HWIP, 0) >= IP_VERSION(3, 6, 0)) && + (amdgpu_ip_version(adev, DCE_HWIP, 0) != IP_VERSION(4, 0, 1))) { + struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); + + crc_poly_mode = acrtc->dm_irq_params.crc_poly_mode; + } + /* Enable or disable CRTC CRC generation */ if (dm_is_crc_source_crtc(source) || source == AMDGPU_DM_PIPE_CRC_SOURCE_NONE) { if (!dc_stream_configure_crc(stream_state->ctx->dc, - stream_state, NULL, enable, enable, 0, true)) { + stream_state, NULL, enable, enable, 0, true, crc_poly_mode)) { ret = -EINVAL; goto unlock; } @@ -877,7 +886,7 @@ void amdgpu_dm_crtc_handle_crc_window_irq(struct drm_crtc *crtc) else if (adev->dm.secure_display_ctx.op_mode == DISPLAY_CRC_MODE) /* update ROI via dm*/ dc_stream_configure_crc(stream_state->ctx->dc, stream_state, - &crc_window, true, true, i, false); + &crc_window, true, true, i, false, (enum crc_poly_mode)acrtc->dm_irq_params.crc_poly_mode); reset_crc_frame_count[i] = true; @@ -901,7 +910,7 @@ void amdgpu_dm_crtc_handle_crc_window_irq(struct drm_crtc *crtc) else if (adev->dm.secure_display_ctx.op_mode == DISPLAY_CRC_MODE) /* Avoid ROI window get changed, keep overwriting. */ dc_stream_configure_crc(stream_state->ctx->dc, stream_state, - &crc_window, true, true, i, false); + &crc_window, true, true, i, false, (enum crc_poly_mode)acrtc->dm_irq_params.crc_poly_mode); /* crc ready for psp to read out */ crtc_ctx->crc_info.crc[i].crc_ready = true; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index cfe35442dfcb..d6d43f1bf6d2 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -3839,6 +3839,50 @@ static int crc_win_update_get(void *data, u64 *val) DEFINE_DEBUGFS_ATTRIBUTE(crc_win_update_fops, crc_win_update_get, crc_win_update_set, "%llu\n"); + +/* + * Trigger to set crc polynomial mode + * 0: 16-bit CRC, 1: 32-bit CRC + * only accepts 0 or 1 for supported hwip versions + */ +static int crc_poly_mode_set(void *data, u64 val) +{ + struct drm_crtc *crtc = data; + struct amdgpu_crtc *acrtc; + struct amdgpu_device *adev = drm_to_adev(crtc->dev); + + if ((amdgpu_ip_version(adev, DCE_HWIP, 0) >= IP_VERSION(3, 6, 0)) && + (amdgpu_ip_version(adev, DCE_HWIP, 0) != IP_VERSION(4, 0, 1)) && + (val < 2)) { + acrtc = to_amdgpu_crtc(crtc); + mutex_lock(&adev->dm.dc_lock); + spin_lock_irq(&adev_to_drm(adev)->event_lock); + acrtc->dm_irq_params.crc_poly_mode = val; + spin_unlock_irq(&adev_to_drm(adev)->event_lock); + mutex_unlock(&adev->dm.dc_lock); + } + + return 0; +} + +/* + * Get crc polynomial mode (0: 16-bit CRC, 1: 32-bit CRC) + */ +static int crc_poly_mode_get(void *data, u64 *val) +{ + struct drm_crtc *crtc = data; + struct drm_device *drm_dev = crtc->dev; + struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); + + spin_lock_irq(&drm_dev->event_lock); + *val = acrtc->dm_irq_params.crc_poly_mode; + spin_unlock_irq(&drm_dev->event_lock); + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(crc_poly_mode_fops, crc_poly_mode_get, + crc_poly_mode_set, "%llu\n"); #endif void crtc_debugfs_init(struct drm_crtc *crtc) { @@ -3858,6 +3902,8 @@ void crtc_debugfs_init(struct drm_crtc *crtc) &crc_win_y_end_fops); debugfs_create_file_unsafe("crc_win_update", 0644, dir, crtc, &crc_win_update_fops); + debugfs_create_file_unsafe("crc_poly_mode", 0644, dir, crtc, + &crc_poly_mode_fops); dput(dir); #endif debugfs_create_file("amdgpu_current_bpc", 0644, crtc->debugfs_entry, diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq_params.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq_params.h index 3c9995275cbd..f0c1b0c1faa9 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq_params.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq_params.h @@ -39,6 +39,7 @@ struct dm_irq_params { #ifdef CONFIG_DEBUG_FS enum amdgpu_dm_pipe_crc_source crc_src; + int crc_poly_mode; /* enum crc_poly_mode from timing_generator.h */ #ifdef CONFIG_DRM_AMD_SECURE_DISPLAY struct crc_window_param window_param[MAX_CRC_WINDOW_NUM]; /* At least one CRC window is activated or not*/ diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 441b7e0a3b22..e7d2b861dedd 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -701,6 +701,7 @@ dc_stream_forward_multiple_crc_window(struct dc_stream_state *stream, * once. * @idx: Capture CRC on which CRC engine instance * @reset: Reset CRC engine before the configuration + * @crc_poly_mode: CRC polynomial mode * * By default, the entire frame is used to calculate the CRC. * @@ -709,7 +710,7 @@ dc_stream_forward_multiple_crc_window(struct dc_stream_state *stream, */ bool dc_stream_configure_crc(struct dc *dc, struct dc_stream_state *stream, struct crc_params *crc_window, bool enable, bool continuous, - uint8_t idx, bool reset) + uint8_t idx, bool reset, enum crc_poly_mode crc_poly_mode) { struct pipe_ctx *pipe; struct crc_params param; @@ -733,6 +734,7 @@ bool dc_stream_configure_crc(struct dc *dc, struct dc_stream_state *stream, param.windowb_y_start = 0; param.windowb_x_end = pipe->stream->timing.h_addressable; param.windowb_y_end = pipe->stream->timing.v_addressable; + param.crc_poly_mode = crc_poly_mode; if (crc_window) { param.windowa_x_start = crc_window->windowa_x_start; diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index 719b98d8e8ca..9960494007ff 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -584,7 +584,8 @@ bool dc_stream_configure_crc(struct dc *dc, bool enable, bool continuous, uint8_t idx, - bool reset); + bool reset, + enum crc_poly_mode crc_poly_mode); bool dc_stream_get_crc(struct dc *dc, struct dc_stream_state *stream, diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h index da7bf59c4b9d..671ab1fc7320 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h @@ -122,6 +122,12 @@ enum timing_synchronization_type { VBLANK_SYNCHRONIZABLE }; +enum crc_poly_mode { + CRC_POLY_MODE_16, + CRC_POLY_MODE_32, + CRC_POLY_MODE_MAX, +}; + struct crc_params { /* Regions used to calculate CRC*/ uint16_t windowa_x_start; @@ -144,6 +150,7 @@ struct crc_params { uint8_t crc_eng_inst; bool reset; + enum crc_poly_mode crc_poly_mode; }; struct dcn_otg_state { diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.h b/drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.h index 803bcc25601c..0b3f974f452e 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.h +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.h @@ -244,7 +244,13 @@ uint32_t OTG_TRIGB_MANUAL_TRIG; \ uint32_t OTG_UPDATE_LOCK; \ uint32_t OTG_V_TOTAL_INT_STATUS; \ - uint32_t OTG_VSYNC_NOM_INT_STATUS + uint32_t OTG_VSYNC_NOM_INT_STATUS; \ + uint32_t OTG_CRC0_DATA_R32; \ + uint32_t OTG_CRC0_DATA_G32; \ + uint32_t OTG_CRC0_DATA_B32; \ + uint32_t OTG_CRC1_DATA_R32; \ + uint32_t OTG_CRC1_DATA_G32; \ + uint32_t OTG_CRC1_DATA_B32 struct dcn_optc_registers { @@ -657,6 +663,15 @@ struct dcn_optc_registers { type OTG_V_COUNT_STOP;\ type OTG_V_COUNT_STOP_TIMER; +#define TG_REG_FIELD_LIST_DCN3_6(type) \ + type OTG_CRC_POLY_SEL; \ + type CRC0_R_CR32; \ + type CRC0_G_Y32; \ + type CRC0_B_CB32; \ + type CRC1_R_CR32; \ + type CRC1_G_Y32; \ + type CRC1_B_CB32; + #define TG_REG_FIELD_LIST_DCN401(type) \ type OPTC_SEGMENT_WIDTH_LAST;\ type OTG_PSTATE_KEEPOUT_START;\ @@ -670,6 +685,7 @@ struct dcn_optc_shift { TG_REG_FIELD_LIST_DCN2_0(uint8_t) TG_REG_FIELD_LIST_DCN3_2(uint8_t) TG_REG_FIELD_LIST_DCN3_5(uint8_t) + TG_REG_FIELD_LIST_DCN3_6(uint8_t) TG_REG_FIELD_LIST_DCN401(uint8_t) }; @@ -678,6 +694,7 @@ struct dcn_optc_mask { TG_REG_FIELD_LIST_DCN2_0(uint32_t) TG_REG_FIELD_LIST_DCN3_2(uint32_t) TG_REG_FIELD_LIST_DCN3_5(uint32_t) + TG_REG_FIELD_LIST_DCN3_6(uint32_t) TG_REG_FIELD_LIST_DCN401(uint32_t) }; diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c index f699e95059f3..0953acbcc6d4 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c @@ -180,6 +180,96 @@ static void optc35_phantom_crtc_post_enable(struct timing_generator *optc) REG_WAIT(OTG_CLOCK_CONTROL, OTG_BUSY, 0, 1, 100000); } +/** + * optc35_get_crc - Capture CRC result per component + * + * @optc: timing_generator instance. + * @idx: index of crc engine to get CRC from + * @r_cr: primary CRC signature for red data. + * @g_y: primary CRC signature for green data. + * @b_cb: primary CRC signature for blue data. + * + * This function reads the CRC signature from the OPTC registers. Notice that + * we have three registers to keep the CRC result per color component (RGB). + * + * For different DCN versions: + * - If CRC32 registers (OTG_CRC0_DATA_R32/G32/B32) are available, read from + * 32-bit CRC registers. DCN 3.6+ supports both CRC-32 and CRC-16 polynomials + * selectable via OTG_CRC_POLY_SEL. + * - Otherwise, read from legacy 16-bit CRC registers (OTG_CRC0_DATA_RG/B) + * which only support CRC-16 polynomial. + * + * Returns: + * If CRC is disabled, return false; otherwise, return true, and the CRC + * results in the parameters. + */ +static bool optc35_get_crc(struct timing_generator *optc, uint8_t idx, + uint32_t *r_cr, uint32_t *g_y, uint32_t *b_cb) +{ + uint32_t field = 0; + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_GET(OTG_CRC_CNTL, OTG_CRC_EN, &field); + + /* Early return if CRC is not enabled for this CRTC */ + if (!field) + return false; + + if (optc1->tg_mask->CRC0_R_CR32 != 0 && optc1->tg_mask->CRC1_R_CR32 != 0 && + optc1->tg_mask->CRC0_G_Y32 != 0 && optc1->tg_mask->CRC1_G_Y32 != 0 && + optc1->tg_mask->CRC0_B_CB32 != 0 && optc1->tg_mask->CRC1_B_CB32 != 0) { + switch (idx) { + case 0: + /* OTG_CRC0_DATA_R32/G32/B32 has the CRC32 results */ + REG_GET(OTG_CRC0_DATA_R32, + CRC0_R_CR32, r_cr); + REG_GET(OTG_CRC0_DATA_G32, + CRC0_G_Y32, g_y); + REG_GET(OTG_CRC0_DATA_B32, + CRC0_B_CB32, b_cb); + break; + case 1: + /* OTG_CRC1_DATA_R32/G32/B32 has the CRC32 results */ + REG_GET(OTG_CRC1_DATA_R32, + CRC1_R_CR32, r_cr); + REG_GET(OTG_CRC1_DATA_G32, + CRC1_G_Y32, g_y); + REG_GET(OTG_CRC1_DATA_B32, + CRC1_B_CB32, b_cb); + break; + default: + return false; + } + } else { + switch (idx) { + case 0: + /* OTG_CRC0_DATA_RG has the CRC16 results for the red and green component */ + REG_GET_2(OTG_CRC0_DATA_RG, + CRC0_R_CR, r_cr, + CRC0_G_Y, g_y); + + /* OTG_CRC0_DATA_B has the CRC16 results for the blue component */ + REG_GET(OTG_CRC0_DATA_B, + CRC0_B_CB, b_cb); + break; + case 1: + /* OTG_CRC1_DATA_RG has the CRC16 results for the red and green component */ + REG_GET_2(OTG_CRC1_DATA_RG, + CRC1_R_CR, r_cr, + CRC1_G_Y, g_y); + + /* OTG_CRC1_DATA_B has the CRC16 results for the blue component */ + REG_GET(OTG_CRC1_DATA_B, + CRC1_B_CB, b_cb); + break; + default: + return false; + } + } + + return true; +} + static bool optc35_configure_crc(struct timing_generator *optc, const struct crc_params *params) { @@ -266,6 +356,10 @@ static bool optc35_configure_crc(struct timing_generator *optc, default: return false; } + if (optc1->tg_mask->OTG_CRC_POLY_SEL != 0) { + REG_UPDATE(OTG_CRC_CNTL, + OTG_CRC_POLY_SEL, params->crc_poly_mode); + } return true; } @@ -488,7 +582,7 @@ static const struct timing_generator_funcs dcn35_tg_funcs = { .is_optc_underflow_occurred = optc1_is_optc_underflow_occurred, .clear_optc_underflow = optc1_clear_optc_underflow, .setup_global_swap_lock = NULL, - .get_crc = optc1_get_crc, + .get_crc = optc35_get_crc, .configure_crc = optc35_configure_crc, .set_dsc_config = optc3_set_dsc_config, .get_dsc_status = optc2_get_dsc_status, diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.h b/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.h index 733a2f149d9a..5c2cb1f27783 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.h +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.h @@ -74,6 +74,16 @@ SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_VUPDATE_KEEPOUT_STATUS, mask_sh),\ SF(OTG0_INTERRUPT_DEST, OTG0_IHC_OTG_VERTICAL_INTERRUPT2_DEST, mask_sh) +#define OPTC_COMMON_MASK_SH_LIST_DCN3_6(mask_sh)\ + OPTC_COMMON_MASK_SH_LIST_DCN3_5(mask_sh),\ + SF(OTG0_OTG_CRC_CNTL, OTG_CRC_POLY_SEL, mask_sh),\ + SF(OTG_CRC320_OTG_CRC0_DATA_R32, CRC0_R_CR32, mask_sh),\ + SF(OTG_CRC320_OTG_CRC0_DATA_G32, CRC0_G_Y32, mask_sh),\ + SF(OTG_CRC320_OTG_CRC0_DATA_B32, CRC0_B_CB32, mask_sh),\ + SF(OTG_CRC320_OTG_CRC1_DATA_R32, CRC1_R_CR32, mask_sh),\ + SF(OTG_CRC320_OTG_CRC1_DATA_G32, CRC1_G_Y32, mask_sh),\ + SF(OTG_CRC320_OTG_CRC1_DATA_B32, CRC1_B_CB32, mask_sh) + void dcn35_timing_generator_init(struct optc *optc1); void dcn35_timing_generator_set_fgcg(struct optc *optc1, bool enable); diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn36/dcn36_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn36/dcn36_resource.c index 6469d5fe2e6d..0ee16926db4e 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn36/dcn36_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn36/dcn36_resource.c @@ -460,16 +460,22 @@ static const struct dcn30_mpc_mask mpc_mask = { }; #define optc_regs_init(id)\ - OPTC_COMMON_REG_LIST_DCN3_5_RI(id) + OPTC_COMMON_REG_LIST_DCN3_5_RI(id),\ + SRI_ARR(OTG_CRC0_DATA_R32, OTG_CRC32, id),\ + SRI_ARR(OTG_CRC0_DATA_G32, OTG_CRC32, id),\ + SRI_ARR(OTG_CRC0_DATA_B32, OTG_CRC32, id),\ + SRI_ARR(OTG_CRC1_DATA_R32, OTG_CRC32, id),\ + SRI_ARR(OTG_CRC1_DATA_G32, OTG_CRC32, id),\ + SRI_ARR(OTG_CRC1_DATA_B32, OTG_CRC32, id) static struct dcn_optc_registers optc_regs[4]; static const struct dcn_optc_shift optc_shift = { - OPTC_COMMON_MASK_SH_LIST_DCN3_5(__SHIFT) + OPTC_COMMON_MASK_SH_LIST_DCN3_6(__SHIFT) }; static const struct dcn_optc_mask optc_mask = { - OPTC_COMMON_MASK_SH_LIST_DCN3_5(_MASK) + OPTC_COMMON_MASK_SH_LIST_DCN3_6(_MASK) }; #define hubp_regs_init(id)\ From 1e5a335e2436a263cdc5c27ea7bbb0aa8137346a Mon Sep 17 00:00:00 2001 From: Fangzhi Zuo Date: Wed, 21 Jan 2026 14:24:37 -0500 Subject: [PATCH 18/51] drm/amd/display: Init DMUB DPIA Only for APU [why & how] 1. There is no need to init dpia in dgpu 2. Add additional dpia flags a. dpia hpd dynamic control b. consolidated dpia link training to dp c. dynamic bw allocation support Reviewed-by: Roman Li Signed-off-by: Fangzhi Zuo Signed-off-by: Wayne Lin Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 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 ca40166ca924..631b44fd6dae 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1244,6 +1244,7 @@ static int dm_dmub_hw_init(struct amdgpu_device *adev) struct dmub_srv *dmub_srv = adev->dm.dmub_srv; struct dmub_srv_fb_info *fb_info = adev->dm.dmub_fb_info; const struct firmware *dmub_fw = adev->dm.dmub_fw; + struct dc *dc = adev->dm.dc; struct dmcu *dmcu = adev->dm.dc->res_pool->dmcu; struct abm *abm = adev->dm.dc->res_pool->abm; struct dc_context *ctx = adev->dm.dc->ctx; @@ -1349,18 +1350,15 @@ static int dm_dmub_hw_init(struct amdgpu_device *adev) for (i = 0; i < fb_info->num_fb; ++i) hw_params.fb[i] = &fb_info->fb[i]; - switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) { - case IP_VERSION(3, 1, 3): - case IP_VERSION(3, 1, 4): - case IP_VERSION(3, 5, 0): - case IP_VERSION(3, 5, 1): - case IP_VERSION(3, 6, 0): - case IP_VERSION(4, 0, 1): + /* Enable usb4 dpia in the FW APU */ + if (dc->caps.is_apu && + dc->res_pool->usb4_dpia_count != 0 && + !dc->debug.dpia_debug.bits.disable_dpia) { hw_params.dpia_supported = true; - hw_params.disable_dpia = adev->dm.dc->debug.dpia_debug.bits.disable_dpia; - break; - default: - break; + hw_params.disable_dpia = dc->debug.dpia_debug.bits.disable_dpia; + hw_params.dpia_hpd_int_enable_supported = false; + hw_params.enable_non_transparent_setconfig = dc->config.consolidated_dpia_dp_lt; + hw_params.disable_dpia_bw_allocation = !dc->config.usb4_bw_alloc_support; } switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) { From 22bd5f691665b3d427d21db077698d580a5e5266 Mon Sep 17 00:00:00 2001 From: Bhuvanachandra Pinninti Date: Fri, 23 Jan 2026 16:13:01 +0530 Subject: [PATCH 19/51] drm/amd/display: DIO memory leak fix. [why] Allocated memory for dcn10_dio but not freed in dcn401_resource. [how] Add kfree for it in dcn401_resource. Reviewed-by: Aric Cyr Signed-off-by: Bhuvanachandra Pinninti Signed-off-by: Wayne Lin Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c index df3acf589582..4875faffe873 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c @@ -1532,6 +1532,11 @@ static void dcn401_resource_destruct(struct dcn401_resource_pool *pool) if (pool->base.dccg != NULL) dcn_dccg_destroy(&pool->base.dccg); + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } + if (pool->base.oem_device != NULL) { struct dc *dc = pool->base.oem_device->ctx->dc; From 2e193f5b1b4f638b47a177a6b4686cbb5cf75065 Mon Sep 17 00:00:00 2001 From: Nicholas Carbones Date: Wed, 7 Jan 2026 09:42:27 -0500 Subject: [PATCH 20/51] drm/amd/display: Add Handling for gfxversion DcGfxBase [Why] There is no way to set tiling in dml in the case that gfxversion is DcGfxBase. [How] Where tiling is updated based on Gfx, add case for DcGfxBase and set tiling to dml2_sw_linear. Reviewed-by: Dillon Varone Signed-off-by: Nicholas Carbones Signed-off-by: Wayne Lin Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.c index bf5e7f4e0416..3f4963ce3a00 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.c @@ -460,6 +460,9 @@ static void populate_dml21_surface_config_from_plane_state( case DcGfxAddr3: surface->tiling = gfx_addr3_to_dml2_swizzle_mode(plane_state->tiling_info.gfx_addr3.swizzle); break; + case DcGfxBase: + surface->tiling = dml2_sw_linear; + break; } } From 7c1ed3dc6769119e55473650cebacdb0ad8d0edb Mon Sep 17 00:00:00 2001 From: Taimur Hassan Date: Fri, 23 Jan 2026 17:13:14 -0500 Subject: [PATCH 21/51] drm/amd/display: [FW Promotion] Release 0.1.45.0 Add new enum definition for panel replay ml activity options. Acked-by: ChiaHsuan Chung Signed-off-by: Taimur Hassan Signed-off-by: Wayne Lin Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index 18e0bdfd6ff4..3b4f5e990ec5 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -736,6 +736,16 @@ union pr_hw_flags { uint32_t u32All; }; +/** + * Definition of Panel Replay ML Activity Options + */ +enum pr_ml_activity_option { + OPTION_DEFAULT = 0x00, // VESA Option Default (1C) + OPTION_1A = 0x01, // VESA Option 1A + OPTION_1B = 0x02, // VESA Option 1B + OPTION_1C = 0x03, // VESA Option 1C +}; + union fw_assisted_mclk_switch_version { struct { uint8_t minor : 5; From 4a0f94dfef34745a380a93b3a764d82e0ff840f4 Mon Sep 17 00:00:00 2001 From: Taimur Hassan Date: Fri, 23 Jan 2026 22:39:10 -0500 Subject: [PATCH 22/51] drm/amd/display: Promote DC to 3.2.368 This version brings along following fixes: - Migrate DCCG register access from hwseq to dccg component. - Add lpddr5 handling to dml2.1 - Correct external pr fsm control - Make DCN35 OTG disable w/a reusable - Make DSC FGCG a DSC block level function - Make some DCN35 DCCG symbols reusable - Fix writeback on DCN 3.2+ - Fix IGT link training failure on Replay panel - Fix system resume lag issue - Add oem panel config for new features - Fix IGT ILR link training failure on Replay panel - Fix a NULL pointer dereference in dcn20_hwseq.c - Add Gfx Base Case For Linear Tiling Handling - Migrate DIO registers access from hwseq to dio component. - Match expected data types - Add CRC 32-bit mode support for DCN3.6+ - Init DMUB DPIA Only for APU - DIO memory leak fix. - Add Handling for gfxversion DcGfxBase Acked-by: ChiaHsuan Chung Signed-off-by: Taimur Hassan Signed-off-by: Wayne Lin Tested-by: Dan Wheeler 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 ce2eceba2ab7..fdfcfa416d16 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.367" +#define DC_VER "3.2.368" /** * MAX_SURFACES - representative of the upper bound of surfaces that can be piped to a single CRTC From 500449eb7008a1e60fd748b4c9d4c2b000cb88c7 Mon Sep 17 00:00:00 2001 From: "Stanley.Yang" Date: Tue, 20 Jan 2026 19:19:08 +0800 Subject: [PATCH 23/51] drm/amdgpu: statistic xgmi training error count Report xgmi training error uncorrectable error count. Signed-off-by: Stanley.Yang Reviewed-by: Tao Zhou Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c index aad530c46a9f..9e32f343097e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c @@ -1176,7 +1176,7 @@ static int xgmi_v6_4_0_aca_bank_parser(struct aca_handle *handle, struct aca_ban switch (type) { case ACA_SMU_TYPE_UE: - if (ext_error_code != 0 && ext_error_code != 9) + if (ext_error_code != 0 && ext_error_code != 1 && ext_error_code != 9) count = 0ULL; bank->aca_err_type = ACA_ERROR_TYPE_UE; From 97a9689300eb2b393ba5efc17c8e5db835917080 Mon Sep 17 00:00:00 2001 From: Bert Karwatzki Date: Sun, 1 Feb 2026 01:24:45 +0100 Subject: [PATCH 24/51] Revert "drm/amd: Check if ASPM is enabled from PCIe subsystem" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 7294863a6f01248d72b61d38478978d638641bee. This commit was erroneously applied again after commit 0ab5d711ec74 ("drm/amd: Refactor `amdgpu_aspm` to be evaluated per device") removed it, leading to very hard to debug crashes, when used with a system with two AMD GPUs of which only one supports ASPM. Link: https://lore.kernel.org/linux-acpi/20251006120944.7880-1-spasswolf@web.de/ Link: https://github.com/acpica/acpica/issues/1060 Fixes: 0ab5d711ec74 ("drm/amd: Refactor `amdgpu_aspm` to be evaluated per device") Signed-off-by: Bert Karwatzki Reviewed-by: Christian König Reviewed-by: Mario Limonciello (AMD) Signed-off-by: Mario Limonciello Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index d6d0a6e34c6b..95d26f086d54 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -2405,9 +2405,6 @@ static int amdgpu_pci_probe(struct pci_dev *pdev, return -ENODEV; } - if (amdgpu_aspm == -1 && !pcie_aspm_enabled(pdev)) - amdgpu_aspm = 0; - if (amdgpu_virtual_display || amdgpu_device_asic_has_dc_support(pdev, flags & AMD_ASIC_MASK)) supports_atomic = true; From e37fb0f818386d2c91474e1aee29fbf692fa08a3 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Mon, 19 Jan 2026 14:37:34 +0530 Subject: [PATCH 25/51] drm/amd/pm: Use feature bits data structure Feature bits are not necessarily restricted to 64-bits. Use smu_feature_bits data structure to represent feature mask for checking DPM status. Signed-off-by: Lijo Lazar Reviewed-by: Asad Kamal Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 17 ++++++++++ .../gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 21 +++++++----- .../amd/pm/swsmu/smu11/cyan_skillfish_ppt.c | 16 +++++---- .../gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 26 ++++++++------- .../amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 26 ++++++++------- .../gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 28 +++++++++------- .../drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 25 ++++++++------ .../drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 22 ++++++++----- .../drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c | 33 ++++++++++--------- .../drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c | 28 +++++++++------- .../drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c | 22 +++++++++---- .../drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 22 ++++++++----- .../drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c | 28 +++++++++------- .../drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c | 32 ++++++++++-------- .../drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c | 18 +++++----- .../drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c | 32 ++++++++++-------- 16 files changed, 237 insertions(+), 159 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 7c63c631f6d4..c58290686f0d 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h @@ -477,6 +477,23 @@ struct smu_feature_bits { DECLARE_BITMAP(bits, SMU_FEATURE_MAX); }; +/* + * Helpers for initializing smu_feature_bits statically. + * Use SMU_FEATURE_BIT_INIT() which automatically handles array indexing: + * static const struct smu_feature_bits example = { + * .bits = { + * SMU_FEATURE_BIT_INIT(5), + * SMU_FEATURE_BIT_INIT(10), + * SMU_FEATURE_BIT_INIT(65), + * SMU_FEATURE_BIT_INIT(100) + * } + * }; + */ +#define SMU_FEATURE_BITS_ELEM(bit) ((bit) / BITS_PER_LONG) +#define SMU_FEATURE_BITS_POS(bit) ((bit) % BITS_PER_LONG) +#define SMU_FEATURE_BIT_INIT(bit) \ + [SMU_FEATURE_BITS_ELEM(bit)] = (1UL << SMU_FEATURE_BITS_POS(bit)) + enum smu_feature_list { SMU_FEATURE_LIST_SUPPORTED, SMU_FEATURE_LIST_ALLOWED, 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 b22a0e91826d..814f24b7ccc4 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c @@ -65,14 +65,15 @@ #define SMU_FEATURES_HIGH_MASK 0xFFFFFFFF00000000 #define SMU_FEATURES_HIGH_SHIFT 32 -#define SMC_DPM_FEATURE ( \ - FEATURE_DPM_PREFETCHER_MASK | \ - FEATURE_DPM_GFXCLK_MASK | \ - FEATURE_DPM_UCLK_MASK | \ - FEATURE_DPM_SOCCLK_MASK | \ - FEATURE_DPM_MP0CLK_MASK | \ - FEATURE_DPM_FCLK_MASK | \ - FEATURE_DPM_XGMI_MASK) +static const struct smu_feature_bits arcturus_dpm_features = { + .bits = { SMU_FEATURE_BIT_INIT(FEATURE_DPM_PREFETCHER_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_UCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_SOCCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_MP0CLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_FCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_XGMI_BIT) } +}; #define smnPCIE_ESM_CTRL 0x111003D0 @@ -1527,12 +1528,14 @@ static bool arcturus_is_dpm_running(struct smu_context *smu) { int ret = 0; uint64_t feature_enabled; + uint32_t feature_mask[2]; ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); if (ret) return false; - return !!(feature_enabled & SMC_DPM_FEATURE); + smu_feature_bits_to_arr32(&arcturus_dpm_features, feature_mask, 64); + return !!(feature_enabled & *(uint64_t *)feature_mask); } static int arcturus_dpm_set_vcn_enable(struct smu_context *smu, 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 4a5dcc893665..406acfbbbc63 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 @@ -60,11 +60,13 @@ static struct gfx_user_settings { static uint32_t cyan_skillfish_sclk_default; -#define FEATURE_MASK(feature) (1ULL << feature) -#define SMC_DPM_FEATURE ( \ - FEATURE_MASK(FEATURE_FCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_SOC_DPM_BIT) | \ - FEATURE_MASK(FEATURE_GFX_DPM_BIT)) +static const struct smu_feature_bits cyan_skillfish_dpm_features = { + .bits = { + SMU_FEATURE_BIT_INIT(FEATURE_FCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_SOC_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_GFX_DPM_BIT) + } +}; static struct cmn2asic_msg_mapping cyan_skillfish_message_map[SMU_MSG_MAX_COUNT] = { MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 0), @@ -362,6 +364,7 @@ static bool cyan_skillfish_is_dpm_running(struct smu_context *smu) struct amdgpu_device *adev = smu->adev; int ret = 0; uint64_t feature_enabled; + uint32_t feature_mask[2]; /* we need to re-init after suspend so return false */ if (adev->in_suspend) @@ -378,7 +381,8 @@ static bool cyan_skillfish_is_dpm_running(struct smu_context *smu) cyan_skillfish_get_smu_metrics_data(smu, METRICS_CURR_GFXCLK, &cyan_skillfish_sclk_default); - return !!(feature_enabled & SMC_DPM_FEATURE); + smu_feature_bits_to_arr32(&cyan_skillfish_dpm_features, feature_mask, 64); + return !!(feature_enabled & *(uint64_t *)feature_mask); } static ssize_t cyan_skillfish_get_gpu_metrics(struct smu_context *smu, 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 f14eed052526..f5be64395108 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c @@ -58,16 +58,18 @@ #undef pr_info #undef pr_debug -#define FEATURE_MASK(feature) (1ULL << feature) -#define SMC_DPM_FEATURE ( \ - FEATURE_MASK(FEATURE_DPM_PREFETCHER_BIT) | \ - FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_GFX_PACE_BIT) | \ - FEATURE_MASK(FEATURE_DPM_UCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_MP0CLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_LINK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_DCEFCLK_BIT)) +static const struct smu_feature_bits navi10_dpm_features = { + .bits = { + SMU_FEATURE_BIT_INIT(FEATURE_DPM_PREFETCHER_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFX_PACE_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_UCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_SOCCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_MP0CLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_LINK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_DCEFCLK_BIT) + } +}; #define SMU_11_0_GFX_BUSY_THRESHOLD 15 @@ -1620,12 +1622,14 @@ static bool navi10_is_dpm_running(struct smu_context *smu) { int ret = 0; uint64_t feature_enabled; + uint32_t feature_mask[2]; ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); if (ret) return false; - return !!(feature_enabled & SMC_DPM_FEATURE); + smu_feature_bits_to_arr32(&navi10_dpm_features, feature_mask, 64); + return !!(feature_enabled & *(uint64_t *)feature_mask); } static int navi10_get_fan_speed_rpm(struct smu_context *smu, 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 98a02fc08214..7d23b6c8c538 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 @@ -60,16 +60,18 @@ #undef pr_info #undef pr_debug -#define FEATURE_MASK(feature) (1ULL << feature) -#define SMC_DPM_FEATURE ( \ - FEATURE_MASK(FEATURE_DPM_PREFETCHER_BIT) | \ - FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_UCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_LINK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_FCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_DCEFCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_MP0CLK_BIT)) +static const struct smu_feature_bits sienna_cichlid_dpm_features = { + .bits = { + SMU_FEATURE_BIT_INIT(FEATURE_DPM_PREFETCHER_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_UCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_LINK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_SOCCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_FCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_DCEFCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_MP0CLK_BIT) + } +}; #define SMU_11_0_7_GFX_BUSY_THRESHOLD 15 @@ -1535,12 +1537,14 @@ static bool sienna_cichlid_is_dpm_running(struct smu_context *smu) { int ret = 0; uint64_t feature_enabled; + uint32_t feature_mask[2]; ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); if (ret) return false; - return !!(feature_enabled & SMC_DPM_FEATURE); + smu_feature_bits_to_arr32(&sienna_cichlid_dpm_features, feature_mask, 64); + return !!(feature_enabled & *(uint64_t *)feature_mask); } static int sienna_cichlid_get_fan_speed_rpm(struct smu_context *smu, 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 4de1778ea6b3..f8b76577d008 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c @@ -58,17 +58,19 @@ #define SMUIO_GFX_MISC_CNTL__SMU_GFX_cold_vs_gfxoff_MASK 0x00000001L #define SMUIO_GFX_MISC_CNTL__PWR_GFXOFF_STATUS_MASK 0x00000006L -#define FEATURE_MASK(feature) (1ULL << feature) -#define SMC_DPM_FEATURE ( \ - FEATURE_MASK(FEATURE_CCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_VCN_DPM_BIT) | \ - FEATURE_MASK(FEATURE_FCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_SOCCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_MP0CLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_LCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_SHUBCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_DCFCLK_DPM_BIT)| \ - FEATURE_MASK(FEATURE_GFX_DPM_BIT)) +static const struct smu_feature_bits vangogh_dpm_features = { + .bits = { + SMU_FEATURE_BIT_INIT(FEATURE_CCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_VCN_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_FCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_SOCCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_MP0CLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_LCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_SHUBCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DCFCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_GFX_DPM_BIT) + } +}; static struct cmn2asic_msg_mapping vangogh_message_map[SMU_MSG_MAX_COUNT] = { MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 0), @@ -505,6 +507,7 @@ static bool vangogh_is_dpm_running(struct smu_context *smu) struct amdgpu_device *adev = smu->adev; int ret = 0; uint64_t feature_enabled; + uint32_t feature_mask[2]; /* we need to re-init after suspend so return false */ if (adev->in_suspend) @@ -515,7 +518,8 @@ static bool vangogh_is_dpm_running(struct smu_context *smu) if (ret) return false; - return !!(feature_enabled & SMC_DPM_FEATURE); + smu_feature_bits_to_arr32(&vangogh_dpm_features, feature_mask, 64); + return !!(feature_enabled & *(uint64_t *)feature_mask); } static int vangogh_get_dpm_clk_limited(struct smu_context *smu, enum smu_clk_type clk_type, 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 3b6a34644a92..4185c7282a11 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -61,15 +61,18 @@ [smu_feature] = {1, (aldebaran_feature)} #define FEATURE_MASK(feature) (1ULL << feature) -#define SMC_DPM_FEATURE ( \ - FEATURE_MASK(FEATURE_DATA_CALCULATIONS) | \ - FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_UCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_FCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_LCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_XGMI_BIT) | \ - FEATURE_MASK(FEATURE_DPM_VCN_BIT)) +static const struct smu_feature_bits aldebaran_dpm_features = { + .bits = { + SMU_FEATURE_BIT_INIT(FEATURE_DATA_CALCULATIONS), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_UCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_SOCCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_FCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_LCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_XGMI_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_VCN_BIT) + } +}; #define smnPCIE_ESM_CTRL 0x111003D0 @@ -1396,11 +1399,13 @@ static bool aldebaran_is_dpm_running(struct smu_context *smu) { int ret; uint64_t feature_enabled; + uint32_t feature_mask[2]; ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); if (ret) return false; - return !!(feature_enabled & SMC_DPM_FEATURE); + smu_feature_bits_to_arr32(&aldebaran_dpm_features, feature_mask, 64); + return !!(feature_enabled & *(uint64_t *)feature_mask); } static int aldebaran_i2c_xfer(struct i2c_adapter *i2c_adap, 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 9c4298736b28..0856c1c34d7a 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 @@ -59,14 +59,16 @@ #define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c)) -#define FEATURE_MASK(feature) (1ULL << feature) -#define SMC_DPM_FEATURE ( \ - FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_UCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_LINK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_FCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_MP0CLK_BIT)) +static const struct smu_feature_bits smu_v13_0_0_dpm_features = { + .bits = { + SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_UCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_LINK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_SOCCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_FCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_MP0CLK_BIT) + } +}; #define MP0_MP1_DATA_REGION_SIZE_COMBOPPTABLE 0x4000 @@ -690,12 +692,14 @@ static bool smu_v13_0_0_is_dpm_running(struct smu_context *smu) { int ret = 0; uint64_t feature_enabled; + uint32_t feature_mask[2]; ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); if (ret) return false; - return !!(feature_enabled & SMC_DPM_FEATURE); + smu_feature_bits_to_arr32(&smu_v13_0_0_dpm_features, feature_mask, 64); + return !!(feature_enabled & *(uint64_t *)feature_mask); } static int smu_v13_0_0_system_features_control(struct smu_context *smu, 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 41c61362f7fc..741762f4bd2c 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 @@ -52,24 +52,25 @@ #define mmMP1_SMN_C2PMSG_90 0x029a #define mmMP1_SMN_C2PMSG_90_BASE_IDX 1 -#define FEATURE_MASK(feature) (1ULL << feature) - #define SMU_13_0_4_UMD_PSTATE_GFXCLK 938 #define SMU_13_0_4_UMD_PSTATE_SOCCLK 938 #define SMU_13_0_4_UMD_PSTATE_FCLK 1875 -#define SMC_DPM_FEATURE ( \ - FEATURE_MASK(FEATURE_CCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_VCN_DPM_BIT) | \ - FEATURE_MASK(FEATURE_FCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_SOCCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_MP0CLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_LCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_SHUBCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_DCFCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_ISP_DPM_BIT) | \ - FEATURE_MASK(FEATURE_IPU_DPM_BIT) | \ - FEATURE_MASK(FEATURE_GFX_DPM_BIT)) +static const struct smu_feature_bits smu_v13_0_4_dpm_features = { + .bits = { + SMU_FEATURE_BIT_INIT(FEATURE_CCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_VCN_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_FCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_SOCCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_MP0CLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_LCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_SHUBCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DCFCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_ISP_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_IPU_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_GFX_DPM_BIT) + } +}; static struct cmn2asic_msg_mapping smu_v13_0_4_message_map[SMU_MSG_MAX_COUNT] = { MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 1), @@ -213,13 +214,15 @@ static bool smu_v13_0_4_is_dpm_running(struct smu_context *smu) { int ret = 0; uint64_t feature_enabled; + uint32_t feature_mask[2]; ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); if (ret) return false; - return !!(feature_enabled & SMC_DPM_FEATURE); + smu_feature_bits_to_arr32(&smu_v13_0_4_dpm_features, feature_mask, 64); + return !!(feature_enabled & *(uint64_t *)feature_mask); } static int smu_v13_0_4_system_features_control(struct smu_context *smu, bool en) 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 e4be727789c0..7311162e50f0 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 @@ -51,17 +51,19 @@ #define mmMP1_C2PMSG_33 (0xbee261 + 0xb00000 / 4) #define mmMP1_C2PMSG_33_BASE_IDX 0 -#define FEATURE_MASK(feature) (1ULL << feature) -#define SMC_DPM_FEATURE ( \ - FEATURE_MASK(FEATURE_CCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_FCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_LCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_GFX_DPM_BIT) | \ - FEATURE_MASK(FEATURE_VCN_DPM_BIT) | \ - FEATURE_MASK(FEATURE_DCFCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_SOCCLK_DPM_BIT)| \ - FEATURE_MASK(FEATURE_MP0CLK_DPM_BIT)| \ - FEATURE_MASK(FEATURE_SHUBCLK_DPM_BIT)) +static const struct smu_feature_bits smu_v13_0_5_dpm_features = { + .bits = { + SMU_FEATURE_BIT_INIT(FEATURE_CCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_FCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_LCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_GFX_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_VCN_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DCFCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_SOCCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_MP0CLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_SHUBCLK_DPM_BIT) + } +}; static struct cmn2asic_msg_mapping smu_v13_0_5_message_map[SMU_MSG_MAX_COUNT] = { MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 1), @@ -231,13 +233,15 @@ static bool smu_v13_0_5_is_dpm_running(struct smu_context *smu) { int ret = 0; uint64_t feature_enabled; + uint32_t feature_mask[2]; ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); if (ret) return false; - return !!(feature_enabled & SMC_DPM_FEATURE); + smu_feature_bits_to_arr32(&smu_v13_0_5_dpm_features, feature_mask, 64); + return !!(feature_enabled & *(uint64_t *)feature_mask); } static int smu_v13_0_5_mode_reset(struct smu_context *smu, int type) 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 bd893e95515f..97866e570192 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 @@ -76,12 +76,18 @@ MODULE_FIRMWARE("amdgpu/smu_13_0_14.bin"); [smu_feature] = { 1, (smu_13_0_6_feature) } #define FEATURE_MASK(feature) (1ULL << feature) -#define SMC_DPM_FEATURE \ - (FEATURE_MASK(FEATURE_DATA_CALCULATION) | \ - FEATURE_MASK(FEATURE_DPM_GFXCLK) | FEATURE_MASK(FEATURE_DPM_UCLK) | \ - FEATURE_MASK(FEATURE_DPM_SOCCLK) | FEATURE_MASK(FEATURE_DPM_FCLK) | \ - FEATURE_MASK(FEATURE_DPM_LCLK) | FEATURE_MASK(FEATURE_DPM_XGMI) | \ - FEATURE_MASK(FEATURE_DPM_VCN)) +static const struct smu_feature_bits smu_v13_0_6_dpm_features = { + .bits = { + SMU_FEATURE_BIT_INIT(FEATURE_DATA_CALCULATION), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_UCLK), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_SOCCLK), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_FCLK), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_LCLK), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_XGMI), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_VCN) + } +}; #define smnPCIE_ESM_CTRL 0x93D0 #define smnPCIE_LC_LINK_WIDTH_CNTL 0x1a340288 @@ -2284,6 +2290,7 @@ static bool smu_v13_0_6_is_dpm_running(struct smu_context *smu) { int ret; uint64_t feature_enabled; + uint32_t feature_mask[2]; if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 12)) return smu_v13_0_12_is_dpm_running(smu); @@ -2293,7 +2300,8 @@ static bool smu_v13_0_6_is_dpm_running(struct smu_context *smu) if (ret) return false; - return !!(feature_enabled & SMC_DPM_FEATURE); + smu_feature_bits_to_arr32(&smu_v13_0_6_dpm_features, feature_mask, 64); + return !!(feature_enabled & *(uint64_t *)feature_mask); } static int smu_v13_0_6_request_i2c_xfer(struct smu_context *smu, 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 415766dbfe6c..eeff6c874635 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 @@ -59,14 +59,16 @@ #define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c)) -#define FEATURE_MASK(feature) (1ULL << feature) -#define SMC_DPM_FEATURE ( \ - FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_UCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_LINK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_FCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_MP0CLK_BIT)) +static const struct smu_feature_bits smu_v13_0_7_dpm_features = { + .bits = { + SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_UCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_LINK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_SOCCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_FCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_MP0CLK_BIT) + } +}; #define smnMP1_FIRMWARE_FLAGS_SMU_13_0_7 0x3b10028 @@ -698,12 +700,14 @@ static bool smu_v13_0_7_is_dpm_running(struct smu_context *smu) { int ret = 0; uint64_t feature_enabled; + uint32_t feature_mask[2]; ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); if (ret) return false; - return !!(feature_enabled & SMC_DPM_FEATURE); + smu_feature_bits_to_arr32(&smu_v13_0_7_dpm_features, feature_mask, 64); + return !!(feature_enabled & *(uint64_t *)feature_mask); } static uint32_t smu_v13_0_7_get_throttler_status(SmuMetrics_t *metrics) 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 7f70f79c3b2f..2331dbb9181a 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 @@ -55,17 +55,19 @@ #define SMU_13_0_1_UMD_PSTATE_SOCCLK 678 #define SMU_13_0_1_UMD_PSTATE_FCLK 1800 -#define FEATURE_MASK(feature) (1ULL << feature) -#define SMC_DPM_FEATURE ( \ - FEATURE_MASK(FEATURE_CCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_VCN_DPM_BIT) | \ - FEATURE_MASK(FEATURE_FCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_SOCCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_MP0CLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_LCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_SHUBCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_DCFCLK_DPM_BIT)| \ - FEATURE_MASK(FEATURE_GFX_DPM_BIT)) +static const struct smu_feature_bits yellow_carp_dpm_features = { + .bits = { + SMU_FEATURE_BIT_INIT(FEATURE_CCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_VCN_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_FCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_SOCCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_MP0CLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_LCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_SHUBCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DCFCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_GFX_DPM_BIT) + } +}; static struct cmn2asic_msg_mapping yellow_carp_message_map[SMU_MSG_MAX_COUNT] = { MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 1), @@ -258,13 +260,15 @@ static bool yellow_carp_is_dpm_running(struct smu_context *smu) { int ret = 0; uint64_t feature_enabled; + uint32_t feature_mask[2]; ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); if (ret) return false; - return !!(feature_enabled & SMC_DPM_FEATURE); + smu_feature_bits_to_arr32(&yellow_carp_dpm_features, feature_mask, 64); + return !!(feature_enabled & *(uint64_t *)feature_mask); } static int yellow_carp_post_smu_init(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 a4e376e8328c..019e43fdecd6 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 @@ -72,19 +72,21 @@ #define SMU_14_0_4_UMD_PSTATE_GFXCLK 938 #define SMU_14_0_4_UMD_PSTATE_SOCCLK 938 -#define FEATURE_MASK(feature) (1ULL << feature) -#define SMC_DPM_FEATURE ( \ - FEATURE_MASK(FEATURE_CCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_VCN_DPM_BIT) | \ - FEATURE_MASK(FEATURE_FCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_SOCCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_LCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_SHUBCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_DCFCLK_DPM_BIT)| \ - FEATURE_MASK(FEATURE_ISP_DPM_BIT)| \ - FEATURE_MASK(FEATURE_IPU_DPM_BIT) | \ - FEATURE_MASK(FEATURE_GFX_DPM_BIT) | \ - FEATURE_MASK(FEATURE_VPE_DPM_BIT)) +static const struct smu_feature_bits smu_v14_0_0_dpm_features = { + .bits = { + SMU_FEATURE_BIT_INIT(FEATURE_CCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_VCN_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_FCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_SOCCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_LCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_SHUBCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DCFCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_ISP_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_IPU_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_GFX_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_VPE_DPM_BIT) + } +}; enum smu_mall_pg_config { SMU_MALL_PG_CONFIG_PMFW_CONTROL = 0, @@ -471,13 +473,15 @@ static bool smu_v14_0_0_is_dpm_running(struct smu_context *smu) { int ret = 0; uint64_t feature_enabled; + uint32_t feature_mask[2]; ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); if (ret) return false; - return !!(feature_enabled & SMC_DPM_FEATURE); + smu_feature_bits_to_arr32(&smu_v14_0_0_dpm_features, feature_mask, 64); + return !!(feature_enabled & *(uint64_t *)feature_mask); } static int smu_v14_0_0_set_watermarks_table(struct smu_context *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 3c351ee41e68..eb8bad2de1cc 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 @@ -56,13 +56,13 @@ #define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c)) -#define FEATURE_MASK(feature) (1ULL << feature) -#define SMC_DPM_FEATURE ( \ - FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_UCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_LINK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT) | \ - FEATURE_MASK(FEATURE_DPM_FCLK_BIT)) +static const struct smu_feature_bits smu_v14_0_2_dpm_features = { + .bits = { SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_UCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_LINK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_SOCCLK_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_FCLK_BIT) } +}; #define MP0_MP1_DATA_REGION_SIZE_COMBOPPTABLE 0x4000 #define DEBUGSMC_MSG_Mode1Reset 2 @@ -590,12 +590,14 @@ static bool smu_v14_0_2_is_dpm_running(struct smu_context *smu) { int ret = 0; uint64_t feature_enabled; + uint32_t feature_mask[2]; ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); if (ret) return false; - return !!(feature_enabled & SMC_DPM_FEATURE); + smu_feature_bits_to_arr32(&smu_v14_0_2_dpm_features, feature_mask, 64); + return !!(feature_enabled & *(uint64_t *)feature_mask); } static uint32_t smu_v14_0_2_get_throttler_status(SmuMetrics_t *metrics) 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 b48444706c1e..d66e9a1a0ef8 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 @@ -70,19 +70,21 @@ #define SMU_15_0_UMD_PSTATE_FCLK 1800 -#define FEATURE_MASK(feature) (1ULL << feature) -#define SMC_DPM_FEATURE ( \ - FEATURE_MASK(FEATURE_CCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_VCN_DPM_BIT) | \ - FEATURE_MASK(FEATURE_FCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_SOCCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_LCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_SHUBCLK_DPM_BIT) | \ - FEATURE_MASK(FEATURE_DCFCLK_DPM_BIT)| \ - FEATURE_MASK(FEATURE_ISP_DPM_BIT)| \ - FEATURE_MASK(FEATURE_NPU_DPM_BIT) | \ - FEATURE_MASK(FEATURE_GFX_DPM_BIT) | \ - FEATURE_MASK(FEATURE_VPE_DPM_BIT)) +static const struct smu_feature_bits smu_v15_0_0_dpm_features = { + .bits = { + SMU_FEATURE_BIT_INIT(FEATURE_CCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_VCN_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_FCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_SOCCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_LCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_SHUBCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_DCFCLK_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_ISP_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_NPU_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_GFX_DPM_BIT), + SMU_FEATURE_BIT_INIT(FEATURE_VPE_DPM_BIT) + } +}; enum smu_mall_pg_config { SMU_MALL_PG_CONFIG_PMFW_CONTROL = 0, @@ -445,13 +447,15 @@ static bool smu_v15_0_0_is_dpm_running(struct smu_context *smu) { int ret = 0; uint64_t feature_enabled; + uint32_t feature_mask[2]; ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); if (ret) return false; - return !!(feature_enabled & SMC_DPM_FEATURE); + smu_feature_bits_to_arr32(&smu_v15_0_0_dpm_features, feature_mask, 64); + return !!(feature_enabled & *(uint64_t *)feature_mask); } static int smu_v15_0_0_set_watermarks_table(struct smu_context *smu, From 7b88453a476c9770c094c1f596e0b9fee208e65b Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Mon, 19 Jan 2026 16:04:06 +0530 Subject: [PATCH 26/51] drm/amd/pm: Change get_enabled_mask signature Use smu_feature_bits instead of uint64_t pointer and operate on feature bits. Signed-off-by: Lijo Lazar Reviewed-by: Asad Kamal Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 17 +++-- drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h | 9 ++- .../gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c | 7 +- .../amd/pm/swsmu/smu11/cyan_skillfish_ppt.c | 14 ++-- .../gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c | 7 +- .../amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 7 +- .../gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c | 7 +- .../gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c | 4 +- .../drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 7 +- .../drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 7 +- .../drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c | 20 +++--- .../drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c | 7 +- .../drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c | 7 +- .../drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c | 11 ++- .../drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 7 +- .../drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c | 7 +- .../drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c | 7 +- .../drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c | 7 +- .../drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c | 7 +- drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 72 +++++++++---------- drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h | 2 +- 21 files changed, 123 insertions(+), 117 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 75897ac203c3..797da21e2e5f 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -1646,7 +1646,7 @@ static int smu_smc_hw_setup(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; uint8_t pcie_gen = 0, pcie_width = 0; - uint64_t features_supported; + struct smu_feature_bits features_supported; int ret = 0; switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) { @@ -1807,7 +1807,7 @@ static int smu_smc_hw_setup(struct smu_context *smu) return ret; } smu_feature_list_set_bits(smu, SMU_FEATURE_LIST_SUPPORTED, - (unsigned long *)&features_supported); + features_supported.bits); if (!smu_is_dpm_running(smu)) dev_info(adev->dev, "dpm has been disabled\n"); @@ -3152,10 +3152,19 @@ static int smu_read_sensor(void *handle, *((uint32_t *)data) = pstate_table->uclk_pstate.peak * 100; *size = 4; break; - case AMDGPU_PP_SENSOR_ENABLED_SMC_FEATURES_MASK: - ret = smu_feature_get_enabled_mask(smu, (uint64_t *)data); + case AMDGPU_PP_SENSOR_ENABLED_SMC_FEATURES_MASK: { + struct smu_feature_bits feature_mask; + uint32_t features[2]; + + /* TBD: need to handle for > 64 bits */ + ret = smu_feature_get_enabled_mask(smu, &feature_mask); + if (!ret) { + smu_feature_bits_to_arr32(&feature_mask, features, 64); + *(uint64_t *)data = *(uint64_t *)features; + } *size = 8; break; + } case AMDGPU_PP_SENSOR_UVD_POWER: *(uint32_t *)data = smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UVD_BIT) ? 1 : 0; *size = 4; 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 c58290686f0d..4019ef859504 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h @@ -1229,7 +1229,8 @@ struct pptable_funcs { * on the SMU. * &feature_mask: Enabled feature mask. */ - int (*get_enabled_mask)(struct smu_context *smu, uint64_t *feature_mask); + int (*get_enabled_mask)(struct smu_context *smu, + struct smu_feature_bits *feature_mask); /** * @feature_is_enabled: Test if a feature is enabled. @@ -2061,6 +2062,12 @@ static inline bool smu_feature_bits_empty(const struct smu_feature_bits *bits, return bitmap_empty(bits->bits, nbits); } +static inline bool smu_feature_bits_full(const struct smu_feature_bits *bits, + unsigned int nbits) +{ + return bitmap_full(bits->bits, nbits); +} + static inline void smu_feature_bits_copy(struct smu_feature_bits *dst, const unsigned long *src, unsigned int nbits) 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 814f24b7ccc4..0c4afd1e1aab 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c @@ -1527,15 +1527,14 @@ static int arcturus_set_performance_level(struct smu_context *smu, static bool arcturus_is_dpm_running(struct smu_context *smu) { int ret = 0; - uint64_t feature_enabled; - uint32_t feature_mask[2]; + struct smu_feature_bits feature_enabled; ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); if (ret) return false; - smu_feature_bits_to_arr32(&arcturus_dpm_features, feature_mask, 64); - return !!(feature_enabled & *(uint64_t *)feature_mask); + return smu_feature_bits_test_mask(&feature_enabled, + arcturus_dpm_features.bits); } static int arcturus_dpm_set_vcn_enable(struct smu_context *smu, 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 406acfbbbc63..87953a4d0a43 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 @@ -363,8 +363,7 @@ static bool cyan_skillfish_is_dpm_running(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; int ret = 0; - uint64_t feature_enabled; - uint32_t feature_mask[2]; + struct smu_feature_bits feature_enabled; /* we need to re-init after suspend so return false */ if (adev->in_suspend) @@ -381,8 +380,8 @@ static bool cyan_skillfish_is_dpm_running(struct smu_context *smu) cyan_skillfish_get_smu_metrics_data(smu, METRICS_CURR_GFXCLK, &cyan_skillfish_sclk_default); - smu_feature_bits_to_arr32(&cyan_skillfish_dpm_features, feature_mask, 64); - return !!(feature_enabled & *(uint64_t *)feature_mask); + return smu_feature_bits_test_mask(&feature_enabled, + cyan_skillfish_dpm_features.bits); } static ssize_t cyan_skillfish_get_gpu_metrics(struct smu_context *smu, @@ -569,12 +568,13 @@ static int cyan_skillfish_get_dpm_ultimate_freq(struct smu_context *smu, return 0; } -static int cyan_skillfish_get_enabled_mask(struct smu_context *smu, - uint64_t *feature_mask) +static int +cyan_skillfish_get_enabled_mask(struct smu_context *smu, + struct smu_feature_bits *feature_mask) { if (!feature_mask) return -EINVAL; - memset(feature_mask, 0xff, sizeof(*feature_mask)); + smu_feature_bits_fill(feature_mask); return 0; } 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 f5be64395108..737bfdfb814c 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c @@ -1621,15 +1621,14 @@ static int navi10_display_config_changed(struct smu_context *smu) static bool navi10_is_dpm_running(struct smu_context *smu) { int ret = 0; - uint64_t feature_enabled; - uint32_t feature_mask[2]; + struct smu_feature_bits feature_enabled; ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); if (ret) return false; - smu_feature_bits_to_arr32(&navi10_dpm_features, feature_mask, 64); - return !!(feature_enabled & *(uint64_t *)feature_mask); + return smu_feature_bits_test_mask(&feature_enabled, + navi10_dpm_features.bits); } static int navi10_get_fan_speed_rpm(struct smu_context *smu, 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 7d23b6c8c538..6268bc5ed3e6 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 @@ -1536,15 +1536,14 @@ static int sienna_cichlid_display_config_changed(struct smu_context *smu) static bool sienna_cichlid_is_dpm_running(struct smu_context *smu) { int ret = 0; - uint64_t feature_enabled; - uint32_t feature_mask[2]; + struct smu_feature_bits feature_enabled; ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); if (ret) return false; - smu_feature_bits_to_arr32(&sienna_cichlid_dpm_features, feature_mask, 64); - return !!(feature_enabled & *(uint64_t *)feature_mask); + return smu_feature_bits_test_mask(&feature_enabled, + sienna_cichlid_dpm_features.bits); } static int sienna_cichlid_get_fan_speed_rpm(struct smu_context *smu, 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 f8b76577d008..08179840697e 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c @@ -506,8 +506,7 @@ static bool vangogh_is_dpm_running(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; int ret = 0; - uint64_t feature_enabled; - uint32_t feature_mask[2]; + struct smu_feature_bits feature_enabled; /* we need to re-init after suspend so return false */ if (adev->in_suspend) @@ -518,8 +517,8 @@ static bool vangogh_is_dpm_running(struct smu_context *smu) if (ret) return false; - smu_feature_bits_to_arr32(&vangogh_dpm_features, feature_mask, 64); - return !!(feature_enabled & *(uint64_t *)feature_mask); + return smu_feature_bits_test_mask(&feature_enabled, + vangogh_dpm_features.bits); } static int vangogh_get_dpm_clk_limited(struct smu_context *smu, enum smu_clk_type clk_type, 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 5346b60b09b9..31e21ff8859a 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c @@ -1434,11 +1434,11 @@ static int renoir_gfx_state_change_set(struct smu_context *smu, uint32_t state) } static int renoir_get_enabled_mask(struct smu_context *smu, - uint64_t *feature_mask) + struct smu_feature_bits *feature_mask) { if (!feature_mask) return -EINVAL; - memset(feature_mask, 0xff, sizeof(*feature_mask)); + smu_feature_bits_fill(feature_mask); return 0; } 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 4185c7282a11..ad23682217ee 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -1398,14 +1398,13 @@ static int aldebaran_usr_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_ static bool aldebaran_is_dpm_running(struct smu_context *smu) { int ret; - uint64_t feature_enabled; - uint32_t feature_mask[2]; + struct smu_feature_bits feature_enabled; ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); if (ret) return false; - smu_feature_bits_to_arr32(&aldebaran_dpm_features, feature_mask, 64); - return !!(feature_enabled & *(uint64_t *)feature_mask); + return smu_feature_bits_test_mask(&feature_enabled, + aldebaran_dpm_features.bits); } static int aldebaran_i2c_xfer(struct i2c_adapter *i2c_adap, 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 0856c1c34d7a..de770c10da3d 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 @@ -691,15 +691,14 @@ static int smu_v13_0_0_set_default_dpm_table(struct smu_context *smu) static bool smu_v13_0_0_is_dpm_running(struct smu_context *smu) { int ret = 0; - uint64_t feature_enabled; - uint32_t feature_mask[2]; + struct smu_feature_bits feature_enabled; ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); if (ret) return false; - smu_feature_bits_to_arr32(&smu_v13_0_0_dpm_features, feature_mask, 64); - return !!(feature_enabled & *(uint64_t *)feature_mask); + return smu_feature_bits_test_mask(&feature_enabled, + smu_v13_0_0_dpm_features.bits); } static int smu_v13_0_0_system_features_control(struct smu_context *smu, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c index 9a34e5460b35..3d60d3c1e585 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c @@ -52,10 +52,13 @@ #define SMU_13_0_12_FEA_MAP(smu_feature, smu_13_0_12_feature) \ [smu_feature] = { 1, (smu_13_0_12_feature) } -#define FEATURE_MASK(feature) (1ULL << feature) -#define SMC_DPM_FEATURE \ - (FEATURE_MASK(FEATURE_DATA_CALCULATION) | \ - FEATURE_MASK(FEATURE_DPM_GFXCLK) | FEATURE_MASK(FEATURE_DPM_FCLK)) +static const struct smu_feature_bits smu_v13_0_12_dpm_features = { + .bits = { + SMU_FEATURE_BIT_INIT(FEATURE_DATA_CALCULATION), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK), + SMU_FEATURE_BIT_INIT(FEATURE_DPM_FCLK) + } +}; #define NUM_JPEG_RINGS_FW 10 #define NUM_JPEG_RINGS_GPU_METRICS(gpu_metrics) \ @@ -199,14 +202,14 @@ void smu_v13_0_12_tables_fini(struct smu_context *smu) } static int smu_v13_0_12_get_enabled_mask(struct smu_context *smu, - uint64_t *feature_mask) + struct smu_feature_bits *feature_mask) { int ret; ret = smu_cmn_get_enabled_mask(smu, feature_mask); if (ret == -EIO) { - *feature_mask = 0; + smu_feature_bits_clearall(feature_mask); ret = 0; } @@ -372,14 +375,15 @@ int smu_v13_0_12_setup_driver_pptable(struct smu_context *smu) bool smu_v13_0_12_is_dpm_running(struct smu_context *smu) { int ret; - uint64_t feature_enabled; + struct smu_feature_bits feature_enabled; ret = smu_v13_0_12_get_enabled_mask(smu, &feature_enabled); if (ret) return false; - return !!(feature_enabled & SMC_DPM_FEATURE); + return smu_feature_bits_test_mask(&feature_enabled, + smu_v13_0_12_dpm_features.bits); } int smu_v13_0_12_get_smu_metrics_data(struct smu_context *smu, 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 741762f4bd2c..75b90ac0c29c 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 @@ -213,16 +213,15 @@ static int smu_v13_0_4_fini_smc_tables(struct smu_context *smu) static bool smu_v13_0_4_is_dpm_running(struct smu_context *smu) { int ret = 0; - uint64_t feature_enabled; - uint32_t feature_mask[2]; + struct smu_feature_bits feature_enabled; ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); if (ret) return false; - smu_feature_bits_to_arr32(&smu_v13_0_4_dpm_features, feature_mask, 64); - return !!(feature_enabled & *(uint64_t *)feature_mask); + return smu_feature_bits_test_mask(&feature_enabled, + smu_v13_0_4_dpm_features.bits); } static int smu_v13_0_4_system_features_control(struct smu_context *smu, bool en) 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 7311162e50f0..8ee5002e3d6b 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 @@ -232,16 +232,15 @@ static int smu_v13_0_5_dpm_set_jpeg_enable(struct smu_context *smu, bool enable) static bool smu_v13_0_5_is_dpm_running(struct smu_context *smu) { int ret = 0; - uint64_t feature_enabled; - uint32_t feature_mask[2]; + struct smu_feature_bits feature_enabled; ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); if (ret) return false; - smu_feature_bits_to_arr32(&smu_v13_0_5_dpm_features, feature_mask, 64); - return !!(feature_enabled & *(uint64_t *)feature_mask); + return smu_feature_bits_test_mask(&feature_enabled, + smu_v13_0_5_dpm_features.bits); } static int smu_v13_0_5_mode_reset(struct smu_context *smu, int type) 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 97866e570192..be7d77eee2b0 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 @@ -2272,14 +2272,14 @@ static int smu_v13_0_6_usr_edit_dpm_table(struct smu_context *smu, } static int smu_v13_0_6_get_enabled_mask(struct smu_context *smu, - uint64_t *feature_mask) + struct smu_feature_bits *feature_mask) { int ret; ret = smu_cmn_get_enabled_mask(smu, feature_mask); if (ret == -EIO && !smu_v13_0_6_cap_supported(smu, SMU_CAP(DPM))) { - *feature_mask = 0; + smu_feature_bits_clearall(feature_mask); ret = 0; } @@ -2289,8 +2289,7 @@ static int smu_v13_0_6_get_enabled_mask(struct smu_context *smu, static bool smu_v13_0_6_is_dpm_running(struct smu_context *smu) { int ret; - uint64_t feature_enabled; - uint32_t feature_mask[2]; + struct smu_feature_bits feature_enabled; if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 12)) return smu_v13_0_12_is_dpm_running(smu); @@ -2300,8 +2299,8 @@ static bool smu_v13_0_6_is_dpm_running(struct smu_context *smu) if (ret) return false; - smu_feature_bits_to_arr32(&smu_v13_0_6_dpm_features, feature_mask, 64); - return !!(feature_enabled & *(uint64_t *)feature_mask); + return smu_feature_bits_test_mask(&feature_enabled, + smu_v13_0_6_dpm_features.bits); } static int smu_v13_0_6_request_i2c_xfer(struct smu_context *smu, 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 eeff6c874635..fe3d6bfe6812 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 @@ -699,15 +699,14 @@ static int smu_v13_0_7_set_default_dpm_table(struct smu_context *smu) static bool smu_v13_0_7_is_dpm_running(struct smu_context *smu) { int ret = 0; - uint64_t feature_enabled; - uint32_t feature_mask[2]; + struct smu_feature_bits feature_enabled; ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); if (ret) return false; - smu_feature_bits_to_arr32(&smu_v13_0_7_dpm_features, feature_mask, 64); - return !!(feature_enabled & *(uint64_t *)feature_mask); + return smu_feature_bits_test_mask(&feature_enabled, + smu_v13_0_7_dpm_features.bits); } static uint32_t smu_v13_0_7_get_throttler_status(SmuMetrics_t *metrics) 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 2331dbb9181a..f9789b1fcbf8 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 @@ -259,16 +259,15 @@ static int yellow_carp_dpm_set_jpeg_enable(struct smu_context *smu, bool enable) static bool yellow_carp_is_dpm_running(struct smu_context *smu) { int ret = 0; - uint64_t feature_enabled; - uint32_t feature_mask[2]; + struct smu_feature_bits feature_enabled; ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); if (ret) return false; - smu_feature_bits_to_arr32(&yellow_carp_dpm_features, feature_mask, 64); - return !!(feature_enabled & *(uint64_t *)feature_mask); + return smu_feature_bits_test_mask(&feature_enabled, + yellow_carp_dpm_features.bits); } static int yellow_carp_post_smu_init(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 019e43fdecd6..dbdf7653cc53 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 @@ -472,16 +472,15 @@ static int smu_v14_0_0_read_sensor(struct smu_context *smu, static bool smu_v14_0_0_is_dpm_running(struct smu_context *smu) { int ret = 0; - uint64_t feature_enabled; - uint32_t feature_mask[2]; + struct smu_feature_bits feature_enabled; ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); if (ret) return false; - smu_feature_bits_to_arr32(&smu_v14_0_0_dpm_features, feature_mask, 64); - return !!(feature_enabled & *(uint64_t *)feature_mask); + return smu_feature_bits_test_mask(&feature_enabled, + smu_v14_0_0_dpm_features.bits); } static int smu_v14_0_0_set_watermarks_table(struct smu_context *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 eb8bad2de1cc..becfd356b4e7 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 @@ -589,15 +589,14 @@ static int smu_v14_0_2_set_default_dpm_table(struct smu_context *smu) static bool smu_v14_0_2_is_dpm_running(struct smu_context *smu) { int ret = 0; - uint64_t feature_enabled; - uint32_t feature_mask[2]; + struct smu_feature_bits feature_enabled; ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); if (ret) return false; - smu_feature_bits_to_arr32(&smu_v14_0_2_dpm_features, feature_mask, 64); - return !!(feature_enabled & *(uint64_t *)feature_mask); + return smu_feature_bits_test_mask(&feature_enabled, + smu_v14_0_2_dpm_features.bits); } static uint32_t smu_v14_0_2_get_throttler_status(SmuMetrics_t *metrics) 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 d66e9a1a0ef8..c3f22844ba2f 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 @@ -446,16 +446,15 @@ static int smu_v15_0_0_read_sensor(struct smu_context *smu, static bool smu_v15_0_0_is_dpm_running(struct smu_context *smu) { int ret = 0; - uint64_t feature_enabled; - uint32_t feature_mask[2]; + struct smu_feature_bits feature_enabled; ret = smu_cmn_get_enabled_mask(smu, &feature_enabled); if (ret) return false; - smu_feature_bits_to_arr32(&smu_v15_0_0_dpm_features, feature_mask, 64); - return !!(feature_enabled & *(uint64_t *)feature_mask); + return smu_feature_bits_test_mask(&feature_enabled, + smu_v15_0_0_dpm_features.bits); } static int smu_v15_0_0_set_watermarks_table(struct smu_context *smu, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c index 9bb7e3760c0f..a9e0b52bc739 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c @@ -690,7 +690,7 @@ int smu_cmn_feature_is_supported(struct smu_context *smu, } static int __smu_get_enabled_features(struct smu_context *smu, - uint64_t *enabled_features) + struct smu_feature_bits *enabled_features) { return smu_cmn_call_asic_func(get_enabled_mask, smu, enabled_features); } @@ -699,7 +699,7 @@ int smu_cmn_feature_is_enabled(struct smu_context *smu, enum smu_feature_mask mask) { struct amdgpu_device *adev = smu->adev; - uint64_t enabled_features; + struct smu_feature_bits enabled_features; int feature_id; if (__smu_get_enabled_features(smu, &enabled_features)) { @@ -712,7 +712,8 @@ int smu_cmn_feature_is_enabled(struct smu_context *smu, * enabled. Also considering they have no feature_map available, the * check here can avoid unwanted feature_map check below. */ - if (enabled_features == ULLONG_MAX) + if (smu_feature_bits_full(&enabled_features, + smu->smu_feature.feature_num)) return 1; feature_id = smu_cmn_to_asic_specific_index(smu, @@ -721,7 +722,7 @@ int smu_cmn_feature_is_enabled(struct smu_context *smu, if (feature_id < 0) return 0; - return test_bit(feature_id, (unsigned long *)&enabled_features); + return smu_feature_bits_is_set(&enabled_features, feature_id); } bool smu_cmn_clk_dpm_is_enabled(struct smu_context *smu, @@ -763,45 +764,38 @@ bool smu_cmn_clk_dpm_is_enabled(struct smu_context *smu, } int smu_cmn_get_enabled_mask(struct smu_context *smu, - uint64_t *feature_mask) + struct smu_feature_bits *feature_mask) { - uint32_t *feature_mask_high; - uint32_t *feature_mask_low; + uint32_t features[2]; int ret = 0, index = 0; if (!feature_mask) return -EINVAL; - feature_mask_low = &((uint32_t *)feature_mask)[0]; - feature_mask_high = &((uint32_t *)feature_mask)[1]; - index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG, SMU_MSG_GetEnabledSmuFeatures); if (index > 0) { - ret = smu_cmn_send_smc_msg_with_param(smu, - SMU_MSG_GetEnabledSmuFeatures, - 0, - feature_mask_low); + ret = smu_cmn_send_smc_msg_with_param( + smu, SMU_MSG_GetEnabledSmuFeatures, 0, &features[0]); if (ret) return ret; - ret = smu_cmn_send_smc_msg_with_param(smu, - SMU_MSG_GetEnabledSmuFeatures, - 1, - feature_mask_high); + ret = smu_cmn_send_smc_msg_with_param( + smu, SMU_MSG_GetEnabledSmuFeatures, 1, &features[1]); } else { - ret = smu_cmn_send_smc_msg(smu, - SMU_MSG_GetEnabledSmuFeaturesHigh, - feature_mask_high); + ret = smu_cmn_send_smc_msg( + smu, SMU_MSG_GetEnabledSmuFeaturesHigh, &features[1]); if (ret) return ret; - ret = smu_cmn_send_smc_msg(smu, - SMU_MSG_GetEnabledSmuFeaturesLow, - feature_mask_low); + ret = smu_cmn_send_smc_msg( + smu, SMU_MSG_GetEnabledSmuFeaturesLow, &features[0]); } + if (!ret) + smu_feature_bits_from_arr32(feature_mask, features, 64); + return ret; } @@ -886,7 +880,8 @@ size_t smu_cmn_get_pp_feature_mask(struct smu_context *smu, char *buf) { int8_t sort_feature[MAX(SMU_FEATURE_COUNT, SMU_FEATURE_MAX)]; - uint64_t feature_mask; + struct smu_feature_bits feature_mask; + uint32_t features[2]; int i, feature_index; uint32_t count = 0; size_t size = 0; @@ -894,8 +889,10 @@ size_t smu_cmn_get_pp_feature_mask(struct smu_context *smu, if (__smu_get_enabled_features(smu, &feature_mask)) return 0; - size = sysfs_emit_at(buf, size, "features high: 0x%08x low: 0x%08x\n", - upper_32_bits(feature_mask), lower_32_bits(feature_mask)); + /* TBD: Need to handle for > 64 bits */ + smu_feature_bits_to_arr32(&feature_mask, features, 64); + size = sysfs_emit_at(buf, size, "features high: 0x%08x low: 0x%08x\n", + features[1], features[0]); memset(sort_feature, -1, sizeof(sort_feature)); @@ -916,12 +913,13 @@ size_t smu_cmn_get_pp_feature_mask(struct smu_context *smu, if (sort_feature[feature_index] < 0) continue; - size += sysfs_emit_at(buf, size, "%02d. %-20s (%2d) : %s\n", - count++, - smu_get_feature_name(smu, sort_feature[feature_index]), - feature_index, - !!test_bit(feature_index, (unsigned long *)&feature_mask) ? - "enabled" : "disabled"); + size += sysfs_emit_at( + buf, size, "%02d. %-20s (%2d) : %s\n", count++, + smu_get_feature_name(smu, sort_feature[feature_index]), + feature_index, + smu_feature_bits_is_set(&feature_mask, feature_index) ? + "enabled" : + "disabled"); } return size; @@ -931,7 +929,8 @@ int smu_cmn_set_pp_feature_mask(struct smu_context *smu, uint64_t new_mask) { int ret = 0; - uint64_t feature_mask; + struct smu_feature_bits feature_mask; + uint64_t feature_mask_u64; uint64_t feature_2_enabled = 0; uint64_t feature_2_disabled = 0; @@ -939,8 +938,9 @@ int smu_cmn_set_pp_feature_mask(struct smu_context *smu, if (ret) return ret; - feature_2_enabled = ~feature_mask & new_mask; - feature_2_disabled = feature_mask & ~new_mask; + feature_mask_u64 = *(uint64_t *)feature_mask.bits; + feature_2_enabled = ~feature_mask_u64 & new_mask; + feature_2_disabled = feature_mask_u64 & ~new_mask; if (feature_2_enabled) { ret = smu_cmn_feature_update_enable_state(smu, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h index 92ad2ece7a36..b7bfddc65fb2 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h @@ -141,7 +141,7 @@ bool smu_cmn_clk_dpm_is_enabled(struct smu_context *smu, enum smu_clk_type clk_type); int smu_cmn_get_enabled_mask(struct smu_context *smu, - uint64_t *feature_mask); + struct smu_feature_bits *feature_mask); uint64_t smu_cmn_get_indep_throttler_status( const unsigned long dep_status, From da8c276035494e86f2cfda7afd92c3202c4c0997 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Mon, 19 Jan 2026 18:32:19 +0530 Subject: [PATCH 27/51] drm/amd/pm: Add default feature number definition The number of default features could be different from the actual width of the bitmap. Use a different definition for it. Also increase the max width of bitmap to 128. 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 | 3 ++- drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c | 2 +- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c | 2 +- drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c | 2 +- drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c | 2 +- drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c | 6 ++++-- 7 files changed, 11 insertions(+), 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 797da21e2e5f..9f52b7b24198 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -1355,7 +1355,7 @@ static int smu_sw_init(struct amdgpu_ip_block *ip_block) int i, ret; smu->pool_size = adev->pm.smu_prv_buffer_size; - smu_feature_init(smu, SMU_FEATURE_MAX); + smu_feature_init(smu, SMU_FEATURE_NUM_DEFAULT); INIT_WORK(&smu->throttling_logging_work, smu_throttling_logging_work_fn); INIT_WORK(&smu->interrupt_work, smu_interrupt_work_fn); 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 4019ef859504..512493a8452b 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h @@ -471,7 +471,8 @@ struct smu_power_context { struct smu_power_gate power_gate; }; -#define SMU_FEATURE_MAX (64) +#define SMU_FEATURE_NUM_DEFAULT (64) +#define SMU_FEATURE_MAX (128) struct smu_feature_bits { DECLARE_BITMAP(bits, SMU_FEATURE_MAX); 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 1d0f9f8ddf9b..56efcfa327df 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 @@ -751,7 +751,7 @@ int smu_v11_0_set_allowed_mask(struct smu_context *smu) uint32_t feature_mask[2]; if (smu_feature_list_is_empty(smu, SMU_FEATURE_LIST_ALLOWED) || - feature->feature_num < 64) { + feature->feature_num < SMU_FEATURE_NUM_DEFAULT) { ret = -EINVAL; goto failed; } 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 3b0aa6a2e78e..63a65ea802fd 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 @@ -762,7 +762,7 @@ int smu_v13_0_set_allowed_mask(struct smu_context *smu) uint32_t feature_mask[2]; if (smu_feature_list_is_empty(smu, SMU_FEATURE_LIST_ALLOWED) || - feature->feature_num < 64) + feature->feature_num < SMU_FEATURE_NUM_DEFAULT) return -EINVAL; smu_feature_list_to_arr32(smu, SMU_FEATURE_LIST_ALLOWED, feature_mask); 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 cabbd234c6e2..7dc6687c3693 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 @@ -747,7 +747,7 @@ int smu_v14_0_set_allowed_mask(struct smu_context *smu) uint32_t feature_mask[2]; if (smu_feature_list_is_empty(smu, SMU_FEATURE_LIST_ALLOWED) || - feature->feature_num < 64) + feature->feature_num < SMU_FEATURE_NUM_DEFAULT) return -EINVAL; smu_feature_list_to_arr32(smu, SMU_FEATURE_LIST_ALLOWED, feature_mask); 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 d77eaac556d9..a2854d528bab 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 @@ -716,7 +716,7 @@ int smu_v15_0_set_allowed_mask(struct smu_context *smu) uint32_t feature_mask[2]; if (smu_feature_list_is_empty(smu, SMU_FEATURE_LIST_ALLOWED) || - feature->feature_num < 64) + feature->feature_num < SMU_FEATURE_NUM_DEFAULT) return -EINVAL; smu_feature_list_to_arr32(smu, SMU_FEATURE_LIST_ALLOWED, feature_mask); diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c index a9e0b52bc739..6fd50c2fd20e 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c @@ -794,7 +794,8 @@ int smu_cmn_get_enabled_mask(struct smu_context *smu, } if (!ret) - smu_feature_bits_from_arr32(feature_mask, features, 64); + smu_feature_bits_from_arr32(feature_mask, features, + SMU_FEATURE_NUM_DEFAULT); return ret; } @@ -909,7 +910,8 @@ size_t smu_cmn_get_pp_feature_mask(struct smu_context *smu, size += sysfs_emit_at(buf, size, "%-2s. %-20s %-3s : %-s\n", "No", "Feature", "Bit", "State"); - for (feature_index = 0; feature_index < SMU_FEATURE_MAX; feature_index++) { + for (feature_index = 0; feature_index < smu->smu_feature.feature_num; + feature_index++) { if (sort_feature[feature_index] < 0) continue; From c6fa06fc4c78ed6658bc77d41ceaca0c0121da48 Mon Sep 17 00:00:00 2001 From: Jinzhou Su Date: Wed, 21 Jan 2026 16:27:46 +0800 Subject: [PATCH 28/51] drm/amdgpu/psp_v15_0_8: Add get ras capability Add get ras capability for psp 15.0.8. v2:Remove APU type check and IP version check. Signed-off-by: Jinzhou Su Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/psp_v15_0_8.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v15_0_8.c b/drivers/gpu/drm/amd/amdgpu/psp_v15_0_8.c index 5249f5bd2a10..b2d7cbd894c0 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v15_0_8.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v15_0_8.c @@ -187,6 +187,26 @@ static void psp_v15_0_8_ring_set_wptr(struct psp_context *psp, uint32_t value) WREG32_SOC15(MP0, 0, regMPASP_SMN_C2PMSG_67, value); } +static bool psp_v15_0_8_get_ras_capability(struct psp_context *psp) +{ + struct amdgpu_device *adev = psp->adev; + struct amdgpu_ras *con = amdgpu_ras_get_context(adev); + u32 reg_data; + + /* query ras cap should be done from host side */ + if (amdgpu_sriov_vf(adev)) + return false; + + if (!con) + return false; + + reg_data = RREG32_SOC15(MP0, 0, regMPASP_SMN_C2PMSG_127); + adev->ras_hw_enabled = (reg_data & GENMASK_ULL(23, 0)); + con->poison_supported = ((reg_data & GENMASK_ULL(24, 24)) >> 24) ? true : false; + + return true; +} + static int psp_v15_0_8_get_fw_type(struct amdgpu_firmware_info *ucode, enum psp_gfx_fw_type *type) { @@ -334,6 +354,7 @@ static const struct psp_funcs psp_v15_0_8_funcs = { .ring_get_wptr = psp_v15_0_8_ring_get_wptr, .ring_set_wptr = psp_v15_0_8_ring_set_wptr, .get_fw_type = psp_v15_0_8_get_fw_type, + .get_ras_capability = psp_v15_0_8_get_ras_capability, }; void psp_v15_0_8_set_psp_funcs(struct psp_context *psp) From 08b1eb621cc32819b7958a15cff10016b03b7aff Mon Sep 17 00:00:00 2001 From: Andrew Martin Date: Tue, 11 Nov 2025 16:43:45 -0500 Subject: [PATCH 29/51] drm/amdgpu: Ignored various return code The return code of a non void function should not be ignored. In cases where we do not care, the code needs to suppress it. Signed-off-by: Andrew Martin Reviewed-by: Felix Kuehling Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 8 +++----- drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 8 ++++++-- drivers/gpu/drm/amd/amdkfd/kfd_debug.c | 9 +++++---- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 877d0df50376..3bfd79c89df3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -317,8 +317,7 @@ int amdgpu_amdkfd_post_reset(struct amdgpu_device *adev) void amdgpu_amdkfd_gpu_reset(struct amdgpu_device *adev) { if (amdgpu_device_should_recover_gpu(adev)) - amdgpu_reset_domain_schedule(adev->reset_domain, - &adev->kfd.reset_work); + (void)amdgpu_reset_domain_schedule(adev->reset_domain, &adev->kfd.reset_work); } int amdgpu_amdkfd_alloc_kernel_mem(struct amdgpu_device *adev, size_t size, @@ -720,9 +719,8 @@ void amdgpu_amdkfd_set_compute_idle(struct amdgpu_device *adev, bool idle) if (gfx_block != NULL) gfx_block->version->funcs->set_powergating_state((void *)gfx_block, state); } - amdgpu_dpm_switch_power_profile(adev, - PP_SMC_POWER_PROFILE_COMPUTE, - !idle); + (void)amdgpu_dpm_switch_power_profile(adev, PP_SMC_POWER_PROFILE_COMPUTE, !idle); + } bool amdgpu_amdkfd_is_kfd_vmid(struct amdgpu_device *adev, u32 vmid) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index 88621cb7d409..732ad1224a61 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -2804,8 +2804,12 @@ static int runtime_enable(struct kfd_process *p, uint64_t r_debug, * SET_SHADER_DEBUGGER clears any stale process context data * saved in MES. */ - if (pdd->dev->kfd->shared_resources.enable_mes) - kfd_dbg_set_mes_debug_mode(pdd, !kfd_dbg_has_cwsr_workaround(pdd->dev)); + if (pdd->dev->kfd->shared_resources.enable_mes) { + ret = kfd_dbg_set_mes_debug_mode( + pdd, !kfd_dbg_has_cwsr_workaround(pdd->dev)); + if (ret) + return ret; + } } p->runtime_info.runtime_state = DEBUG_RUNTIME_STATE_ENABLED; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_debug.c b/drivers/gpu/drm/amd/amdkfd/kfd_debug.c index 8f8a0975f1a7..1dae317858e9 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_debug.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_debug.c @@ -575,9 +575,9 @@ int kfd_dbg_trap_set_flags(struct kfd_process *target, uint32_t *flags) continue; if (!pdd->dev->kfd->shared_resources.enable_mes) - debug_refresh_runlist(pdd->dev->dqm); + (void)debug_refresh_runlist(pdd->dev->dqm); else - kfd_dbg_set_mes_debug_mode(pdd, true); + (void)kfd_dbg_set_mes_debug_mode(pdd, true); } } @@ -637,9 +637,10 @@ void kfd_dbg_trap_deactivate(struct kfd_process *target, bool unwind, int unwind pr_err("Failed to release debug vmid on [%i]\n", pdd->dev->id); if (!pdd->dev->kfd->shared_resources.enable_mes) - debug_refresh_runlist(pdd->dev->dqm); + (void)debug_refresh_runlist(pdd->dev->dqm); else - kfd_dbg_set_mes_debug_mode(pdd, !kfd_dbg_has_cwsr_workaround(pdd->dev)); + (void)kfd_dbg_set_mes_debug_mode(pdd, + !kfd_dbg_has_cwsr_workaround(pdd->dev)); } kfd_dbg_set_workaround(target, false); From 6ba60345f45eaf7cb4f89105d26083a4b9fd1cba Mon Sep 17 00:00:00 2001 From: Harish Kasiviswanathan Date: Fri, 9 Jan 2026 15:26:36 -0500 Subject: [PATCH 30/51] drm/amdgpu: Fix double deletion of validate_list If amdgpu_amdkfd_gpuvm_free_memory_of_gpu() fails after kgd_mem is removed from validate_list, the mem handle still lingers in the KFD idr. This means when process is terminated, kfd_process_free_outstanding_kfd_bos() will call amdgpu_amdkfd_gpuvm_free_memory_of_gpu() again resulting in double deletion. To avoid this - (a) Check if list is empty before deleting it (b) Rearragne amdgpu_amdkfd_gpuvm_free_memory_of_gpu() such that it can be safely called again if it returns failure the first time. Signed-off-by: Harish Kasiviswanathan Reviewed-by: Philip Yang Signed-off-by: Alex Deucher --- .../gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index 768998c82b43..00ea69baa126 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -1924,21 +1924,21 @@ int amdgpu_amdkfd_gpuvm_free_memory_of_gpu( /* Make sure restore workers don't access the BO any more */ mutex_lock(&process_info->lock); - list_del(&mem->validate_list); + if (!list_empty(&mem->validate_list)) + list_del_init(&mem->validate_list); mutex_unlock(&process_info->lock); - /* Cleanup user pages and MMU notifiers */ - if (amdgpu_ttm_tt_get_usermm(mem->bo->tbo.ttm)) { - amdgpu_hmm_unregister(mem->bo); - mutex_lock(&process_info->notifier_lock); - amdgpu_hmm_range_free(mem->range); - mutex_unlock(&process_info->notifier_lock); - } - ret = reserve_bo_and_cond_vms(mem, NULL, BO_VM_ALL, &ctx); if (unlikely(ret)) return ret; + /* Cleanup user pages and MMU notifiers */ + if (amdgpu_ttm_tt_get_usermm(mem->bo->tbo.ttm)) { + amdgpu_hmm_unregister(mem->bo); + amdgpu_hmm_range_free(mem->range); + mem->range = NULL; + } + amdgpu_amdkfd_remove_eviction_fence(mem->bo, process_info->eviction_fence); pr_debug("Release VA 0x%llx - 0x%llx\n", mem->va, From 5006505b19a2119e71c008044d59f6d753c858b9 Mon Sep 17 00:00:00 2001 From: Melissa Wen Date: Thu, 22 Jan 2026 12:20:29 -0300 Subject: [PATCH 31/51] drm/amd/display: fix wrong color value mapping on MCM shaper LUT Some shimmer/colorful points appears when using the steamOS color pipeline for HDR on gaming with DCN32. These points look like black values being wrongly mapped to red/blue/green values. It was caused because the number of hw points in regular LUTs and in a shaper LUT was treated as the same. DCN3+ regular LUTs have 257 bases and implicit deltas (i.e. HW calculates them), but shaper LUT is a special case: it has 256 bases and 256 deltas, as in DCN1-2 regular LUTs, and outputs 14-bit values. Fix that by setting by decreasing in 1 the number of HW points computed in the LUT segmentation so that shaper LUT (i.e. fixpoint == true) keeps the same DCN10 CM logic and regular LUTs go with `hw_points + 1`. CC: Krunoslav Kovac Fixes: 4d5fd3d08ea9 ("drm/amd/display: PQ tail accuracy") Signed-off-by: Melissa Wen Reviewed-by: Alex Hung Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c index 0690c346f2c5..a4f14b16564c 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c @@ -163,6 +163,11 @@ bool cm3_helper_translate_curve_to_hw_format( hw_points += (1 << seg_distr[k]); } + // DCN3+ have 257 pts in lieu of no separate slope registers + // Prior HW had 256 base+slope pairs + // Shaper LUT (i.e. fixpoint == true) is still 256 bases and 256 deltas + hw_points = fixpoint ? (hw_points - 1) : hw_points; + j = 0; for (k = 0; k < (region_end - region_start); k++) { increment = NUMBER_SW_SEGMENTS / (1 << seg_distr[k]); @@ -223,8 +228,6 @@ bool cm3_helper_translate_curve_to_hw_format( corner_points[1].green.slope = dc_fixpt_zero; corner_points[1].blue.slope = dc_fixpt_zero; - // DCN3+ have 257 pts in lieu of no separate slope registers - // Prior HW had 256 base+slope pairs lut_params->hw_points_num = hw_points + 1; k = 0; From 0274a54897f356f9c78767c4a2a5863f7dde90c6 Mon Sep 17 00:00:00 2001 From: Melissa Wen Date: Mon, 8 Dec 2025 22:44:15 -0100 Subject: [PATCH 32/51] drm/amd/display: extend delta clamping logic to CM3 LUT helper Commit 27fc10d1095f ("drm/amd/display: Fix the delta clamping for shaper LUT") fixed banding when using plane shaper LUT in DCN10 CM helper. The problem is also present in DCN30 CM helper, fix banding by extending the same bug delta clamping fix to CM3. Signed-off-by: Melissa Wen Reviewed-by: Harry Wentland Signed-off-by: Alex Deucher --- .../amd/display/dc/dcn30/dcn30_cm_common.c | 30 +++++++++++++++---- .../display/dc/dwb/dcn30/dcn30_cm_common.h | 2 +- .../amd/display/dc/hwss/dcn30/dcn30_hwseq.c | 9 +++--- .../amd/display/dc/hwss/dcn32/dcn32_hwseq.c | 17 ++++++----- .../amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 16 +++++----- 5 files changed, 49 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c index a4f14b16564c..227aa8672d17 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c @@ -105,9 +105,12 @@ void cm_helper_program_gamcor_xfer_func( #define NUMBER_REGIONS 32 #define NUMBER_SW_SEGMENTS 16 -bool cm3_helper_translate_curve_to_hw_format( - const struct dc_transfer_func *output_tf, - struct pwl_params *lut_params, bool fixpoint) +#define DC_LOGGER \ + ctx->logger + +bool cm3_helper_translate_curve_to_hw_format(struct dc_context *ctx, + const struct dc_transfer_func *output_tf, + struct pwl_params *lut_params, bool fixpoint) { struct curve_points3 *corner_points; struct pwl_result_data *rgb_resulted; @@ -251,6 +254,10 @@ bool cm3_helper_translate_curve_to_hw_format( if (fixpoint == true) { i = 1; while (i != hw_points + 2) { + uint32_t red_clamp; + uint32_t green_clamp; + uint32_t blue_clamp; + if (i >= hw_points) { if (dc_fixpt_lt(rgb_plus_1->red, rgb->red)) rgb_plus_1->red = dc_fixpt_add(rgb->red, @@ -263,9 +270,20 @@ bool cm3_helper_translate_curve_to_hw_format( rgb_minus_1->delta_blue); } - rgb->delta_red_reg = dc_fixpt_clamp_u0d10(rgb->delta_red); - rgb->delta_green_reg = dc_fixpt_clamp_u0d10(rgb->delta_green); - rgb->delta_blue_reg = dc_fixpt_clamp_u0d10(rgb->delta_blue); + rgb->delta_red = dc_fixpt_sub(rgb_plus_1->red, rgb->red); + rgb->delta_green = dc_fixpt_sub(rgb_plus_1->green, rgb->green); + rgb->delta_blue = dc_fixpt_sub(rgb_plus_1->blue, rgb->blue); + + red_clamp = dc_fixpt_clamp_u0d14(rgb->delta_red); + green_clamp = dc_fixpt_clamp_u0d14(rgb->delta_green); + blue_clamp = dc_fixpt_clamp_u0d14(rgb->delta_blue); + + if (red_clamp >> 10 || green_clamp >> 10 || blue_clamp >> 10) + DC_LOG_ERROR("Losing delta precision while programming shaper LUT."); + + rgb->delta_red_reg = red_clamp & 0x3ff; + rgb->delta_green_reg = green_clamp & 0x3ff; + rgb->delta_blue_reg = blue_clamp & 0x3ff; rgb->red_reg = dc_fixpt_clamp_u0d14(rgb->red); rgb->green_reg = dc_fixpt_clamp_u0d14(rgb->green); rgb->blue_reg = dc_fixpt_clamp_u0d14(rgb->blue); diff --git a/drivers/gpu/drm/amd/display/dc/dwb/dcn30/dcn30_cm_common.h b/drivers/gpu/drm/amd/display/dc/dwb/dcn30/dcn30_cm_common.h index b86347c9b038..95f9318a54ef 100644 --- a/drivers/gpu/drm/amd/display/dc/dwb/dcn30/dcn30_cm_common.h +++ b/drivers/gpu/drm/amd/display/dc/dwb/dcn30/dcn30_cm_common.h @@ -59,7 +59,7 @@ void cm_helper_program_gamcor_xfer_func( const struct pwl_params *params, const struct dcn3_xfer_func_reg *reg); -bool cm3_helper_translate_curve_to_hw_format( +bool cm3_helper_translate_curve_to_hw_format(struct dc_context *ctx, const struct dc_transfer_func *output_tf, struct pwl_params *lut_params, bool fixpoint); diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c index d58f2cf2615c..d04cfd403b7e 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c @@ -241,7 +241,7 @@ bool dcn30_set_blend_lut( if (plane_state->blend_tf.type == TF_TYPE_HWPWL) blend_lut = &plane_state->blend_tf.pwl; else if (plane_state->blend_tf.type == TF_TYPE_DISTRIBUTED_POINTS) { - result = cm3_helper_translate_curve_to_hw_format( + result = cm3_helper_translate_curve_to_hw_format(plane_state->ctx, &plane_state->blend_tf, &dpp_base->regamma_params, false); if (!result) return result; @@ -336,8 +336,9 @@ bool dcn30_set_input_transfer_func(struct dc *dc, if (plane_state->in_transfer_func.type == TF_TYPE_HWPWL) params = &plane_state->in_transfer_func.pwl; else if (plane_state->in_transfer_func.type == TF_TYPE_DISTRIBUTED_POINTS && - cm3_helper_translate_curve_to_hw_format(&plane_state->in_transfer_func, - &dpp_base->degamma_params, false)) + cm3_helper_translate_curve_to_hw_format(plane_state->ctx, + &plane_state->in_transfer_func, + &dpp_base->degamma_params, false)) params = &dpp_base->degamma_params; result = dpp_base->funcs->dpp_program_gamcor_lut(dpp_base, params); @@ -408,7 +409,7 @@ bool dcn30_set_output_transfer_func(struct dc *dc, params = &stream->out_transfer_func.pwl; else if (pipe_ctx->stream->out_transfer_func.type == TF_TYPE_DISTRIBUTED_POINTS && - cm3_helper_translate_curve_to_hw_format( + cm3_helper_translate_curve_to_hw_format(stream->ctx, &stream->out_transfer_func, &mpc->blender_params, false)) params = &mpc->blender_params; diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c index 37300e12e645..1be121349672 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c @@ -493,8 +493,9 @@ bool dcn32_set_mcm_luts( if (plane_state->blend_tf.type == TF_TYPE_HWPWL) lut_params = &plane_state->blend_tf.pwl; else if (plane_state->blend_tf.type == TF_TYPE_DISTRIBUTED_POINTS) { - result = cm3_helper_translate_curve_to_hw_format(&plane_state->blend_tf, - &dpp_base->regamma_params, false); + result = cm3_helper_translate_curve_to_hw_format(plane_state->ctx, + &plane_state->blend_tf, + &dpp_base->regamma_params, false); if (!result) return result; @@ -509,8 +510,9 @@ bool dcn32_set_mcm_luts( else if (plane_state->in_shaper_func.type == TF_TYPE_DISTRIBUTED_POINTS) { // TODO: dpp_base replace ASSERT(false); - cm3_helper_translate_curve_to_hw_format(&plane_state->in_shaper_func, - &dpp_base->shaper_params, true); + cm3_helper_translate_curve_to_hw_format(plane_state->ctx, + &plane_state->in_shaper_func, + &dpp_base->shaper_params, true); lut_params = &dpp_base->shaper_params; } @@ -550,8 +552,9 @@ bool dcn32_set_input_transfer_func(struct dc *dc, if (plane_state->in_transfer_func.type == TF_TYPE_HWPWL) params = &plane_state->in_transfer_func.pwl; else if (plane_state->in_transfer_func.type == TF_TYPE_DISTRIBUTED_POINTS && - cm3_helper_translate_curve_to_hw_format(&plane_state->in_transfer_func, - &dpp_base->degamma_params, false)) + cm3_helper_translate_curve_to_hw_format(plane_state->ctx, + &plane_state->in_transfer_func, + &dpp_base->degamma_params, false)) params = &dpp_base->degamma_params; dpp_base->funcs->dpp_program_gamcor_lut(dpp_base, params); @@ -582,7 +585,7 @@ bool dcn32_set_output_transfer_func(struct dc *dc, params = &stream->out_transfer_func.pwl; else if (pipe_ctx->stream->out_transfer_func.type == TF_TYPE_DISTRIBUTED_POINTS && - cm3_helper_translate_curve_to_hw_format( + cm3_helper_translate_curve_to_hw_format(stream->ctx, &stream->out_transfer_func, &mpc->blender_params, false)) params = &mpc->blender_params; 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 9cda39d0ed95..b91517b9fedc 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 @@ -432,7 +432,7 @@ void dcn401_populate_mcm_luts(struct dc *dc, if (mcm_luts.lut1d_func->type == TF_TYPE_HWPWL) m_lut_params.pwl = &mcm_luts.lut1d_func->pwl; else if (mcm_luts.lut1d_func->type == TF_TYPE_DISTRIBUTED_POINTS) { - rval = cm3_helper_translate_curve_to_hw_format( + rval = cm3_helper_translate_curve_to_hw_format(mpc->ctx, mcm_luts.lut1d_func, &dpp_base->regamma_params, false); m_lut_params.pwl = rval ? &dpp_base->regamma_params : NULL; @@ -452,7 +452,7 @@ void dcn401_populate_mcm_luts(struct dc *dc, m_lut_params.pwl = &mcm_luts.shaper->pwl; else if (mcm_luts.shaper->type == TF_TYPE_DISTRIBUTED_POINTS) { ASSERT(false); - rval = cm3_helper_translate_curve_to_hw_format( + rval = cm3_helper_translate_curve_to_hw_format(mpc->ctx, mcm_luts.shaper, &dpp_base->regamma_params, true); m_lut_params.pwl = rval ? &dpp_base->regamma_params : NULL; @@ -629,8 +629,9 @@ bool dcn401_set_mcm_luts(struct pipe_ctx *pipe_ctx, if (plane_state->blend_tf.type == TF_TYPE_HWPWL) lut_params = &plane_state->blend_tf.pwl; else if (plane_state->blend_tf.type == TF_TYPE_DISTRIBUTED_POINTS) { - rval = cm3_helper_translate_curve_to_hw_format(&plane_state->blend_tf, - &dpp_base->regamma_params, false); + rval = cm3_helper_translate_curve_to_hw_format(plane_state->ctx, + &plane_state->blend_tf, + &dpp_base->regamma_params, false); lut_params = rval ? &dpp_base->regamma_params : NULL; } result = mpc->funcs->program_1dlut(mpc, lut_params, mpcc_id); @@ -641,8 +642,9 @@ bool dcn401_set_mcm_luts(struct pipe_ctx *pipe_ctx, lut_params = &plane_state->in_shaper_func.pwl; else if (plane_state->in_shaper_func.type == TF_TYPE_DISTRIBUTED_POINTS) { // TODO: dpp_base replace - rval = cm3_helper_translate_curve_to_hw_format(&plane_state->in_shaper_func, - &dpp_base->shaper_params, true); + rval = cm3_helper_translate_curve_to_hw_format(plane_state->ctx, + &plane_state->in_shaper_func, + &dpp_base->shaper_params, true); lut_params = rval ? &dpp_base->shaper_params : NULL; } result &= mpc->funcs->program_shaper(mpc, lut_params, mpcc_id); @@ -676,7 +678,7 @@ bool dcn401_set_output_transfer_func(struct dc *dc, params = &stream->out_transfer_func.pwl; else if (pipe_ctx->stream->out_transfer_func.type == TF_TYPE_DISTRIBUTED_POINTS && - cm3_helper_translate_curve_to_hw_format( + cm3_helper_translate_curve_to_hw_format(stream->ctx, &stream->out_transfer_func, &mpc->blender_params, false)) params = &mpc->blender_params; From 1714dcc4c2c53e41190896eba263ed6328bcf415 Mon Sep 17 00:00:00 2001 From: Melissa Wen Date: Fri, 16 Jan 2026 12:50:49 -0300 Subject: [PATCH 33/51] drm/amd/display: remove assert around dpp_base replacement There is nothing wrong if in_shaper_func type is DISTRIBUTED POINTS. Remove the assert placed for a TODO to avoid misinterpretations. Signed-off-by: Melissa Wen Reviewed-by: Alex Hung Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c index 1be121349672..2767d3a97812 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c @@ -509,7 +509,6 @@ bool dcn32_set_mcm_luts( lut_params = &plane_state->in_shaper_func.pwl; else if (plane_state->in_shaper_func.type == TF_TYPE_DISTRIBUTED_POINTS) { // TODO: dpp_base replace - ASSERT(false); cm3_helper_translate_curve_to_hw_format(plane_state->ctx, &plane_state->in_shaper_func, &dpp_base->shaper_params, true); From 8980be03b3f9a4b58197ef95d3b37efa41a25331 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Thu, 22 Jan 2026 12:11:49 +0530 Subject: [PATCH 34/51] drm/amdgpu: Skip vcn poison irq release on VF VF doesn't enable VCN poison irq in VCNv2.5. Skip releasing it and avoid call trace during deinitialization. [ 71.913601] [drm] clean up the vf2pf work item [ 71.915088] ------------[ cut here ]------------ [ 71.915092] WARNING: CPU: 3 PID: 1079 at /tmp/amd.aFkFvSQl/amd/amdgpu/amdgpu_irq.c:641 amdgpu_irq_put+0xc6/0xe0 [amdgpu] [ 71.915355] Modules linked in: amdgpu(OE-) amddrm_ttm_helper(OE) amdttm(OE) amddrm_buddy(OE) amdxcp(OE) amddrm_exec(OE) amd_sched(OE) amdkcl(OE) drm_suballoc_helper drm_display_helper cec rc_core i2c_algo_bit video wmi binfmt_misc nls_iso8859_1 intel_rapl_msr intel_rapl_common input_leds joydev serio_raw mac_hid qemu_fw_cfg sch_fq_codel dm_multipath scsi_dh_rdac scsi_dh_emc scsi_dh_alua efi_pstore ip_tables x_tables autofs4 btrfs blake2b_generic raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx xor raid6_pq libcrc32c raid1 raid0 hid_generic crct10dif_pclmul crc32_pclmul polyval_clmulni polyval_generic ghash_clmulni_intel usbhid 8139too sha256_ssse3 sha1_ssse3 hid psmouse bochs i2c_i801 ahci drm_vram_helper libahci i2c_smbus lpc_ich drm_ttm_helper 8139cp mii ttm aesni_intel crypto_simd cryptd [ 71.915484] CPU: 3 PID: 1079 Comm: rmmod Tainted: G OE 6.8.0-87-generic #88~22.04.1-Ubuntu [ 71.915489] Hardware name: Red Hat KVM/RHEL, BIOS 1.16.3-2.el9_5.1 04/01/2014 [ 71.915492] RIP: 0010:amdgpu_irq_put+0xc6/0xe0 [amdgpu] [ 71.915768] Code: 75 84 b8 ea ff ff ff eb d4 44 89 ea 48 89 de 4c 89 e7 e8 fd fc ff ff 5b 41 5c 41 5d 41 5e 5d 31 d2 31 f6 31 ff e9 55 30 3b c7 <0f> 0b eb d4 b8 fe ff ff ff eb a8 e9 b7 3b 8a 00 66 2e 0f 1f 84 00 [ 71.915771] RSP: 0018:ffffcf0800eafa30 EFLAGS: 00010246 [ 71.915775] RAX: 0000000000000000 RBX: ffff891bda4b0668 RCX: 0000000000000000 [ 71.915777] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 [ 71.915779] RBP: ffffcf0800eafa50 R08: 0000000000000000 R09: 0000000000000000 [ 71.915781] R10: 0000000000000000 R11: 0000000000000000 R12: ffff891bda480000 [ 71.915782] R13: 0000000000000000 R14: 0000000000000001 R15: 0000000000000000 [ 71.915792] FS: 000070cff87c4c40(0000) GS:ffff893abfb80000(0000) knlGS:0000000000000000 [ 71.915795] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 71.915797] CR2: 00005fa13073e478 CR3: 000000010d634006 CR4: 0000000000770ef0 [ 71.915800] PKRU: 55555554 [ 71.915802] Call Trace: [ 71.915805] [ 71.915809] vcn_v2_5_hw_fini+0x19e/0x1e0 [amdgpu] Signed-off-by: Lijo Lazar Reviewed-by: Mangesh Gadre Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c index cebee453871c..006a15451197 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c @@ -521,7 +521,9 @@ static int vcn_v2_5_hw_fini(struct amdgpu_ip_block *ip_block) RREG32_SOC15(VCN, i, mmUVD_STATUS))) vinst->set_pg_state(vinst, AMD_PG_STATE_GATE); - if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__VCN)) + /* VF doesn't enable interrupt operations for RAS */ + if (!amdgpu_sriov_vf(adev) && + amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__VCN)) amdgpu_irq_put(adev, &vinst->ras_poison_irq, 0); } From d6e04d2e675fefcb24cc8ba3b72a4adf98dabdb2 Mon Sep 17 00:00:00 2001 From: Lijo Lazar Date: Fri, 30 Jan 2026 15:44:28 +0530 Subject: [PATCH 35/51] drm/amd/pm: Remove buffer allocation in SMUv13.0.6 No longer required to allocate temporary buffer while fetching metrcis, instead, use metrics table cache data directly. Signed-off-by: Lijo Lazar Reviewed-by: Asad Kamal Signed-off-by: Alex Deucher --- .../drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) 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 be7d77eee2b0..3a9210083ce3 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 @@ -2564,9 +2564,10 @@ static ssize_t smu_v13_0_6_get_xcp_metrics(struct smu_context *smu, int xcp_id, const u8 num_jpeg_rings = AMDGPU_MAX_JPEG_RINGS_4_0_3; int version = smu_v13_0_6_get_metrics_version(smu); struct smu_v13_0_6_partition_metrics *xcp_metrics; - MetricsTableV0_t *metrics_v0 __free(kfree) = NULL; + struct smu_table_context *smu_table = &smu->smu_table; struct amdgpu_device *adev = smu->adev; int ret, inst, i, j, k, idx; + MetricsTableV0_t *metrics_v0; MetricsTableV1_t *metrics_v1; MetricsTableV2_t *metrics_v2; struct amdgpu_xcp *xcp; @@ -2586,22 +2587,20 @@ static ssize_t smu_v13_0_6_get_xcp_metrics(struct smu_context *smu, int xcp_id, xcp_metrics = (struct smu_v13_0_6_partition_metrics *)table; smu_v13_0_6_partition_metrics_init(xcp_metrics, 1, 1); - metrics_v0 = kzalloc(METRICS_TABLE_SIZE, GFP_KERNEL); - if (!metrics_v0) - return -ENOMEM; - - ret = smu_v13_0_6_get_metrics_table(smu, metrics_v0, false); + ret = smu_v13_0_6_get_metrics_table(smu, NULL, false); if (ret) return ret; + metrics_v0 = (MetricsTableV0_t *)smu_table->metrics_table; + if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 12) && smu_v13_0_6_cap_supported(smu, SMU_CAP(STATIC_METRICS))) return smu_v13_0_12_get_xcp_metrics(smu, xcp, table, metrics_v0); - metrics_v1 = (MetricsTableV1_t *)metrics_v0; - metrics_v2 = (MetricsTableV2_t *)metrics_v0; + metrics_v1 = (MetricsTableV1_t *)smu_table->metrics_table; + metrics_v2 = (MetricsTableV2_t *)smu_table->metrics_table; per_inst = smu_v13_0_6_cap_supported(smu, SMU_CAP(PER_INST_METRICS)); @@ -2677,21 +2676,21 @@ static ssize_t smu_v13_0_6_get_gpu_metrics(struct smu_context *smu, void **table { struct smu_v13_0_6_gpu_metrics *gpu_metrics; int version = smu_v13_0_6_get_metrics_version(smu); - MetricsTableV0_t *metrics_v0 __free(kfree) = NULL; + struct smu_table_context *smu_table = &smu->smu_table; struct amdgpu_device *adev = smu->adev; int ret = 0, xcc_id, inst, i, j; + MetricsTableV0_t *metrics_v0; MetricsTableV1_t *metrics_v1; MetricsTableV2_t *metrics_v2; u16 link_width_level; u8 num_jpeg_rings; bool per_inst; - metrics_v0 = kzalloc(METRICS_TABLE_SIZE, GFP_KERNEL); - ret = smu_v13_0_6_get_metrics_table(smu, metrics_v0, false); + ret = smu_v13_0_6_get_metrics_table(smu, NULL, false); if (ret) return ret; - metrics_v2 = (MetricsTableV2_t *)metrics_v0; + metrics_v0 = (MetricsTableV0_t *)smu_table->metrics_table; gpu_metrics = (struct smu_v13_0_6_gpu_metrics *)smu_driver_table_ptr( smu, SMU_DRIVER_TABLE_GPU_METRICS); @@ -2702,8 +2701,8 @@ static ssize_t smu_v13_0_6_get_gpu_metrics(struct smu_context *smu, void **table goto fill; } - metrics_v1 = (MetricsTableV1_t *)metrics_v0; - metrics_v2 = (MetricsTableV2_t *)metrics_v0; + metrics_v1 = (MetricsTableV1_t *)smu_table->metrics_table; + metrics_v2 = (MetricsTableV2_t *)smu_table->metrics_table; gpu_metrics->temperature_hotspot = SMUQ10_ROUND(GET_METRIC_FIELD(MaxSocketTemperature, version)); From c40c94693c87e092fea94fe8cbd751d216511793 Mon Sep 17 00:00:00 2001 From: "Stanley.Yang" Date: Fri, 23 Jan 2026 19:58:29 +0800 Subject: [PATCH 36/51] drm/amd/ras: statistic xgmi training error count Report xgmi training error uncorrectable error count. Signed-off-by: Stanley.Yang Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/ras/rascore/ras_aca_v1_0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/ras/rascore/ras_aca_v1_0.c b/drivers/gpu/drm/amd/ras/rascore/ras_aca_v1_0.c index 29df98948703..210fbd8851a6 100644 --- a/drivers/gpu/drm/amd/ras/rascore/ras_aca_v1_0.c +++ b/drivers/gpu/drm/amd/ras/rascore/ras_aca_v1_0.c @@ -299,7 +299,7 @@ static int aca_parse_xgmi_bank(struct ras_core_context *ras_core, count = ACA_REG_MISC0_ERRCNT(bank->regs[ACA_REG_IDX__MISC0]); if (bank->ecc_type == RAS_ERR_TYPE__UE) { - if (ext_error_code != 0 && ext_error_code != 9) + if (ext_error_code != 0 && ext_error_code != 1 && ext_error_code != 9) count = 0ULL; ecc->ue_count = count; } else if (bank->ecc_type == RAS_ERR_TYPE__CE) { From c9be63d565789b56ca7b0197e2cb78a3671f95a8 Mon Sep 17 00:00:00 2001 From: Zilin Guan Date: Thu, 29 Jan 2026 09:25:32 +0000 Subject: [PATCH 37/51] drm/amdgpu: Fix memory leak in amdgpu_acpi_enumerate_xcc() In amdgpu_acpi_enumerate_xcc(), if amdgpu_acpi_dev_init() returns -ENOMEM, the function returns directly without releasing the allocated xcc_info, resulting in a memory leak. Fix this by ensuring that xcc_info is properly freed in the error paths. Compile tested only. Issue found using a prototype static analysis tool and code review. Fixes: 4d5275ab0b18 ("drm/amdgpu: Add parsing of acpi xcc objects") Reviewed-by: Lijo Lazar Signed-off-by: Zilin Guan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c index c126d1bf2bc8..02d5abf9df2b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c @@ -1186,8 +1186,10 @@ int amdgpu_acpi_enumerate_xcc(void) if (!dev_info) ret = amdgpu_acpi_dev_init(&dev_info, xcc_info, sbdf); - if (ret == -ENOMEM) + if (ret == -ENOMEM) { + kfree(xcc_info); return ret; + } if (!dev_info) { kfree(xcc_info); From 0c44d61945c4a80775292d96460aa2f22e62f86c Mon Sep 17 00:00:00 2001 From: Zilin Guan Date: Thu, 29 Jan 2026 09:05:42 +0000 Subject: [PATCH 38/51] drm/amdgpu: Use kvfree instead of kfree in amdgpu_gmc_get_nps_memranges() amdgpu_discovery_get_nps_info() internally allocates memory for ranges using kvcalloc(), which may use vmalloc() for large allocation. Using kfree() to release vmalloc memory will lead to a memory corruption. Use kvfree() to safely handle both kmalloc and vmalloc allocations. Compile tested only. Issue found using a prototype static analysis tool and code review. Fixes: b194d21b9bcc ("drm/amdgpu: Use NPS ranges from discovery table") Reviewed-by: Lijo Lazar Signed-off-by: Zilin Guan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c index b793ce17140c..d35d9719d566 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c @@ -1436,7 +1436,7 @@ int amdgpu_gmc_get_nps_memranges(struct amdgpu_device *adev, if (!*exp_ranges) *exp_ranges = range_cnt; err: - kfree(ranges); + kvfree(ranges); return ret; } From ee41e5b63c8210525c936ee637a2c8d185ce873c Mon Sep 17 00:00:00 2001 From: Zilin Guan Date: Thu, 29 Jan 2026 08:35:15 +0000 Subject: [PATCH 39/51] drm/amdgpu: Fix memory leak in amdgpu_ras_init() When amdgpu_nbio_ras_sw_init() fails in amdgpu_ras_init(), the function returns directly without freeing the allocated con structure, leading to a memory leak. Fix this by jumping to the release_con label to properly clean up the allocated memory before returning the error code. Compile tested only. Issue found using a prototype static analysis tool and code review. Fixes: fdc94d3a8c88 ("drm/amdgpu: Rework pcie_bif ras sw_init") Reviewed-by: Tao Zhou Signed-off-by: Zilin Guan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index f582113d78b7..b28fcf932f7e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -4352,7 +4352,7 @@ int amdgpu_ras_init(struct amdgpu_device *adev) * to handle fatal error */ r = amdgpu_nbio_ras_sw_init(adev); if (r) - return r; + goto release_con; if (adev->nbio.ras && adev->nbio.ras->init_ras_controller_interrupt) { From 46a2cb7d24f21132e970cab52359210c3f5ea3c6 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 3 Feb 2026 11:51:45 -0500 Subject: [PATCH 40/51] drm/amdgpu/sdma5: enable queue resets unconditionally There is no firmware version dependency. Fixes: 59fd50b8663b ("drm/amdgpu: Add sysfs interface for sdma reset mask") Cc: Jesse Zhang Reviewed-by: Jesse.Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c index e77e079fe833..e3a035c9fece 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c @@ -1424,18 +1424,9 @@ static int sdma_v5_0_sw_init(struct amdgpu_ip_block *ip_block) adev->sdma.supported_reset = amdgpu_get_soft_full_reset_mask(&adev->sdma.instance[0].ring); - switch (amdgpu_ip_version(adev, SDMA0_HWIP, 0)) { - case IP_VERSION(5, 0, 0): - case IP_VERSION(5, 0, 2): - case IP_VERSION(5, 0, 5): - if ((adev->sdma.instance[0].fw_version >= 35) && - !amdgpu_sriov_vf(adev) && - !adev->debug_disable_gpu_ring_reset) - adev->sdma.supported_reset |= AMDGPU_RESET_TYPE_PER_QUEUE; - break; - default: - break; - } + if (!amdgpu_sriov_vf(adev) && + !adev->debug_disable_gpu_ring_reset) + adev->sdma.supported_reset |= AMDGPU_RESET_TYPE_PER_QUEUE; /* Allocate memory for SDMA IP Dump buffer */ ptr = kcalloc(adev->sdma.num_instances * reg_count, sizeof(uint32_t), GFP_KERNEL); From 314d30ad50622fc0d70da71509f9dff21545be14 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 3 Feb 2026 11:52:46 -0500 Subject: [PATCH 41/51] drm/amdgpu/sdma5.2: enable queue resets unconditionally There is no firmware version dependency. This also enables sdma queue resets on all SDMA 5.2.x based chips. Fixes: 59fd50b8663b ("drm/amdgpu: Add sysfs interface for sdma reset mask") Cc: Jesse Zhang Reviewed-by: Jesse.Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c b/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c index 50b51965c211..feebaa8cd9b1 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c @@ -1342,25 +1342,9 @@ static int sdma_v5_2_sw_init(struct amdgpu_ip_block *ip_block) adev->sdma.supported_reset = amdgpu_get_soft_full_reset_mask(&adev->sdma.instance[0].ring); - switch (amdgpu_ip_version(adev, SDMA0_HWIP, 0)) { - case IP_VERSION(5, 2, 0): - case IP_VERSION(5, 2, 2): - case IP_VERSION(5, 2, 3): - case IP_VERSION(5, 2, 4): - if ((adev->sdma.instance[0].fw_version >= 76) && - !amdgpu_sriov_vf(adev) && - !adev->debug_disable_gpu_ring_reset) - adev->sdma.supported_reset |= AMDGPU_RESET_TYPE_PER_QUEUE; - break; - case IP_VERSION(5, 2, 5): - if ((adev->sdma.instance[0].fw_version >= 34) && - !amdgpu_sriov_vf(adev) && - !adev->debug_disable_gpu_ring_reset) - adev->sdma.supported_reset |= AMDGPU_RESET_TYPE_PER_QUEUE; - break; - default: - break; - } + if (!amdgpu_sriov_vf(adev) && + !adev->debug_disable_gpu_ring_reset) + adev->sdma.supported_reset |= AMDGPU_RESET_TYPE_PER_QUEUE; /* Allocate memory for SDMA IP Dump buffer */ ptr = kcalloc(adev->sdma.num_instances * reg_count, sizeof(uint32_t), GFP_KERNEL); From 56423871e9eef1dd069bddef895207fa5ce275fe Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 3 Feb 2026 11:53:51 -0500 Subject: [PATCH 42/51] drm/amdgpu/sdma6: enable queue resets unconditionally There is no firmware version dependency. This also enables sdma queue resets on all SDMA 6.x based chips. Fixes: 59fd50b8663b ("drm/amdgpu: Add sysfs interface for sdma reset mask") Cc: Jesse Zhang Reviewed-by: Jesse.Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c index eec659194718..b40126f5d3ef 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c @@ -1364,18 +1364,9 @@ static int sdma_v6_0_sw_init(struct amdgpu_ip_block *ip_block) adev->sdma.supported_reset = amdgpu_get_soft_full_reset_mask(&adev->sdma.instance[0].ring); - switch (amdgpu_ip_version(adev, SDMA0_HWIP, 0)) { - case IP_VERSION(6, 0, 0): - case IP_VERSION(6, 0, 2): - case IP_VERSION(6, 0, 3): - if ((adev->sdma.instance[0].fw_version >= 21) && - !amdgpu_sriov_vf(adev) && - !adev->debug_disable_gpu_ring_reset) - adev->sdma.supported_reset |= AMDGPU_RESET_TYPE_PER_QUEUE; - break; - default: - break; - } + if (!amdgpu_sriov_vf(adev) && + !adev->debug_disable_gpu_ring_reset) + adev->sdma.supported_reset |= AMDGPU_RESET_TYPE_PER_QUEUE; if (amdgpu_sdma_ras_sw_init(adev)) { dev_err(adev->dev, "Failed to initialize sdma ras block!\n"); From 8a70a26c9f34baea6c3199a9862ddaff4554a96d Mon Sep 17 00:00:00 2001 From: Sunday Clement Date: Mon, 2 Feb 2026 12:41:39 -0500 Subject: [PATCH 43/51] drm/amdkfd: Fix out-of-bounds write in kfd_event_page_set() The kfd_event_page_set() function writes KFD_SIGNAL_EVENT_LIMIT * 8 bytes via memset without checking the buffer size parameter. This allows unprivileged userspace to trigger an out-of bounds kernel memory write by passing a small buffer, leading to potential privilege escalation. Signed-off-by: Sunday Clement Reviewed-by: Alexander Deucher Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdkfd/kfd_events.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_events.c index 1ad312af8ff0..13416bff7763 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_events.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_events.c @@ -331,6 +331,12 @@ static int kfd_event_page_set(struct kfd_process *p, void *kernel_address, if (p->signal_page) return -EBUSY; + if (size < KFD_SIGNAL_EVENT_LIMIT * 8) { + pr_err("Event page size %llu is too small, need at least %lu bytes\n", + size, (unsigned long)(KFD_SIGNAL_EVENT_LIMIT * 8)); + return -EINVAL; + } + page = kzalloc(sizeof(*page), GFP_KERNEL); if (!page) return -ENOMEM; From 39fc2bc4da0082c226cbee331f0a5d44db3997da Mon Sep 17 00:00:00 2001 From: Yifan Zhang Date: Mon, 2 Feb 2026 13:17:39 +0800 Subject: [PATCH 44/51] drm/amdgpu: Protect GPU register accesses in powergated state in some paths Ungate GPU CG/PG in device_fini_hw and device_halt to protect GPU register accesses, e.g. GC registers are accessed in amdgpu_irq_disable_all() and amdgpu_fence_driver_hw_fini(). Signed-off-by: Yifan Zhang Acked-by: Alex Deucher Reviewed-by: Lijo Lazar Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index c1ffc63e23ab..528990a595ec 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -3504,9 +3504,6 @@ static int amdgpu_device_ip_fini_early(struct amdgpu_device *adev) } } - amdgpu_device_set_pg_state(adev, AMD_PG_STATE_UNGATE); - amdgpu_device_set_cg_state(adev, AMD_CG_STATE_UNGATE); - amdgpu_amdkfd_suspend(adev, true); amdgpu_amdkfd_teardown_processes(adev); amdgpu_userq_suspend(adev); @@ -4902,6 +4899,9 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev) amdgpu_virt_fini_data_exchange(adev); } + amdgpu_device_set_pg_state(adev, AMD_PG_STATE_UNGATE); + amdgpu_device_set_cg_state(adev, AMD_CG_STATE_UNGATE); + /* disable all interrupts */ amdgpu_irq_disable_all(adev); if (adev->mode_info.mode_config_initialized) { @@ -7360,6 +7360,9 @@ void amdgpu_device_halt(struct amdgpu_device *adev) amdgpu_xcp_dev_unplug(adev); drm_dev_unplug(ddev); + amdgpu_device_set_pg_state(adev, AMD_PG_STATE_UNGATE); + amdgpu_device_set_cg_state(adev, AMD_CG_STATE_UNGATE); + amdgpu_irq_disable_all(adev); amdgpu_fence_driver_hw_fini(adev); From ff205dc95a897b4b8c093b665702e83bffd04dc9 Mon Sep 17 00:00:00 2001 From: Melissa Wen Date: Tue, 9 Dec 2025 12:09:06 -0300 Subject: [PATCH 45/51] drm/amd/display: expose plane blend LUT in HW with MCM Since commit 39923050615cd ("drm/amd/display: Clear DPP 3DLUT Cap") there is a flag in the mpc_color_caps that indicates the pre-blend usage of MPC color caps. Do the same as commit 9e5d4a5e27c6 ("drm/amd/display: Use mpc.preblend flag to indicate preblend") and use the mpc.preblend flag to expose plane blend LUT/TF properties on AMD display driver. CC: Matthew Schwartz Signed-off-by: Melissa Wen Tested-by: Matthew Schwartz Reviewed-by: Alex Hung Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c index d3e62f511c8f..ce56734c09b8 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c @@ -1650,7 +1650,7 @@ dm_atomic_plane_attach_color_mgmt_properties(struct amdgpu_display_manager *dm, MAX_COLOR_3DLUT_SIZE); } - if (dpp_color_caps.ogam_ram) { + if (dpp_color_caps.ogam_ram || dm->dc->caps.color.mpc.preblend) { drm_object_attach_property(&plane->base, mode_info.plane_blend_lut_property, 0); drm_object_attach_property(&plane->base, From 3b948dd0366a0b64c02e4ed1aefdf7825942e803 Mon Sep 17 00:00:00 2001 From: Philip Yang Date: Tue, 27 Jan 2026 13:52:33 -0500 Subject: [PATCH 46/51] drm/amdgpu: Use 5-level paging if gmc support 57-bit VA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Regardless if CPU enable 5-level paging, GPU vm use 5-level paging if gmc init with 57-bit address space support, because ARM64 4-level paging support 48-bit VA, x86 and GPU 4-level paging support 47-bit VA, require 5-level paging on GPU to support ARM64. NPA address space 52-bit mapping on NPA GPU VM require 5-level paging. Debugger trap get device snapshot expect LDS and Scratch base, limit above 57-bit, which is set only for 5-level paging. Signed-off-by: Philip Yang Reviewed-by: Christian König Acked-by: Alex Deucher Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org # 6.19.x --- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 6a2ea200d90c..31383583fc68 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -2360,26 +2360,9 @@ void amdgpu_vm_adjust_size(struct amdgpu_device *adev, uint32_t min_vm_size, unsigned max_bits) { unsigned int max_size = 1 << (max_bits - 30); - bool sys_5level_pgtable = false; unsigned int vm_size; uint64_t tmp; -#ifdef CONFIG_X86_64 - /* - * Refer to function configure_5level_paging() for details. - */ - sys_5level_pgtable = (native_read_cr4() & X86_CR4_LA57); -#endif - - /* - * If GPU supports 5-level page table, but system uses 4-level page table, - * then use 4-level page table on GPU - */ - if (max_level == 4 && !sys_5level_pgtable) { - min_vm_size = 256 * 1024; - max_level = 3; - } - /* adjust vm size first */ if (amdgpu_vm_size != -1) { vm_size = amdgpu_vm_size; From f025a2b8d93358467b8e8f4b3a617e88c5f02fab Mon Sep 17 00:00:00 2001 From: Sunil Khatri Date: Tue, 3 Feb 2026 12:09:05 +0530 Subject: [PATCH 47/51] drm/amdgpu: clean up the amdgpu_cs_parser_bos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In low memory conditions, kmalloc can fail. In such conditions unlock the mutex for a clean exit. We do not need to amdgpu_bo_list_put as it's been handled in the amdgpu_cs_parser_fini. Fixes: 737da5363cc0 ("drm/amdgpu: update the functions to use amdgpu version of hmm") Reported-by: kernel test robot Reported-by: Dan Carpenter Closes: https://lore.kernel.org/r/202602030017.7E0xShmH-lkp@intel.com/ Signed-off-by: Sunil Khatri Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index d591dce0f3b3..f3b5bcdbf2ae 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -892,8 +892,10 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, struct amdgpu_bo *bo = e->bo; e->range = amdgpu_hmm_range_alloc(NULL); - if (unlikely(!e->range)) - return -ENOMEM; + if (unlikely(!e->range)) { + r = -ENOMEM; + goto out_free_user_pages; + } r = amdgpu_ttm_tt_get_user_pages(bo, e->range); if (r) From 5cc7bbd9f1b74d9fe2f7ac08d6ba0477e8d2d65f Mon Sep 17 00:00:00 2001 From: Victor Zhao Date: Wed, 4 Feb 2026 23:15:04 +0800 Subject: [PATCH 48/51] drm/amdgpu: avoid sdma ring reset in sriov sdma ring reset is not supported in SRIOV. kfd driver does not check reset mask, and could queue sdma ring reset during unmap_queues_cpsch. Avoid the ring reset for sriov. Signed-off-by: Victor Zhao Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c index 8b8a04138711..321310ba2c08 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c @@ -558,6 +558,9 @@ int amdgpu_sdma_reset_engine(struct amdgpu_device *adev, uint32_t instance_id, struct amdgpu_ring *gfx_ring = &sdma_instance->ring; struct amdgpu_ring *page_ring = &sdma_instance->page; + if (amdgpu_sriov_vf(adev)) + return -EOPNOTSUPP; + mutex_lock(&sdma_instance->engine_reset_mutex); if (!caller_handles_kernel_queues) { From 6952255ed97914abbf86fc3f92c9918945b885b8 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 30 Jan 2026 11:19:49 -0500 Subject: [PATCH 49/51] drm/amdgpu: re-add the bad job to the pending list for ring resets Returning DRM_GPU_SCHED_STAT_NO_HANG causes the scheduler to add the bad job back the pending list. We've already set the errors on the fence and killed the bad job at this point so it's the correct behavior. Acked-by: Pierre-Eric Pelloux-Prayer Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 9 ++++++++- drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c | 4 ---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c index aaf5477fcd7a..2c82d9e8c0be 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c @@ -92,6 +92,7 @@ static enum drm_gpu_sched_stat amdgpu_job_timedout(struct drm_sched_job *s_job) struct drm_wedge_task_info *info = NULL; struct amdgpu_task_info *ti = NULL; struct amdgpu_device *adev = ring->adev; + enum drm_gpu_sched_stat status = DRM_GPU_SCHED_STAT_RESET; int idx, r; if (!drm_dev_enter(adev_to_drm(adev), &idx)) { @@ -135,13 +136,19 @@ static enum drm_gpu_sched_stat amdgpu_job_timedout(struct drm_sched_job *s_job) ring->funcs->reset) { dev_err(adev->dev, "Starting %s ring reset\n", s_job->sched->name); + /* Stop the scheduler to prevent anybody else from touching the ring buffer. */ + drm_sched_wqueue_stop(&ring->sched); r = amdgpu_ring_reset(ring, job->vmid, job->hw_fence); if (!r) { + /* Start the scheduler again */ + drm_sched_wqueue_start(&ring->sched); atomic_inc(&ring->adev->gpu_reset_counter); dev_err(adev->dev, "Ring %s reset succeeded\n", ring->sched.name); drm_dev_wedged_event(adev_to_drm(adev), DRM_WEDGE_RECOVERY_NONE, info); + /* This is needed to add the job back to the pending list */ + status = DRM_GPU_SCHED_STAT_NO_HANG; goto exit; } dev_err(adev->dev, "Ring %s reset failed\n", ring->sched.name); @@ -177,7 +184,7 @@ static enum drm_gpu_sched_stat amdgpu_job_timedout(struct drm_sched_job *s_job) exit: amdgpu_vm_put_task_info(ti); drm_dev_exit(idx); - return DRM_GPU_SCHED_STAT_RESET; + return status; } int amdgpu_job_alloc(struct amdgpu_device *adev, struct amdgpu_vm *vm, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c index b82357c65723..129ad5138653 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c @@ -868,8 +868,6 @@ bool amdgpu_ring_sched_ready(struct amdgpu_ring *ring) void amdgpu_ring_reset_helper_begin(struct amdgpu_ring *ring, struct amdgpu_fence *guilty_fence) { - /* Stop the scheduler to prevent anybody else from touching the ring buffer. */ - drm_sched_wqueue_stop(&ring->sched); /* back up the non-guilty commands */ amdgpu_ring_backup_unprocessed_commands(ring, guilty_fence); } @@ -895,8 +893,6 @@ int amdgpu_ring_reset_helper_end(struct amdgpu_ring *ring, amdgpu_ring_write(ring, ring->ring_backup[i]); amdgpu_ring_commit(ring); } - /* Start the scheduler again */ - drm_sched_wqueue_start(&ring->sched); return 0; } From f7afda7fcd169a9168695247d07ad94cf7b9798f Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 5 Feb 2026 10:42:54 -0600 Subject: [PATCH 50/51] drm/amd: Fix hang on amdgpu unload by using pci_dev_is_disconnected() The commit 6a23e7b4332c ("drm/amd: Clean up kfd node on surprise disconnect") introduced early KFD cleanup when drm_dev_is_unplugged() returns true. However, this causes hangs during normal module unload (rmmod amdgpu). The issue occurs because drm_dev_unplug() is called in amdgpu_pci_remove() for all removal scenarios, not just surprise disconnects. This was done intentionally in commit 39934d3ed572 ("Revert "drm/amdgpu: TA unload messages are not actually sent to psp when amdgpu is uninstalled"") to fix IGT PCI software unplug test failures. As a result, drm_dev_is_unplugged() returns true even during normal module unload, triggering the early KFD cleanup inappropriately. The correct check should distinguish between: - Actual surprise disconnect (eGPU unplugged): pci_dev_is_disconnected() returns true - Normal module unload (rmmod): pci_dev_is_disconnected() returns false Replace drm_dev_is_unplugged() with pci_dev_is_disconnected() to ensure the early cleanup only happens during true hardware disconnect events. Cc: stable@vger.kernel.org Reported-by: Cal Peake Closes: https://lore.kernel.org/all/b0c22deb-c0fa-3343-33cf-fd9a77d7db99@absolutedigital.net/ Fixes: 6a23e7b4332c ("drm/amd: Clean up kfd node on surprise disconnect") Acked-by: Alex Deucher Signed-off-by: Mario Limonciello Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 528990a595ec..975822141381 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -4924,7 +4924,7 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev) * before ip_fini_early to prevent kfd locking refcount issues by calling * amdgpu_amdkfd_suspend() */ - if (drm_dev_is_unplugged(adev_to_drm(adev))) + if (pci_dev_is_disconnected(adev->pdev)) amdgpu_amdkfd_device_fini_sw(adev); amdgpu_device_ip_fini_early(adev); @@ -4936,7 +4936,7 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev) amdgpu_gart_dummy_page_fini(adev); - if (drm_dev_is_unplugged(adev_to_drm(adev))) + if (pci_dev_is_disconnected(adev->pdev)) amdgpu_device_unmap_mmio(adev); } From 5028a24aa89a2c91b44964191ee8184e5f5c8cb2 Mon Sep 17 00:00:00 2001 From: Kent Russell Date: Tue, 3 Feb 2026 09:48:23 -0500 Subject: [PATCH 51/51] drm/amdgpu: Send applicable RMA CPERs at end of RAS init Firmware and monitoring tools may not be ready to receive a CPER when we read the bad pages, so send the CPERs at the end of RAS initialization to ensure that the FW is ready to receive and process the CPER. This removes the previous CPER submission that was added during bad page load, and sends both in-band and out-of-band at the same time. Signed-off-by: Kent Russell Reviewed-by: Tao Zhou Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c | 2 ++ .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c | 27 ++++++++++++++++--- .../gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h | 2 ++ 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index b28fcf932f7e..856b1bf83533 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -4650,6 +4650,8 @@ int amdgpu_ras_late_init(struct amdgpu_device *adev) amdgpu_ras_block_late_init_default(adev, &obj->ras_comm); } + amdgpu_ras_check_bad_page_status(adev); + return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index 469d04a39d7d..2c5d7f87e593 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -1712,10 +1712,6 @@ int amdgpu_ras_eeprom_check(struct amdgpu_ras_eeprom_control *control) dev_warn(adev->dev, "RAS records:%u exceeds 90%% of threshold:%d", control->ras_num_bad_pages, ras->bad_page_cnt_threshold); - if (amdgpu_bad_page_threshold != 0 && - control->ras_num_bad_pages >= ras->bad_page_cnt_threshold) - amdgpu_dpm_send_rma_reason(adev); - } else if (hdr->header == RAS_TABLE_HDR_BAD && amdgpu_bad_page_threshold != 0) { if (hdr->version >= RAS_TABLE_VER_V2_1) { @@ -1932,3 +1928,26 @@ int amdgpu_ras_smu_erase_ras_table(struct amdgpu_device *adev, result); return -EOPNOTSUPP; } + +void amdgpu_ras_check_bad_page_status(struct amdgpu_device *adev) +{ + struct amdgpu_ras *ras = amdgpu_ras_get_context(adev); + struct amdgpu_ras_eeprom_control *control = ras ? &ras->eeprom_control : NULL; + + if (!control || amdgpu_bad_page_threshold == 0) + return; + + if (control->ras_num_bad_pages >= ras->bad_page_cnt_threshold) { + if (amdgpu_dpm_send_rma_reason(adev)) + dev_warn(adev->dev, "Unable to send out-of-band RMA CPER"); + else + dev_dbg(adev->dev, "Sent out-of-band RMA CPER"); + + if (adev->cper.enabled && !amdgpu_uniras_enabled(adev)) { + if (amdgpu_cper_generate_bp_threshold_record(adev)) + dev_warn(adev->dev, "Unable to send in-band RMA CPER"); + else + dev_dbg(adev->dev, "Sent in-band RMA CPER"); + } + } +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h index 2e5d63957e71..a62114800a92 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h @@ -193,6 +193,8 @@ int amdgpu_ras_eeprom_read_idx(struct amdgpu_ras_eeprom_control *control, int amdgpu_ras_eeprom_update_record_num(struct amdgpu_ras_eeprom_control *control); +void amdgpu_ras_check_bad_page_status(struct amdgpu_device *adev); + extern const struct file_operations amdgpu_ras_debugfs_eeprom_size_ops; extern const struct file_operations amdgpu_ras_debugfs_eeprom_table_ops;