linux/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_thermal.c
<<
>>
Prefs
   1/*
   2 * Copyright 2018 Advanced Micro Devices, Inc.
   3 *
   4 * Permission is hereby granted, free of charge, to any person obtaining a
   5 * copy of this software and associated documentation files (the "Software"),
   6 * to deal in the Software without restriction, including without limitation
   7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8 * and/or sell copies of the Software, and to permit persons to whom the
   9 * Software is furnished to do so, subject to the following conditions:
  10 *
  11 * The above copyright notice and this permission notice shall be included in
  12 * all copies or substantial portions of the Software.
  13 *
  14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20 * OTHER DEALINGS IN THE SOFTWARE.
  21 *
  22 */
  23
  24#include "vega20_thermal.h"
  25#include "vega20_hwmgr.h"
  26#include "vega20_smumgr.h"
  27#include "vega20_ppsmc.h"
  28#include "vega20_inc.h"
  29#include "soc15_common.h"
  30#include "pp_debug.h"
  31
  32static int vega20_disable_fan_control_feature(struct pp_hwmgr *hwmgr)
  33{
  34        struct vega20_hwmgr *data = hwmgr->backend;
  35        int ret = 0;
  36
  37        if (data->smu_features[GNLD_FAN_CONTROL].supported) {
  38                ret = vega20_enable_smc_features(
  39                                hwmgr, false,
  40                                data->smu_features[GNLD_FAN_CONTROL].
  41                                smu_feature_bitmap);
  42                PP_ASSERT_WITH_CODE(!ret,
  43                                "Disable FAN CONTROL feature Failed!",
  44                                return ret);
  45                data->smu_features[GNLD_FAN_CONTROL].enabled = false;
  46        }
  47
  48        return ret;
  49}
  50
  51int vega20_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr)
  52{
  53        struct vega20_hwmgr *data = hwmgr->backend;
  54
  55        if (data->smu_features[GNLD_FAN_CONTROL].supported)
  56                return vega20_disable_fan_control_feature(hwmgr);
  57
  58        return 0;
  59}
  60
  61static int vega20_enable_fan_control_feature(struct pp_hwmgr *hwmgr)
  62{
  63        struct vega20_hwmgr *data = hwmgr->backend;
  64        int ret = 0;
  65
  66        if (data->smu_features[GNLD_FAN_CONTROL].supported) {
  67                ret = vega20_enable_smc_features(
  68                                hwmgr, true,
  69                                data->smu_features[GNLD_FAN_CONTROL].
  70                                smu_feature_bitmap);
  71                PP_ASSERT_WITH_CODE(!ret,
  72                                "Enable FAN CONTROL feature Failed!",
  73                                return ret);
  74                data->smu_features[GNLD_FAN_CONTROL].enabled = true;
  75        }
  76
  77        return ret;
  78}
  79
  80int vega20_fan_ctrl_start_smc_fan_control(struct pp_hwmgr *hwmgr)
  81{
  82        struct vega20_hwmgr *data = hwmgr->backend;
  83
  84        if (data->smu_features[GNLD_FAN_CONTROL].supported)
  85                return vega20_enable_fan_control_feature(hwmgr);
  86
  87        return 0;
  88}
  89
  90static int vega20_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
  91{
  92        struct amdgpu_device *adev = hwmgr->adev;
  93
  94        WREG32_SOC15(THM, 0, mmCG_FDO_CTRL2,
  95                        REG_SET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL2),
  96                                CG_FDO_CTRL2, TMIN, 0));
  97        WREG32_SOC15(THM, 0, mmCG_FDO_CTRL2,
  98                        REG_SET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL2),
  99                                CG_FDO_CTRL2, FDO_PWM_MODE, mode));
 100
 101        return 0;
 102}
 103
 104static int vega20_get_current_rpm(struct pp_hwmgr *hwmgr, uint32_t *current_rpm)
 105{
 106        int ret = 0;
 107
 108        PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc(hwmgr,
 109                                PPSMC_MSG_GetCurrentRpm)) == 0,
 110                        "Attempt to get current RPM from SMC Failed!",
 111                        return ret);
 112        *current_rpm = smum_get_argument(hwmgr);
 113
 114        return 0;
 115}
 116
 117int vega20_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr,
 118                uint32_t *speed)
 119{
 120        struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
 121        PPTable_t *pp_table = &(data->smc_state_table.pp_table);
 122        uint32_t current_rpm, percent = 0;
 123        int ret = 0;
 124
 125        ret = vega20_get_current_rpm(hwmgr, &current_rpm);
 126        if (ret)
 127                return ret;
 128
 129        percent = current_rpm * 100 / pp_table->FanMaximumRpm;
 130
 131        *speed = percent > 100 ? 100 : percent;
 132
 133        return 0;
 134}
 135
 136int vega20_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr,
 137                uint32_t speed)
 138{
 139        struct amdgpu_device *adev = hwmgr->adev;
 140        uint32_t duty100;
 141        uint32_t duty;
 142        uint64_t tmp64;
 143
 144        if (speed > 100)
 145                speed = 100;
 146
 147        if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl))
 148                vega20_fan_ctrl_stop_smc_fan_control(hwmgr);
 149
 150        duty100 = REG_GET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL1),
 151                                    CG_FDO_CTRL1, FMAX_DUTY100);
 152
 153        if (duty100 == 0)
 154                return -EINVAL;
 155
 156        tmp64 = (uint64_t)speed * duty100;
 157        do_div(tmp64, 100);
 158        duty = (uint32_t)tmp64;
 159
 160        WREG32_SOC15(THM, 0, mmCG_FDO_CTRL0,
 161                REG_SET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL0),
 162                        CG_FDO_CTRL0, FDO_STATIC_DUTY, duty));
 163
 164        return vega20_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
 165}
 166
 167int vega20_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr,
 168                struct phm_fan_speed_info *fan_speed_info)
 169{
 170        memset(fan_speed_info, 0, sizeof(*fan_speed_info));
 171        fan_speed_info->supports_percent_read = true;
 172        fan_speed_info->supports_percent_write = true;
 173        fan_speed_info->supports_rpm_read = true;
 174        fan_speed_info->supports_rpm_write = true;
 175
 176        return 0;
 177}
 178
 179int vega20_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed)
 180{
 181        *speed = 0;
 182
 183        return vega20_get_current_rpm(hwmgr, speed);
 184}
 185
 186int vega20_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed)
 187{
 188        struct amdgpu_device *adev = hwmgr->adev;
 189        uint32_t tach_period, crystal_clock_freq;
 190        int result = 0;
 191
 192        if (!speed)
 193                return -EINVAL;
 194
 195        if (PP_CAP(PHM_PlatformCaps_MicrocodeFanControl)) {
 196                result = vega20_fan_ctrl_stop_smc_fan_control(hwmgr);
 197                if (result)
 198                        return result;
 199        }
 200
 201        crystal_clock_freq = amdgpu_asic_get_xclk((struct amdgpu_device *)hwmgr->adev);
 202        tach_period = 60 * crystal_clock_freq * 10000 / (8 * speed);
 203        WREG32_SOC15(THM, 0, mmCG_TACH_CTRL,
 204                        REG_SET_FIELD(RREG32_SOC15(THM, 0, mmCG_TACH_CTRL),
 205                                CG_TACH_CTRL, TARGET_PERIOD,
 206                                tach_period));
 207
 208        return vega20_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC_RPM);
 209}
 210
 211/**
 212* Reads the remote temperature from the SIslands thermal controller.
 213*
 214* @param    hwmgr The address of the hardware manager.
 215*/
 216int vega20_thermal_get_temperature(struct pp_hwmgr *hwmgr)
 217{
 218        struct amdgpu_device *adev = hwmgr->adev;
 219        int temp = 0;
 220
 221        temp = RREG32_SOC15(THM, 0, mmCG_MULT_THERMAL_STATUS);
 222
 223        temp = (temp & CG_MULT_THERMAL_STATUS__CTF_TEMP_MASK) >>
 224                        CG_MULT_THERMAL_STATUS__CTF_TEMP__SHIFT;
 225
 226        temp = temp & 0x1ff;
 227
 228        temp *= PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
 229        return temp;
 230}
 231
 232/**
 233* Set the requested temperature range for high and low alert signals
 234*
 235* @param    hwmgr The address of the hardware manager.
 236* @param    range Temperature range to be programmed for
 237*           high and low alert signals
 238* @exception PP_Result_BadInput if the input data is not valid.
 239*/
 240static int vega20_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
 241                struct PP_TemperatureRange *range)
 242{
 243        struct amdgpu_device *adev = hwmgr->adev;
 244        int low = VEGA20_THERMAL_MINIMUM_ALERT_TEMP *
 245                        PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
 246        int high = VEGA20_THERMAL_MAXIMUM_ALERT_TEMP *
 247                        PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
 248        uint32_t val;
 249
 250        if (low < range->min)
 251                low = range->min;
 252        if (high > range->max)
 253                high = range->max;
 254
 255        if (low > high)
 256                return -EINVAL;
 257
 258        val = RREG32_SOC15(THM, 0, mmTHM_THERMAL_INT_CTRL);
 259
 260        val = CGS_REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, MAX_IH_CREDIT, 5);
 261        val = CGS_REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, THERM_IH_HW_ENA, 1);
 262        val = CGS_REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTH, (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
 263        val = CGS_REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTL, (low / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
 264        val = val & (~THM_THERMAL_INT_CTRL__THERM_TRIGGER_MASK_MASK);
 265
 266        WREG32_SOC15(THM, 0, mmTHM_THERMAL_INT_CTRL, val);
 267
 268        return 0;
 269}
 270
 271/**
 272* Enable thermal alerts on the RV770 thermal controller.
 273*
 274* @param    hwmgr The address of the hardware manager.
 275*/
 276static int vega20_thermal_enable_alert(struct pp_hwmgr *hwmgr)
 277{
 278        struct amdgpu_device *adev = hwmgr->adev;
 279        uint32_t val = 0;
 280
 281        val |= (1 << THM_THERMAL_INT_ENA__THERM_INTH_CLR__SHIFT);
 282        val |= (1 << THM_THERMAL_INT_ENA__THERM_INTL_CLR__SHIFT);
 283        val |= (1 << THM_THERMAL_INT_ENA__THERM_TRIGGER_CLR__SHIFT);
 284
 285        WREG32_SOC15(THM, 0, mmTHM_THERMAL_INT_ENA, val);
 286
 287        return 0;
 288}
 289
 290/**
 291* Disable thermal alerts on the RV770 thermal controller.
 292* @param    hwmgr The address of the hardware manager.
 293*/
 294int vega20_thermal_disable_alert(struct pp_hwmgr *hwmgr)
 295{
 296        struct amdgpu_device *adev = hwmgr->adev;
 297
 298        WREG32_SOC15(THM, 0, mmTHM_THERMAL_INT_ENA, 0);
 299
 300        return 0;
 301}
 302
 303/**
 304* Uninitialize the thermal controller.
 305* Currently just disables alerts.
 306* @param    hwmgr The address of the hardware manager.
 307*/
 308int vega20_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr)
 309{
 310        int result = vega20_thermal_disable_alert(hwmgr);
 311
 312        return result;
 313}
 314
 315/**
 316* Set up the fan table to control the fan using the SMC.
 317* @param    hwmgr  the address of the powerplay hardware manager.
 318* @param    pInput the pointer to input data
 319* @param    pOutput the pointer to output data
 320* @param    pStorage the pointer to temporary storage
 321* @param    Result the last failure code
 322* @return   result from set temperature range routine
 323*/
 324static int vega20_thermal_setup_fan_table(struct pp_hwmgr *hwmgr)
 325{
 326        int ret;
 327        struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
 328        PPTable_t *table = &(data->smc_state_table.pp_table);
 329
 330        ret = smum_send_msg_to_smc_with_parameter(hwmgr,
 331                                PPSMC_MSG_SetFanTemperatureTarget,
 332                                (uint32_t)table->FanTargetTemperature);
 333
 334        return ret;
 335}
 336
 337int vega20_start_thermal_controller(struct pp_hwmgr *hwmgr,
 338                                struct PP_TemperatureRange *range)
 339{
 340        int ret = 0;
 341
 342        if (range == NULL)
 343                return -EINVAL;
 344
 345        ret = vega20_thermal_set_temperature_range(hwmgr, range);
 346        if (ret)
 347                return ret;
 348
 349        ret = vega20_thermal_enable_alert(hwmgr);
 350        if (ret)
 351                return ret;
 352
 353        ret = vega20_thermal_setup_fan_table(hwmgr);
 354
 355        return ret;
 356};
 357