aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c')
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c136
1 files changed, 128 insertions, 8 deletions
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 388c5cb5c647..87b055466a33 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
@@ -266,6 +266,9 @@ int smu_v11_0_check_fw_version(struct smu_context *smu)
case CHIP_BEIGE_GOBY:
smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_Beige_Goby;
break;
+ case CHIP_CYAN_SKILLFISH:
+ smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_Cyan_Skillfish;
+ break;
default:
dev_err(smu->adev->dev, "smu unsupported asic type:%d.\n", smu->adev->asic_type);
smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_INV;
@@ -422,10 +425,20 @@ int smu_v11_0_init_smc_tables(struct smu_context *smu)
ret = -ENOMEM;
goto err3_out;
}
+
+ smu_table->user_overdrive_table =
+ kzalloc(tables[SMU_TABLE_OVERDRIVE].size, GFP_KERNEL);
+ if (!smu_table->user_overdrive_table) {
+ ret = -ENOMEM;
+ goto err4_out;
+ }
+
}
return 0;
+err4_out:
+ kfree(smu_table->boot_overdrive_table);
err3_out:
kfree(smu_table->overdrive_table);
err2_out:
@@ -442,12 +455,14 @@ int smu_v11_0_fini_smc_tables(struct smu_context *smu)
struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
kfree(smu_table->gpu_metrics_table);
+ kfree(smu_table->user_overdrive_table);
kfree(smu_table->boot_overdrive_table);
kfree(smu_table->overdrive_table);
kfree(smu_table->max_sustainable_clocks);
kfree(smu_table->driver_pptable);
kfree(smu_table->clocks_table);
smu_table->gpu_metrics_table = NULL;
+ smu_table->user_overdrive_table = NULL;
smu_table->boot_overdrive_table = NULL;
smu_table->overdrive_table = NULL;
smu_table->max_sustainable_clocks = NULL;
@@ -1185,17 +1200,13 @@ smu_v11_0_set_fan_static_mode(struct smu_context *smu, uint32_t mode)
}
int
-smu_v11_0_set_fan_speed_percent(struct smu_context *smu, uint32_t speed)
+smu_v11_0_set_fan_speed_pwm(struct smu_context *smu, uint32_t speed)
{
struct amdgpu_device *adev = smu->adev;
uint32_t duty100, duty;
uint64_t tmp64;
- if (speed > 100)
- speed = 100;
-
- if (smu_v11_0_auto_fan_control(smu, 0))
- return -EINVAL;
+ speed = MIN(speed, 255);
duty100 = REG_GET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL1),
CG_FDO_CTRL1, FMAX_DUTY100);
@@ -1203,7 +1214,7 @@ smu_v11_0_set_fan_speed_percent(struct smu_context *smu, uint32_t speed)
return -EINVAL;
tmp64 = (uint64_t)speed * duty100;
- do_div(tmp64, 100);
+ do_div(tmp64, 255);
duty = (uint32_t)tmp64;
WREG32_SOC15(THM, 0, mmCG_FDO_CTRL0,
@@ -1213,6 +1224,99 @@ smu_v11_0_set_fan_speed_percent(struct smu_context *smu, uint32_t speed)
return smu_v11_0_set_fan_static_mode(smu, FDO_PWM_MODE_STATIC);
}
+int smu_v11_0_set_fan_speed_rpm(struct smu_context *smu,
+ uint32_t speed)
+{
+ struct amdgpu_device *adev = smu->adev;
+ /*
+ * crystal_clock_freq used for fan speed rpm calculation is
+ * always 25Mhz. So, hardcode it as 2500(in 10K unit).
+ */
+ uint32_t crystal_clock_freq = 2500;
+ uint32_t tach_period;
+
+ /*
+ * To prevent from possible overheat, some ASICs may have requirement
+ * for minimum fan speed:
+ * - For some NV10 SKU, the fan speed cannot be set lower than
+ * 700 RPM.
+ * - For some Sienna Cichlid SKU, the fan speed cannot be set
+ * lower than 500 RPM.
+ */
+ tach_period = 60 * crystal_clock_freq * 10000 / (8 * speed);
+ WREG32_SOC15(THM, 0, mmCG_TACH_CTRL,
+ REG_SET_FIELD(RREG32_SOC15(THM, 0, mmCG_TACH_CTRL),
+ CG_TACH_CTRL, TARGET_PERIOD,
+ tach_period));
+
+ return smu_v11_0_set_fan_static_mode(smu, FDO_PWM_MODE_STATIC_RPM);
+}
+
+int smu_v11_0_get_fan_speed_pwm(struct smu_context *smu,
+ uint32_t *speed)
+{
+ struct amdgpu_device *adev = smu->adev;
+ uint32_t duty100, duty;
+ uint64_t tmp64;
+
+ /*
+ * For pre Sienna Cichlid ASICs, the 0 RPM may be not correctly
+ * detected via register retrieving. To workaround this, we will
+ * report the fan speed as 0 PWM if user just requested such.
+ */
+ if ((smu->user_dpm_profile.flags & SMU_CUSTOM_FAN_SPEED_PWM)
+ && !smu->user_dpm_profile.fan_speed_pwm) {
+ *speed = 0;
+ return 0;
+ }
+
+ duty100 = REG_GET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL1),
+ CG_FDO_CTRL1, FMAX_DUTY100);
+ duty = REG_GET_FIELD(RREG32_SOC15(THM, 0, mmCG_THERMAL_STATUS),
+ CG_THERMAL_STATUS, FDO_PWM_DUTY);
+ if (!duty100)
+ return -EINVAL;
+
+ tmp64 = (uint64_t)duty * 255;
+ do_div(tmp64, duty100);
+ *speed = MIN((uint32_t)tmp64, 255);
+
+ return 0;
+}
+
+int smu_v11_0_get_fan_speed_rpm(struct smu_context *smu,
+ uint32_t *speed)
+{
+ struct amdgpu_device *adev = smu->adev;
+ uint32_t crystal_clock_freq = 2500;
+ uint32_t tach_status;
+ uint64_t tmp64;
+
+ /*
+ * For pre Sienna Cichlid ASICs, the 0 RPM may be not correctly
+ * detected via register retrieving. To workaround this, we will
+ * report the fan speed as 0 RPM if user just requested such.
+ */
+ if ((smu->user_dpm_profile.flags & SMU_CUSTOM_FAN_SPEED_RPM)
+ && !smu->user_dpm_profile.fan_speed_rpm) {
+ *speed = 0;
+ return 0;
+ }
+
+ tmp64 = (uint64_t)crystal_clock_freq * 60 * 10000;
+
+ tach_status = RREG32_SOC15(THM, 0, mmCG_TACH_STATUS);
+ if (tach_status) {
+ do_div(tmp64, tach_status);
+ *speed = (uint32_t)tmp64;
+ } else {
+ dev_warn_once(adev->dev, "Got zero output on CG_TACH_STATUS reading!\n");
+ *speed = 0;
+ }
+
+ return 0;
+}
+
int
smu_v11_0_set_fan_control_mode(struct smu_context *smu,
uint32_t mode)
@@ -1221,7 +1325,9 @@ smu_v11_0_set_fan_control_mode(struct smu_context *smu,
switch (mode) {
case AMD_FAN_CTRL_NONE:
- ret = smu_v11_0_set_fan_speed_percent(smu, 100);
+ ret = smu_v11_0_auto_fan_control(smu, 0);
+ if (!ret)
+ ret = smu_v11_0_set_fan_speed_pwm(smu, 255);
break;
case AMD_FAN_CTRL_MANUAL:
ret = smu_v11_0_auto_fan_control(smu, 0);
@@ -1528,6 +1634,7 @@ int smu_v11_0_baco_set_state(struct smu_context *smu, enum smu_baco_state state)
case CHIP_SIENNA_CICHLID:
case CHIP_NAVY_FLOUNDER:
case CHIP_DIMGREY_CAVEFISH:
+ case CHIP_BEIGE_GOBY:
if (amdgpu_runtime_pm == 2)
ret = smu_cmn_send_smc_msg_with_param(smu,
SMU_MSG_EnterBaco,
@@ -2100,3 +2207,16 @@ int smu_v11_0_deep_sleep_control(struct smu_context *smu,
return ret;
}
+
+int smu_v11_0_restore_user_od_settings(struct smu_context *smu)
+{
+ struct smu_table_context *table_context = &smu->smu_table;
+ void *user_od_table = table_context->user_overdrive_table;
+ int ret = 0;
+
+ ret = smu_cmn_update_table(smu, SMU_TABLE_OVERDRIVE, 0, (void *)user_od_table, true);
+ if (ret)
+ dev_err(smu->adev->dev, "Failed to import overdrive table!\n");
+
+ return ret;
+}