From c27c9778a19e050628689d03604941c7039685a3 Mon Sep 17 00:00:00 2001 From: Evan Quan Date: Thu, 27 Dec 2018 14:23:30 +0800 Subject: drm/amd/powerplay: support BOOTUP_DEFAULT power profile mode This can avoid unexpected profile mode change after running compute workload. Signed-off-by: Evan Quan Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/include/kgd_pp_interface.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/amd/include/kgd_pp_interface.h') diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index 1479ea1dc3e7..789c4f288485 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h @@ -127,12 +127,13 @@ enum amd_pp_task { }; enum PP_SMC_POWER_PROFILE { - PP_SMC_POWER_PROFILE_FULLSCREEN3D = 0x0, - PP_SMC_POWER_PROFILE_POWERSAVING = 0x1, - PP_SMC_POWER_PROFILE_VIDEO = 0x2, - PP_SMC_POWER_PROFILE_VR = 0x3, - PP_SMC_POWER_PROFILE_COMPUTE = 0x4, - PP_SMC_POWER_PROFILE_CUSTOM = 0x5, + PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT = 0x0, + PP_SMC_POWER_PROFILE_FULLSCREEN3D = 0x1, + PP_SMC_POWER_PROFILE_POWERSAVING = 0x2, + PP_SMC_POWER_PROFILE_VIDEO = 0x3, + PP_SMC_POWER_PROFILE_VR = 0x4, + PP_SMC_POWER_PROFILE_COMPUTE = 0x5, + PP_SMC_POWER_PROFILE_CUSTOM = 0x6, }; enum { -- cgit v1.2.3-55-g7522 From 7451ca88d51dc9d97ea94b453450fc81494f48e0 Mon Sep 17 00:00:00 2001 From: Jim Qu Date: Mon, 5 Nov 2018 17:45:56 +0800 Subject: drm/amdgpu: add BACO interfaces in pm and hwmgr function table Signed-off-by: Jim Qu Reviewed-by: Alex Deucher Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/include/kgd_pp_interface.h | 3 +++ drivers/gpu/drm/amd/powerplay/inc/hwmgr.h | 8 ++++++++ 2 files changed, 11 insertions(+) (limited to 'drivers/gpu/drm/amd/include/kgd_pp_interface.h') diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index 789c4f288485..a2ea4c933360 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h @@ -281,6 +281,9 @@ struct amd_pm_funcs { int (*set_hard_min_dcefclk_by_freq)(void *handle, uint32_t clock); int (*set_hard_min_fclk_by_freq)(void *handle, uint32_t clock); int (*set_min_deep_sleep_dcefclk)(void *handle, uint32_t clock); + int (*get_asic_baco_capability)(void *handle, bool *cap); + int (*get_asic_baco_state)(void *handle, int *state); + int (*set_asic_baco_state)(void *handle, int state); }; #endif diff --git a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h index be4f87aed99c..577cec90aef1 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h @@ -47,6 +47,11 @@ enum DISPLAY_GAP { }; typedef enum DISPLAY_GAP DISPLAY_GAP; +enum BACO_STATE { + BACO_STATE_OUT = 0, + BACO_STATE_IN, +}; + struct vi_dpm_level { bool enabled; uint32_t value; @@ -333,6 +338,9 @@ struct pp_hwmgr_func { int (*enable_mgpu_fan_boost)(struct pp_hwmgr *hwmgr); int (*set_hard_min_dcefclk_by_freq)(struct pp_hwmgr *hwmgr, uint32_t clock); int (*set_hard_min_fclk_by_freq)(struct pp_hwmgr *hwmgr, uint32_t clock); + int (*get_asic_baco_capability)(struct pp_hwmgr *hwmgr, bool *cap); + int (*get_asic_baco_state)(struct pp_hwmgr *hwmgr, enum BACO_STATE *state); + int (*set_asic_baco_state)(struct pp_hwmgr *hwmgr, enum BACO_STATE state); }; struct pp_table_func { -- cgit v1.2.3-55-g7522 From 7ca881a8651bdeffd99ba8e0010160f9bf60673e Mon Sep 17 00:00:00 2001 From: Evan Quan Date: Mon, 14 Jan 2019 14:06:54 +0800 Subject: drm/amd/powerplay: support enabled ppfeatures retrieving and setting V3 User can use "ppfeatures" sysfs interface to retrieve and set enabled powerplay features. V2: expose this feature for Vega10 and later dGPUs V3: squash in removal of unused variable (Alex) Signed-off-by: Evan Quan Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h | 8 ++ drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | 71 ++++++++++++++ drivers/gpu/drm/amd/include/kgd_pp_interface.h | 2 + drivers/gpu/drm/amd/powerplay/amd_powerplay.c | 42 +++++++++ drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c | 104 +++++++++++++++++++++ drivers/gpu/drm/amd/powerplay/inc/hwmgr.h | 2 + 6 files changed, 229 insertions(+) (limited to 'drivers/gpu/drm/amd/include/kgd_pp_interface.h') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h index f972cd156795..2f61e9edb1c1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h @@ -364,6 +364,14 @@ enum amdgpu_pcie_gen { ((adev)->powerplay.pp_funcs->enable_mgpu_fan_boost(\ (adev)->powerplay.pp_handle)) +#define amdgpu_dpm_get_ppfeature_status(adev, buf) \ + ((adev)->powerplay.pp_funcs->get_ppfeature_status(\ + (adev)->powerplay.pp_handle, (buf))) + +#define amdgpu_dpm_set_ppfeature_status(adev, ppfeatures) \ + ((adev)->powerplay.pp_funcs->set_ppfeature_status(\ + (adev)->powerplay.pp_handle, (ppfeatures))) + struct amdgpu_dpm { struct amdgpu_ps *ps; /* number of valid power states */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c index 51eb2cf42b81..f21f294e6735 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c @@ -625,6 +625,60 @@ static ssize_t amdgpu_get_pp_od_clk_voltage(struct device *dev, } +/** + * DOC: ppfeatures + * + * The amdgpu driver provides a sysfs API for adjusting what powerplay + * features to be enabled. The file ppfeatures is used for this. And + * this is only available for Vega10 and later dGPUs. + * + * Reading back the file will show you the followings: + * - Current ppfeature masks + * - List of the all supported powerplay features with their naming, + * bitmasks and enablement status('Y'/'N' means "enabled"/"disabled"). + * + * To manually enable or disable a specific feature, just set or clear + * the corresponding bit from original ppfeature masks and input the + * new ppfeature masks. + */ +static ssize_t amdgpu_set_ppfeature_status(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = ddev->dev_private; + uint64_t featuremask; + int ret; + + ret = kstrtou64(buf, 0, &featuremask); + if (ret) + return -EINVAL; + + pr_debug("featuremask = 0x%llx\n", featuremask); + + if (adev->powerplay.pp_funcs->set_ppfeature_status) { + ret = amdgpu_dpm_set_ppfeature_status(adev, featuremask); + if (ret) + return -EINVAL; + } + + return count; +} + +static ssize_t amdgpu_get_ppfeature_status(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = ddev->dev_private; + + if (adev->powerplay.pp_funcs->get_ppfeature_status) + return amdgpu_dpm_get_ppfeature_status(adev, buf); + + return snprintf(buf, PAGE_SIZE, "\n"); +} + /** * DOC: pp_dpm_sclk pp_dpm_mclk pp_dpm_pcie * @@ -1051,6 +1105,9 @@ static DEVICE_ATTR(pp_od_clk_voltage, S_IRUGO | S_IWUSR, static DEVICE_ATTR(gpu_busy_percent, S_IRUGO, amdgpu_get_busy_percent, NULL); static DEVICE_ATTR(pcie_bw, S_IRUGO, amdgpu_get_pcie_bw, NULL); +static DEVICE_ATTR(ppfeatures, S_IRUGO | S_IWUSR, + amdgpu_get_ppfeature_status, + amdgpu_set_ppfeature_status); static ssize_t amdgpu_hwmon_show_temp(struct device *dev, struct device_attribute *attr, @@ -2241,6 +2298,17 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev) return ret; } + if ((adev->asic_type >= CHIP_VEGA10) && + !(adev->flags & AMD_IS_APU)) { + ret = device_create_file(adev->dev, + &dev_attr_ppfeatures); + if (ret) { + DRM_ERROR("failed to create device file " + "ppfeatures\n"); + return ret; + } + } + adev->pm.sysfs_initialized = true; return 0; @@ -2276,6 +2344,9 @@ void amdgpu_pm_sysfs_fini(struct amdgpu_device *adev) device_remove_file(adev->dev, &dev_attr_gpu_busy_percent); if (adev->flags & !AMD_IS_APU) device_remove_file(adev->dev, &dev_attr_pcie_bw); + if ((adev->asic_type >= CHIP_VEGA10) && + !(adev->flags & AMD_IS_APU)) + device_remove_file(adev->dev, &dev_attr_ppfeatures); } void amdgpu_pm_compute_clocks(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index a2ea4c933360..1130f293c4ee 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h @@ -284,6 +284,8 @@ struct amd_pm_funcs { int (*get_asic_baco_capability)(void *handle, bool *cap); int (*get_asic_baco_state)(void *handle, int *state); int (*set_asic_baco_state)(void *handle, int state); + int (*get_ppfeature_status)(void *handle, char *buf); + int (*set_ppfeature_status)(void *handle, uint64_t ppfeature_masks); }; #endif diff --git a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c index 5d8b5d3c2453..3f73f7cd18b9 100644 --- a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c +++ b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c @@ -1455,6 +1455,46 @@ static int pp_set_asic_baco_state(void *handle, int state) return 0; } +static int pp_get_ppfeature_status(void *handle, char *buf) +{ + struct pp_hwmgr *hwmgr = handle; + int ret = 0; + + if (!hwmgr || !hwmgr->pm_en || !buf) + return -EINVAL; + + if (hwmgr->hwmgr_func->get_ppfeature_status == NULL) { + pr_info_ratelimited("%s was not implemented.\n", __func__); + return -EINVAL; + } + + mutex_lock(&hwmgr->smu_lock); + ret = hwmgr->hwmgr_func->get_ppfeature_status(hwmgr, buf); + mutex_unlock(&hwmgr->smu_lock); + + return ret; +} + +static int pp_set_ppfeature_status(void *handle, uint64_t ppfeature_masks) +{ + struct pp_hwmgr *hwmgr = handle; + int ret = 0; + + if (!hwmgr || !hwmgr->pm_en) + return -EINVAL; + + if (hwmgr->hwmgr_func->set_ppfeature_status == NULL) { + pr_info_ratelimited("%s was not implemented.\n", __func__); + return -EINVAL; + } + + mutex_lock(&hwmgr->smu_lock); + ret = hwmgr->hwmgr_func->set_ppfeature_status(hwmgr, ppfeature_masks); + mutex_unlock(&hwmgr->smu_lock); + + return ret; +} + static const struct amd_pm_funcs pp_dpm_funcs = { .load_firmware = pp_dpm_load_fw, .wait_for_fw_loading_complete = pp_dpm_fw_loading_complete, @@ -1508,4 +1548,6 @@ static const struct amd_pm_funcs pp_dpm_funcs = { .get_asic_baco_capability = pp_get_asic_baco_capability, .get_asic_baco_state = pp_get_asic_baco_state, .set_asic_baco_state = pp_set_asic_baco_state, + .get_ppfeature_status = pp_get_ppfeature_status, + .set_ppfeature_status = pp_set_ppfeature_status, }; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c index 2ba387b0f27c..3e97b9d6f450 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c @@ -2776,6 +2776,108 @@ static int vega20_odn_edit_dpm_table(struct pp_hwmgr *hwmgr, return 0; } +static int vega20_get_ppfeature_status(struct pp_hwmgr *hwmgr, char *buf) +{ + static const char *ppfeature_name[] = { + "DPM_PREFETCHER", + "GFXCLK_DPM", + "UCLK_DPM", + "SOCCLK_DPM", + "UVD_DPM", + "VCE_DPM", + "ULV", + "MP0CLK_DPM", + "LINK_DPM", + "DCEFCLK_DPM", + "GFXCLK_DS", + "SOCCLK_DS", + "LCLK_DS", + "PPT", + "TDC", + "THERMAL", + "GFX_PER_CU_CG", + "RM", + "DCEFCLK_DS", + "ACDC", + "VR0HOT", + "VR1HOT", + "FW_CTF", + "LED_DISPLAY", + "FAN_CONTROL", + "GFX_EDC", + "GFXOFF", + "CG", + "FCLK_DPM", + "FCLK_DS", + "MP1CLK_DS", + "MP0CLK_DS", + "XGMI"}; + static const char *output_title[] = { + "FEATURES", + "BITMASK", + "ENABLEMENT"}; + uint64_t features_enabled; + int i; + int ret = 0; + int size = 0; + + ret = vega20_get_enabled_smc_features(hwmgr, &features_enabled); + PP_ASSERT_WITH_CODE(!ret, + "[EnableAllSmuFeatures] Failed to get enabled smc features!", + return ret); + + size += sprintf(buf + size, "Current ppfeatures: 0x%016llx\n", features_enabled); + size += sprintf(buf + size, "%-19s %-22s %s\n", + output_title[0], + output_title[1], + output_title[2]); + for (i = 0; i < GNLD_FEATURES_MAX; i++) { + size += sprintf(buf + size, "%-19s 0x%016llx %6s\n", + ppfeature_name[i], + 1ULL << i, + (features_enabled & (1ULL << i)) ? "Y" : "N"); + } + + return size; +} + +static int vega20_set_ppfeature_status(struct pp_hwmgr *hwmgr, uint64_t new_ppfeature_masks) +{ + uint64_t features_enabled; + uint64_t features_to_enable; + uint64_t features_to_disable; + int ret = 0; + + if (new_ppfeature_masks >= (1ULL << GNLD_FEATURES_MAX)) + return -EINVAL; + + ret = vega20_get_enabled_smc_features(hwmgr, &features_enabled); + if (ret) + return ret; + + features_to_disable = + (features_enabled ^ new_ppfeature_masks) & features_enabled; + features_to_enable = + (features_enabled ^ new_ppfeature_masks) ^ features_to_disable; + + pr_debug("features_to_disable 0x%llx\n", features_to_disable); + pr_debug("features_to_enable 0x%llx\n", features_to_enable); + + if (features_to_disable) { + ret = vega20_enable_smc_features(hwmgr, false, features_to_disable); + if (ret) + return ret; + } + + if (features_to_enable) { + ret = vega20_enable_smc_features(hwmgr, true, features_to_enable); + if (ret) + return ret; + } + + return 0; +} + static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr, enum pp_clock_type type, char *buf) { @@ -3572,6 +3674,8 @@ static const struct pp_hwmgr_func vega20_hwmgr_funcs = { .force_clock_level = vega20_force_clock_level, .print_clock_levels = vega20_print_clock_levels, .read_sensor = vega20_read_sensor, + .get_ppfeature_status = vega20_get_ppfeature_status, + .set_ppfeature_status = vega20_set_ppfeature_status, /* powergate related */ .powergate_uvd = vega20_power_gate_uvd, .powergate_vce = vega20_power_gate_vce, diff --git a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h index 577cec90aef1..b1cd70dcd6e7 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h @@ -341,6 +341,8 @@ struct pp_hwmgr_func { int (*get_asic_baco_capability)(struct pp_hwmgr *hwmgr, bool *cap); int (*get_asic_baco_state)(struct pp_hwmgr *hwmgr, enum BACO_STATE *state); int (*set_asic_baco_state)(struct pp_hwmgr *hwmgr, enum BACO_STATE state); + int (*get_ppfeature_status)(struct pp_hwmgr *hwmgr, char *buf); + int (*set_ppfeature_status)(struct pp_hwmgr *hwmgr, uint64_t ppfeature_masks); }; struct pp_table_func { -- cgit v1.2.3-55-g7522 From d7337ca2640cde21ff178bd78f01d94cd5ea2e08 Mon Sep 17 00:00:00 2001 From: Evan Quan Date: Mon, 14 Jan 2019 14:45:47 +0800 Subject: drm/amd/powerplay: support retrieving and adjusting SOC clock power levels V2 User can use "pp_dpm_socclk" to retrieve and adjust SOC clock power levels. V2: expose this interface for Vega10 and later ASICs only Signed-off-by: Evan Quan Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | 54 +++++++++++++++++++++- drivers/gpu/drm/amd/include/kgd_pp_interface.h | 1 + drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c | 45 ++++++++++++++++++ 3 files changed, 98 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/amd/include/kgd_pp_interface.h') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c index f21f294e6735..4bdb1d082bea 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c @@ -680,11 +680,13 @@ static ssize_t amdgpu_get_ppfeature_status(struct device *dev, } /** - * DOC: pp_dpm_sclk pp_dpm_mclk pp_dpm_pcie + * DOC: pp_dpm_sclk pp_dpm_mclk pp_dpm_socclk pp_dpm_pcie * * The amdgpu driver provides a sysfs API for adjusting what power levels * are enabled for a given power state. The files pp_dpm_sclk, pp_dpm_mclk, - * and pp_dpm_pcie are used for this. + * pp_dpm_socclk and pp_dpm_pcie are used for this. + * + * pp_dpm_socclk interface is only available for Vega10 and later ASICs. * * Reading back the files will show you the available power levels within * the power state and the clock information for those levels. @@ -804,6 +806,42 @@ static ssize_t amdgpu_set_pp_dpm_mclk(struct device *dev, return count; } +static ssize_t amdgpu_get_pp_dpm_socclk(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = ddev->dev_private; + + if (adev->powerplay.pp_funcs->print_clock_levels) + return amdgpu_dpm_print_clock_levels(adev, PP_SOCCLK, buf); + else + return snprintf(buf, PAGE_SIZE, "\n"); +} + +static ssize_t amdgpu_set_pp_dpm_socclk(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = ddev->dev_private; + int ret; + uint32_t mask = 0; + + ret = amdgpu_read_mask(buf, count, &mask); + if (ret) + return ret; + + if (adev->powerplay.pp_funcs->force_clock_level) + ret = amdgpu_dpm_force_clock_level(adev, PP_SOCCLK, mask); + + if (ret) + return -EINVAL; + + return count; +} + static ssize_t amdgpu_get_pp_dpm_pcie(struct device *dev, struct device_attribute *attr, char *buf) @@ -1087,6 +1125,9 @@ static DEVICE_ATTR(pp_dpm_sclk, S_IRUGO | S_IWUSR, static DEVICE_ATTR(pp_dpm_mclk, S_IRUGO | S_IWUSR, amdgpu_get_pp_dpm_mclk, amdgpu_set_pp_dpm_mclk); +static DEVICE_ATTR(pp_dpm_socclk, S_IRUGO | S_IWUSR, + amdgpu_get_pp_dpm_socclk, + amdgpu_set_pp_dpm_socclk); static DEVICE_ATTR(pp_dpm_pcie, S_IRUGO | S_IWUSR, amdgpu_get_pp_dpm_pcie, amdgpu_set_pp_dpm_pcie); @@ -2246,6 +2287,13 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev) DRM_ERROR("failed to create device file pp_dpm_mclk\n"); return ret; } + if (adev->asic_type >= CHIP_VEGA10) { + ret = device_create_file(adev->dev, &dev_attr_pp_dpm_socclk); + if (ret) { + DRM_ERROR("failed to create device file pp_dpm_socclk\n"); + return ret; + } + } ret = device_create_file(adev->dev, &dev_attr_pp_dpm_pcie); if (ret) { DRM_ERROR("failed to create device file pp_dpm_pcie\n"); @@ -2333,6 +2381,8 @@ void amdgpu_pm_sysfs_fini(struct amdgpu_device *adev) device_remove_file(adev->dev, &dev_attr_pp_dpm_sclk); device_remove_file(adev->dev, &dev_attr_pp_dpm_mclk); + if (adev->asic_type >= CHIP_VEGA10) + device_remove_file(adev->dev, &dev_attr_pp_dpm_socclk); device_remove_file(adev->dev, &dev_attr_pp_dpm_pcie); device_remove_file(adev->dev, &dev_attr_pp_sclk_od); device_remove_file(adev->dev, &dev_attr_pp_mclk_od); diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index 1130f293c4ee..f5ec25a6ab54 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h @@ -92,6 +92,7 @@ enum pp_clock_type { PP_SCLK, PP_MCLK, PP_PCIE, + PP_SOCCLK, OD_SCLK, OD_MCLK, OD_VDDC_CURVE, diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c index 3e97b9d6f450..e7c890f036fa 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c @@ -2296,6 +2296,34 @@ static int vega20_force_clock_level(struct pp_hwmgr *hwmgr, break; + case PP_SOCCLK: + soft_min_level = mask ? (ffs(mask) - 1) : 0; + soft_max_level = mask ? (fls(mask) - 1) : 0; + + if (soft_max_level >= data->dpm_table.soc_table.count) { + pr_err("Clock level specified %d is over max allowed %d\n", + soft_max_level, + data->dpm_table.soc_table.count - 1); + return -EINVAL; + } + + data->dpm_table.soc_table.dpm_state.soft_min_level = + data->dpm_table.soc_table.dpm_levels[soft_min_level].value; + data->dpm_table.soc_table.dpm_state.soft_max_level = + data->dpm_table.soc_table.dpm_levels[soft_max_level].value; + + ret = vega20_upload_dpm_min_level(hwmgr, FEATURE_DPM_SOCCLK_MASK); + PP_ASSERT_WITH_CODE(!ret, + "Failed to upload boot level to lowest!", + return ret); + + ret = vega20_upload_dpm_max_level(hwmgr, FEATURE_DPM_SOCCLK_MASK); + PP_ASSERT_WITH_CODE(!ret, + "Failed to upload dpm max level to highest!", + return ret); + + break; + case PP_PCIE: soft_min_level = mask ? (ffs(mask) - 1) : 0; soft_max_level = mask ? (fls(mask) - 1) : 0; @@ -2931,6 +2959,23 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr, (clocks.data[i].clocks_in_khz == now * 10) ? "*" : ""); break; + case PP_SOCCLK: + ret = vega20_get_current_clk_freq(hwmgr, PPCLK_SOCCLK, &now); + PP_ASSERT_WITH_CODE(!ret, + "Attempt to get current socclk freq Failed!", + return ret); + + ret = vega20_get_socclocks(hwmgr, &clocks); + PP_ASSERT_WITH_CODE(!ret, + "Attempt to get soc clk levels Failed!", + return ret); + + for (i = 0; i < clocks.num_levels; i++) + size += sprintf(buf + size, "%d: %uMhz %s\n", + i, clocks.data[i].clocks_in_khz / 1000, + (clocks.data[i].clocks_in_khz == now * 10) ? "*" : ""); + break; + case PP_PCIE: gen_speed = (RREG32_PCIE(smnPCIE_LC_SPEED_CNTL) & PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK) -- cgit v1.2.3-55-g7522 From 828e37efe802ba8c868922af23099638fde5b7b4 Mon Sep 17 00:00:00 2001 From: Evan Quan Date: Mon, 14 Jan 2019 15:44:44 +0800 Subject: drm/amd/powerplay: support retrieving and adjusting fclock power levels V2 User can use "pp_dpm_fclk" to retrieve and adjust fclock power levels. V2: expose this interface for Vega20 and later ASICs only Signed-off-by: Evan Quan Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | 53 +++++++++++++++++- drivers/gpu/drm/amd/include/kgd_pp_interface.h | 1 + drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c | 64 ++++++++++++++++++++++ 3 files changed, 116 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/amd/include/kgd_pp_interface.h') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c index 4bdb1d082bea..23eb6f61da13 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c @@ -680,13 +680,14 @@ static ssize_t amdgpu_get_ppfeature_status(struct device *dev, } /** - * DOC: pp_dpm_sclk pp_dpm_mclk pp_dpm_socclk pp_dpm_pcie + * DOC: pp_dpm_sclk pp_dpm_mclk pp_dpm_socclk pp_dpm_fclk pp_dpm_pcie * * The amdgpu driver provides a sysfs API for adjusting what power levels * are enabled for a given power state. The files pp_dpm_sclk, pp_dpm_mclk, - * pp_dpm_socclk and pp_dpm_pcie are used for this. + * pp_dpm_socclk, pp_dpm_fclk and pp_dpm_pcie are used for this. * * pp_dpm_socclk interface is only available for Vega10 and later ASICs. + * pp_dpm_fclk interface is only available for Vega20 and later ASICs. * * Reading back the files will show you the available power levels within * the power state and the clock information for those levels. @@ -842,6 +843,42 @@ static ssize_t amdgpu_set_pp_dpm_socclk(struct device *dev, return count; } +static ssize_t amdgpu_get_pp_dpm_fclk(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = ddev->dev_private; + + if (adev->powerplay.pp_funcs->print_clock_levels) + return amdgpu_dpm_print_clock_levels(adev, PP_FCLK, buf); + else + return snprintf(buf, PAGE_SIZE, "\n"); +} + +static ssize_t amdgpu_set_pp_dpm_fclk(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = ddev->dev_private; + int ret; + uint32_t mask = 0; + + ret = amdgpu_read_mask(buf, count, &mask); + if (ret) + return ret; + + if (adev->powerplay.pp_funcs->force_clock_level) + ret = amdgpu_dpm_force_clock_level(adev, PP_FCLK, mask); + + if (ret) + return -EINVAL; + + return count; +} + static ssize_t amdgpu_get_pp_dpm_pcie(struct device *dev, struct device_attribute *attr, char *buf) @@ -1128,6 +1165,9 @@ static DEVICE_ATTR(pp_dpm_mclk, S_IRUGO | S_IWUSR, static DEVICE_ATTR(pp_dpm_socclk, S_IRUGO | S_IWUSR, amdgpu_get_pp_dpm_socclk, amdgpu_set_pp_dpm_socclk); +static DEVICE_ATTR(pp_dpm_fclk, S_IRUGO | S_IWUSR, + amdgpu_get_pp_dpm_fclk, + amdgpu_set_pp_dpm_fclk); static DEVICE_ATTR(pp_dpm_pcie, S_IRUGO | S_IWUSR, amdgpu_get_pp_dpm_pcie, amdgpu_set_pp_dpm_pcie); @@ -2294,6 +2334,13 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev) return ret; } } + if (adev->asic_type >= CHIP_VEGA20) { + ret = device_create_file(adev->dev, &dev_attr_pp_dpm_fclk); + if (ret) { + DRM_ERROR("failed to create device file pp_dpm_fclk\n"); + return ret; + } + } ret = device_create_file(adev->dev, &dev_attr_pp_dpm_pcie); if (ret) { DRM_ERROR("failed to create device file pp_dpm_pcie\n"); @@ -2384,6 +2431,8 @@ void amdgpu_pm_sysfs_fini(struct amdgpu_device *adev) if (adev->asic_type >= CHIP_VEGA10) device_remove_file(adev->dev, &dev_attr_pp_dpm_socclk); device_remove_file(adev->dev, &dev_attr_pp_dpm_pcie); + if (adev->asic_type >= CHIP_VEGA20) + device_remove_file(adev->dev, &dev_attr_pp_dpm_fclk); device_remove_file(adev->dev, &dev_attr_pp_sclk_od); device_remove_file(adev->dev, &dev_attr_pp_mclk_od); device_remove_file(adev->dev, diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index f5ec25a6ab54..f82de14f6560 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h @@ -93,6 +93,7 @@ enum pp_clock_type { PP_MCLK, PP_PCIE, PP_SOCCLK, + PP_FCLK, OD_SCLK, OD_MCLK, OD_VDDC_CURVE, diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c index e7c890f036fa..4e7399c310e2 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c @@ -1736,6 +1736,17 @@ static int vega20_upload_dpm_min_level(struct pp_hwmgr *hwmgr, uint32_t feature_ return ret); } + if (data->smu_features[GNLD_DPM_FCLK].enabled && + (feature_mask & FEATURE_DPM_FCLK_MASK)) { + min_freq = data->dpm_table.fclk_table.dpm_state.soft_min_level; + + PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter( + hwmgr, PPSMC_MSG_SetSoftMinByFreq, + (PPCLK_FCLK << 16) | (min_freq & 0xffff))), + "Failed to set soft min fclk!", + return ret); + } + return ret; } @@ -1808,6 +1819,17 @@ static int vega20_upload_dpm_max_level(struct pp_hwmgr *hwmgr, uint32_t feature_ return ret); } + if (data->smu_features[GNLD_DPM_FCLK].enabled && + (feature_mask & FEATURE_DPM_FCLK_MASK)) { + max_freq = data->dpm_table.fclk_table.dpm_state.soft_max_level; + + PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter( + hwmgr, PPSMC_MSG_SetSoftMaxByFreq, + (PPCLK_FCLK << 16) | (max_freq & 0xffff))), + "Failed to set soft max fclk!", + return ret); + } + return ret; } @@ -2324,6 +2346,34 @@ static int vega20_force_clock_level(struct pp_hwmgr *hwmgr, break; + case PP_FCLK: + soft_min_level = mask ? (ffs(mask) - 1) : 0; + soft_max_level = mask ? (fls(mask) - 1) : 0; + + if (soft_max_level >= data->dpm_table.fclk_table.count) { + pr_err("Clock level specified %d is over max allowed %d\n", + soft_max_level, + data->dpm_table.fclk_table.count - 1); + return -EINVAL; + } + + data->dpm_table.fclk_table.dpm_state.soft_min_level = + data->dpm_table.fclk_table.dpm_levels[soft_min_level].value; + data->dpm_table.fclk_table.dpm_state.soft_max_level = + data->dpm_table.fclk_table.dpm_levels[soft_max_level].value; + + ret = vega20_upload_dpm_min_level(hwmgr, FEATURE_DPM_FCLK_MASK); + PP_ASSERT_WITH_CODE(!ret, + "Failed to upload boot level to lowest!", + return ret); + + ret = vega20_upload_dpm_max_level(hwmgr, FEATURE_DPM_FCLK_MASK); + PP_ASSERT_WITH_CODE(!ret, + "Failed to upload dpm max level to highest!", + return ret); + + break; + case PP_PCIE: soft_min_level = mask ? (ffs(mask) - 1) : 0; soft_max_level = mask ? (fls(mask) - 1) : 0; @@ -2920,6 +2970,8 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr, PPTable_t *pptable = (PPTable_t *)pptable_information->smc_pptable; struct amdgpu_device *adev = hwmgr->adev; struct pp_clock_levels_with_latency clocks; + struct vega20_single_dpm_table *fclk_dpm_table = + &(data->dpm_table.fclk_table); int i, now, size = 0; int ret = 0; uint32_t gen_speed, lane_width; @@ -2976,6 +3028,18 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr, (clocks.data[i].clocks_in_khz == now * 10) ? "*" : ""); break; + case PP_FCLK: + ret = vega20_get_current_clk_freq(hwmgr, PPCLK_FCLK, &now); + PP_ASSERT_WITH_CODE(!ret, + "Attempt to get current fclk freq Failed!", + return ret); + + for (i = 0; i < fclk_dpm_table->count; i++) + size += sprintf(buf + size, "%d: %uMhz %s\n", + i, fclk_dpm_table->dpm_levels[i].value, + fclk_dpm_table->dpm_levels[i].value == (now / 100) ? "*" : ""); + break; + case PP_PCIE: gen_speed = (RREG32_PCIE(smnPCIE_LC_SPEED_CNTL) & PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK) -- cgit v1.2.3-55-g7522 From d7e28e2d6b518af760c81ba578ecf4e4b0c0f401 Mon Sep 17 00:00:00 2001 From: Evan Quan Date: Mon, 14 Jan 2019 17:37:26 +0800 Subject: drm/amd/powerplay: support retrieving and adjusting dcefclock power levels V2 User can use "pp_dpm_dcefclk" to retrieve and adjust dcefclock power levels. V2: expose this interface for Vega10 and later ASICs only Signed-off-by: Evan Quan Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | 59 ++++++++++++++++++++-- drivers/gpu/drm/amd/include/kgd_pp_interface.h | 1 + drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c | 52 ++++++++++++++++++- 3 files changed, 107 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm/amd/include/kgd_pp_interface.h') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c index 23eb6f61da13..4099c6b97cb1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c @@ -680,13 +680,16 @@ static ssize_t amdgpu_get_ppfeature_status(struct device *dev, } /** - * DOC: pp_dpm_sclk pp_dpm_mclk pp_dpm_socclk pp_dpm_fclk pp_dpm_pcie + * DOC: pp_dpm_sclk pp_dpm_mclk pp_dpm_socclk pp_dpm_fclk pp_dpm_dcefclk + * pp_dpm_pcie * * The amdgpu driver provides a sysfs API for adjusting what power levels * are enabled for a given power state. The files pp_dpm_sclk, pp_dpm_mclk, - * pp_dpm_socclk, pp_dpm_fclk and pp_dpm_pcie are used for this. + * pp_dpm_socclk, pp_dpm_fclk, pp_dpm_dcefclk and pp_dpm_pcie are used for + * this. * - * pp_dpm_socclk interface is only available for Vega10 and later ASICs. + * pp_dpm_socclk and pp_dpm_dcefclk interfaces are only available for + * Vega10 and later ASICs. * pp_dpm_fclk interface is only available for Vega20 and later ASICs. * * Reading back the files will show you the available power levels within @@ -697,6 +700,8 @@ static ssize_t amdgpu_get_ppfeature_status(struct device *dev, * Secondly,Enter a new value for each level by inputing a string that * contains " echo xx xx xx > pp_dpm_sclk/mclk/pcie" * E.g., echo 4 5 6 to > pp_dpm_sclk will enable sclk levels 4, 5, and 6. + * + * NOTE: change to the dcefclk max dpm level is not supported now */ static ssize_t amdgpu_get_pp_dpm_sclk(struct device *dev, @@ -879,6 +884,42 @@ static ssize_t amdgpu_set_pp_dpm_fclk(struct device *dev, return count; } +static ssize_t amdgpu_get_pp_dpm_dcefclk(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = ddev->dev_private; + + if (adev->powerplay.pp_funcs->print_clock_levels) + return amdgpu_dpm_print_clock_levels(adev, PP_DCEFCLK, buf); + else + return snprintf(buf, PAGE_SIZE, "\n"); +} + +static ssize_t amdgpu_set_pp_dpm_dcefclk(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = ddev->dev_private; + int ret; + uint32_t mask = 0; + + ret = amdgpu_read_mask(buf, count, &mask); + if (ret) + return ret; + + if (adev->powerplay.pp_funcs->force_clock_level) + ret = amdgpu_dpm_force_clock_level(adev, PP_DCEFCLK, mask); + + if (ret) + return -EINVAL; + + return count; +} + static ssize_t amdgpu_get_pp_dpm_pcie(struct device *dev, struct device_attribute *attr, char *buf) @@ -1168,6 +1209,9 @@ static DEVICE_ATTR(pp_dpm_socclk, S_IRUGO | S_IWUSR, static DEVICE_ATTR(pp_dpm_fclk, S_IRUGO | S_IWUSR, amdgpu_get_pp_dpm_fclk, amdgpu_set_pp_dpm_fclk); +static DEVICE_ATTR(pp_dpm_dcefclk, S_IRUGO | S_IWUSR, + amdgpu_get_pp_dpm_dcefclk, + amdgpu_set_pp_dpm_dcefclk); static DEVICE_ATTR(pp_dpm_pcie, S_IRUGO | S_IWUSR, amdgpu_get_pp_dpm_pcie, amdgpu_set_pp_dpm_pcie); @@ -2333,6 +2377,11 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev) DRM_ERROR("failed to create device file pp_dpm_socclk\n"); return ret; } + ret = device_create_file(adev->dev, &dev_attr_pp_dpm_dcefclk); + if (ret) { + DRM_ERROR("failed to create device file pp_dpm_dcefclk\n"); + return ret; + } } if (adev->asic_type >= CHIP_VEGA20) { ret = device_create_file(adev->dev, &dev_attr_pp_dpm_fclk); @@ -2428,8 +2477,10 @@ void amdgpu_pm_sysfs_fini(struct amdgpu_device *adev) device_remove_file(adev->dev, &dev_attr_pp_dpm_sclk); device_remove_file(adev->dev, &dev_attr_pp_dpm_mclk); - if (adev->asic_type >= CHIP_VEGA10) + if (adev->asic_type >= CHIP_VEGA10) { device_remove_file(adev->dev, &dev_attr_pp_dpm_socclk); + device_remove_file(adev->dev, &dev_attr_pp_dpm_dcefclk); + } device_remove_file(adev->dev, &dev_attr_pp_dpm_pcie); if (adev->asic_type >= CHIP_VEGA20) device_remove_file(adev->dev, &dev_attr_pp_dpm_fclk); diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index f82de14f6560..2b579ba9b685 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h @@ -94,6 +94,7 @@ enum pp_clock_type { PP_PCIE, PP_SOCCLK, PP_FCLK, + PP_DCEFCLK, OD_SCLK, OD_MCLK, OD_VDDC_CURVE, diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c index 4e7399c310e2..8c1fa985c7d4 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c @@ -1747,6 +1747,17 @@ static int vega20_upload_dpm_min_level(struct pp_hwmgr *hwmgr, uint32_t feature_ return ret); } + if (data->smu_features[GNLD_DPM_DCEFCLK].enabled && + (feature_mask & FEATURE_DPM_DCEFCLK_MASK)) { + min_freq = data->dpm_table.dcef_table.dpm_state.hard_min_level; + + PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter( + hwmgr, PPSMC_MSG_SetHardMinByFreq, + (PPCLK_DCEFCLK << 16) | (min_freq & 0xffff))), + "Failed to set hard min dcefclk!", + return ret); + } + return ret; } @@ -2259,7 +2270,7 @@ static int vega20_force_clock_level(struct pp_hwmgr *hwmgr, enum pp_clock_type type, uint32_t mask) { struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend); - uint32_t soft_min_level, soft_max_level; + uint32_t soft_min_level, soft_max_level, hard_min_level; int ret = 0; switch (type) { @@ -2374,6 +2385,28 @@ static int vega20_force_clock_level(struct pp_hwmgr *hwmgr, break; + case PP_DCEFCLK: + hard_min_level = mask ? (ffs(mask) - 1) : 0; + + if (hard_min_level >= data->dpm_table.dcef_table.count) { + pr_err("Clock level specified %d is over max allowed %d\n", + hard_min_level, + data->dpm_table.dcef_table.count - 1); + return -EINVAL; + } + + data->dpm_table.dcef_table.dpm_state.hard_min_level = + data->dpm_table.dcef_table.dpm_levels[hard_min_level].value; + + ret = vega20_upload_dpm_min_level(hwmgr, FEATURE_DPM_DCEFCLK_MASK); + PP_ASSERT_WITH_CODE(!ret, + "Failed to upload boot level to lowest!", + return ret); + + //TODO: Setting DCEFCLK max dpm level is not supported + + break; + case PP_PCIE: soft_min_level = mask ? (ffs(mask) - 1) : 0; soft_max_level = mask ? (fls(mask) - 1) : 0; @@ -3040,6 +3073,23 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr, fclk_dpm_table->dpm_levels[i].value == (now / 100) ? "*" : ""); break; + case PP_DCEFCLK: + ret = vega20_get_current_clk_freq(hwmgr, PPCLK_DCEFCLK, &now); + PP_ASSERT_WITH_CODE(!ret, + "Attempt to get current dcefclk freq Failed!", + return ret); + + ret = vega20_get_dcefclocks(hwmgr, &clocks); + PP_ASSERT_WITH_CODE(!ret, + "Attempt to get dcefclk levels Failed!", + return ret); + + for (i = 0; i < clocks.num_levels; i++) + size += sprintf(buf + size, "%d: %uMhz %s\n", + i, clocks.data[i].clocks_in_khz / 1000, + (clocks.data[i].clocks_in_khz == now * 10) ? "*" : ""); + break; + case PP_PCIE: gen_speed = (RREG32_PCIE(smnPCIE_LC_SPEED_CNTL) & PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK) -- cgit v1.2.3-55-g7522