Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

drm/amd/pm/smu7: Fix SMU7 voltage dependency on display clock

The DCE (display controller engine) requires a minimum voltage
in order to function correctly, depending on which clock level
it currently uses.

Add a new table that contains display clock frequency levels
and the corresponding required voltages. The clock frequency
levels are taken from DC (and the old radeon driver's voltage
dependency table for CI in cases where its values were lower).
The voltage levels are taken from the following function:
phm_initializa_dynamic_state_adjustment_rule_settings().
Furthermore, in case of CI, call smu7_patch_vddc() on the new
table to account for leakage voltage (like in radeon).

Use the display clock value from amd_pp_display_configuration
to look up the voltage level needed by the DCE. Send the
voltage to the SMU via the PPSMC_MSG_VddC_Request command.

The previous implementation of this feature was non-functional
because it relied on a "dal_power_level" field which was never
assigned; and it was not at all implemented for CI ASICs.

I verified this on a Radeon R9 M380 which previously booted to
a black screen with DC enabled (default since Linux 6.19), but
now works correctly.

Fixes: 599a7e9fe1b6 ("drm/amd/powerplay: implement smu7 hwmgr to manager asics with smu ip version 7.")
Signed-off-by: Timur Kristóf <timur.kristof@gmail.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

authored by

Timur Kristóf and committed by
Alex Deucher
0138610c 9851f29c

+86 -3
+85 -3
drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c
··· 2802 2802 if (tmp) 2803 2803 return -EINVAL; 2804 2804 2805 + tmp = smu7_patch_vddc(hwmgr, hwmgr->dyn_state.vddc_dependency_on_display_clock); 2806 + if (tmp) 2807 + return -EINVAL; 2808 + 2805 2809 tmp = smu7_patch_vce_vddc(hwmgr, hwmgr->dyn_state.vce_clock_voltage_dependency_table); 2806 2810 if (tmp) 2807 2811 return -EINVAL; ··· 2889 2885 { 2890 2886 kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl); 2891 2887 hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL; 2888 + kfree(hwmgr->dyn_state.vddc_dependency_on_display_clock); 2889 + hwmgr->dyn_state.vddc_dependency_on_display_clock = NULL; 2892 2890 kfree(hwmgr->backend); 2893 2891 hwmgr->backend = NULL; 2894 2892 ··· 2961 2955 return ret; 2962 2956 } 2963 2957 2958 + static int smu7_init_voltage_dependency_on_display_clock_table(struct pp_hwmgr *hwmgr) 2959 + { 2960 + struct phm_clock_voltage_dependency_table *table; 2961 + 2962 + if (!amdgpu_device_ip_get_ip_block(hwmgr->adev, AMD_IP_BLOCK_TYPE_DCE)) 2963 + return 0; 2964 + 2965 + table = kzalloc(struct_size(table, entries, 4), GFP_KERNEL); 2966 + if (!table) 2967 + return -ENOMEM; 2968 + 2969 + if (hwmgr->chip_id >= CHIP_POLARIS10) { 2970 + table->entries[0].clk = 38918; 2971 + table->entries[1].clk = 45900; 2972 + table->entries[2].clk = 66700; 2973 + table->entries[3].clk = 113200; 2974 + 2975 + table->entries[0].v = 700; 2976 + table->entries[1].v = 740; 2977 + table->entries[2].v = 800; 2978 + table->entries[3].v = 900; 2979 + } else { 2980 + if (hwmgr->chip_family == AMDGPU_FAMILY_CZ) { 2981 + table->entries[0].clk = 35200; 2982 + table->entries[1].clk = 35200; 2983 + table->entries[2].clk = 46700; 2984 + table->entries[3].clk = 64300; 2985 + } else { 2986 + table->entries[0].clk = 0; 2987 + table->entries[1].clk = 35200; 2988 + table->entries[2].clk = 54000; 2989 + table->entries[3].clk = 62500; 2990 + } 2991 + 2992 + table->entries[0].v = 0; 2993 + table->entries[1].v = 720; 2994 + table->entries[2].v = 810; 2995 + table->entries[3].v = 900; 2996 + } 2997 + 2998 + table->count = 4; 2999 + hwmgr->dyn_state.vddc_dependency_on_display_clock = table; 3000 + return 0; 3001 + } 3002 + 2964 3003 static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) 2965 3004 { 2966 3005 struct amdgpu_device *adev = hwmgr->adev; ··· 3033 2982 } else { 3034 2983 smu7_get_elb_voltages(hwmgr); 3035 2984 } 2985 + 2986 + result = smu7_init_voltage_dependency_on_display_clock_table(hwmgr); 2987 + if (result) 2988 + goto fail; 3036 2989 3037 2990 if (hwmgr->pp_table_version == PP_TABLE_V1) { 3038 2991 smu7_complete_dependency_tables(hwmgr); ··· 3134 3079 return 0; 3135 3080 } 3136 3081 3082 + static uint32_t smu7_lookup_vddc_from_dispclk(struct pp_hwmgr *hwmgr) 3083 + { 3084 + const struct amd_pp_display_configuration *cfg = hwmgr->display_config; 3085 + const struct phm_clock_voltage_dependency_table *vddc_dep_on_dispclk = 3086 + hwmgr->dyn_state.vddc_dependency_on_display_clock; 3087 + uint32_t i; 3088 + 3089 + if (!vddc_dep_on_dispclk || !vddc_dep_on_dispclk->count || 3090 + !cfg || !cfg->num_display || !cfg->display_clk) 3091 + return 0; 3092 + 3093 + /* Start from 1 because ClocksStateUltraLow should not be used according to DC. */ 3094 + for (i = 1; i < vddc_dep_on_dispclk->count; ++i) 3095 + if (vddc_dep_on_dispclk->entries[i].clk >= cfg->display_clk) 3096 + return vddc_dep_on_dispclk->entries[i].v; 3097 + 3098 + return vddc_dep_on_dispclk->entries[vddc_dep_on_dispclk->count - 1].v; 3099 + } 3100 + 3101 + static void smu7_apply_minimum_dce_voltage_request(struct pp_hwmgr *hwmgr) 3102 + { 3103 + uint32_t req_vddc = smu7_lookup_vddc_from_dispclk(hwmgr); 3104 + 3105 + smum_send_msg_to_smc_with_parameter(hwmgr, 3106 + PPSMC_MSG_VddC_Request, 3107 + req_vddc * VOLTAGE_SCALE, 3108 + NULL); 3109 + } 3110 + 3137 3111 static int smu7_upload_dpm_level_enable_mask(struct pp_hwmgr *hwmgr) 3138 3112 { 3139 3113 struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); 3140 3114 3141 - if (hwmgr->pp_table_version == PP_TABLE_V1) 3142 - phm_apply_dal_min_voltage_request(hwmgr); 3143 - /* TO DO for v0 iceland and Ci*/ 3115 + smu7_apply_minimum_dce_voltage_request(hwmgr); 3144 3116 3145 3117 if (!data->sclk_dpm_key_disabled) { 3146 3118 if (data->dpm_level_enable_mask.sclk_dpm_enable_mask)
+1
drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h
··· 631 631 struct phm_clock_voltage_dependency_table *vddci_dependency_on_mclk; 632 632 struct phm_clock_voltage_dependency_table *vddc_dependency_on_mclk; 633 633 struct phm_clock_voltage_dependency_table *mvdd_dependency_on_mclk; 634 + struct phm_clock_voltage_dependency_table *vddc_dependency_on_display_clock; 634 635 struct phm_clock_voltage_dependency_table *vddc_dep_on_dal_pwrl; 635 636 struct phm_clock_array *valid_sclk_values; 636 637 struct phm_clock_array *valid_mclk_values;