linux/drivers/gpu/drm/amd/powerplay/smumgr/vega12_smumgr.c
<<
>>
Prefs
   1/*
   2 * Copyright 2017 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 "smumgr.h"
  25#include "vega12_inc.h"
  26#include "soc15_common.h"
  27#include "smu9_smumgr.h"
  28#include "vega12_smumgr.h"
  29#include "vega12_ppsmc.h"
  30#include "vega12/smu9_driver_if.h"
  31#include "ppatomctrl.h"
  32#include "pp_debug.h"
  33
  34
  35/*
  36 * Copy table from SMC into driver FB
  37 * @param   hwmgr    the address of the HW manager
  38 * @param   table_id    the driver's table ID to copy from
  39 */
  40static int vega12_copy_table_from_smc(struct pp_hwmgr *hwmgr,
  41                                      uint8_t *table, int16_t table_id)
  42{
  43        struct vega12_smumgr *priv =
  44                        (struct vega12_smumgr *)(hwmgr->smu_backend);
  45
  46        PP_ASSERT_WITH_CODE(table_id < TABLE_COUNT,
  47                        "Invalid SMU Table ID!", return -EINVAL);
  48        PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].version != 0,
  49                        "Invalid SMU Table version!", return -EINVAL);
  50        PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].size != 0,
  51                        "Invalid SMU Table Length!", return -EINVAL);
  52        PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc_with_parameter(hwmgr,
  53                        PPSMC_MSG_SetDriverDramAddrHigh,
  54                        upper_32_bits(priv->smu_tables.entry[table_id].mc_addr)) == 0,
  55                        "[CopyTableFromSMC] Attempt to Set Dram Addr High Failed!", return -EINVAL);
  56        PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc_with_parameter(hwmgr,
  57                        PPSMC_MSG_SetDriverDramAddrLow,
  58                        lower_32_bits(priv->smu_tables.entry[table_id].mc_addr)) == 0,
  59                        "[CopyTableFromSMC] Attempt to Set Dram Addr Low Failed!",
  60                        return -EINVAL);
  61        PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc_with_parameter(hwmgr,
  62                        PPSMC_MSG_TransferTableSmu2Dram,
  63                        table_id) == 0,
  64                        "[CopyTableFromSMC] Attempt to Transfer Table From SMU Failed!",
  65                        return -EINVAL);
  66
  67        memcpy(table, priv->smu_tables.entry[table_id].table,
  68                        priv->smu_tables.entry[table_id].size);
  69
  70        return 0;
  71}
  72
  73/*
  74 * Copy table from Driver FB into SMC
  75 * @param   hwmgr    the address of the HW manager
  76 * @param   table_id    the table to copy from
  77 */
  78static int vega12_copy_table_to_smc(struct pp_hwmgr *hwmgr,
  79                                    uint8_t *table, int16_t table_id)
  80{
  81        struct vega12_smumgr *priv =
  82                        (struct vega12_smumgr *)(hwmgr->smu_backend);
  83
  84        PP_ASSERT_WITH_CODE(table_id < TABLE_COUNT,
  85                        "Invalid SMU Table ID!", return -EINVAL);
  86        PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].version != 0,
  87                        "Invalid SMU Table version!", return -EINVAL);
  88        PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].size != 0,
  89                        "Invalid SMU Table Length!", return -EINVAL);
  90
  91        memcpy(priv->smu_tables.entry[table_id].table, table,
  92                        priv->smu_tables.entry[table_id].size);
  93
  94        PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc_with_parameter(hwmgr,
  95                        PPSMC_MSG_SetDriverDramAddrHigh,
  96                        upper_32_bits(priv->smu_tables.entry[table_id].mc_addr)) == 0,
  97                        "[CopyTableToSMC] Attempt to Set Dram Addr High Failed!",
  98                        return -EINVAL;);
  99        PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc_with_parameter(hwmgr,
 100                        PPSMC_MSG_SetDriverDramAddrLow,
 101                        lower_32_bits(priv->smu_tables.entry[table_id].mc_addr)) == 0,
 102                        "[CopyTableToSMC] Attempt to Set Dram Addr Low Failed!",
 103                        return -EINVAL);
 104        PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc_with_parameter(hwmgr,
 105                        PPSMC_MSG_TransferTableDram2Smu,
 106                        table_id) == 0,
 107                        "[CopyTableToSMC] Attempt to Transfer Table To SMU Failed!",
 108                        return -EINVAL);
 109
 110        return 0;
 111}
 112
 113int vega12_enable_smc_features(struct pp_hwmgr *hwmgr,
 114                bool enable, uint64_t feature_mask)
 115{
 116        uint32_t smu_features_low, smu_features_high;
 117
 118        smu_features_low = (uint32_t)((feature_mask & SMU_FEATURES_LOW_MASK) >> SMU_FEATURES_LOW_SHIFT);
 119        smu_features_high = (uint32_t)((feature_mask & SMU_FEATURES_HIGH_MASK) >> SMU_FEATURES_HIGH_SHIFT);
 120
 121        if (enable) {
 122                PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc_with_parameter(hwmgr,
 123                                PPSMC_MSG_EnableSmuFeaturesLow, smu_features_low) == 0,
 124                                "[EnableDisableSMCFeatures] Attemp to enable SMU features Low failed!",
 125                                return -EINVAL);
 126                PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc_with_parameter(hwmgr,
 127                                PPSMC_MSG_EnableSmuFeaturesHigh, smu_features_high) == 0,
 128                                "[EnableDisableSMCFeatures] Attemp to enable SMU features High failed!",
 129                                return -EINVAL);
 130        } else {
 131                PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc_with_parameter(hwmgr,
 132                                PPSMC_MSG_DisableSmuFeaturesLow, smu_features_low) == 0,
 133                                "[EnableDisableSMCFeatures] Attemp to disable SMU features Low failed!",
 134                                return -EINVAL);
 135                PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc_with_parameter(hwmgr,
 136                                PPSMC_MSG_DisableSmuFeaturesHigh, smu_features_high) == 0,
 137                                "[EnableDisableSMCFeatures] Attemp to disable SMU features High failed!",
 138                                return -EINVAL);
 139        }
 140
 141        return 0;
 142}
 143
 144int vega12_get_enabled_smc_features(struct pp_hwmgr *hwmgr,
 145                uint64_t *features_enabled)
 146{
 147        uint32_t smc_features_low, smc_features_high;
 148
 149        if (features_enabled == NULL)
 150                return -EINVAL;
 151
 152        PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc(hwmgr,
 153                        PPSMC_MSG_GetEnabledSmuFeaturesLow) == 0,
 154                        "[GetEnabledSMCFeatures] Attemp to get SMU features Low failed!",
 155                        return -EINVAL);
 156        smc_features_low = smu9_get_argument(hwmgr);
 157
 158        PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc(hwmgr,
 159                        PPSMC_MSG_GetEnabledSmuFeaturesHigh) == 0,
 160                        "[GetEnabledSMCFeatures] Attemp to get SMU features High failed!",
 161                        return -EINVAL);
 162        smc_features_high = smu9_get_argument(hwmgr);
 163
 164        *features_enabled = ((((uint64_t)smc_features_low << SMU_FEATURES_LOW_SHIFT) & SMU_FEATURES_LOW_MASK) |
 165                        (((uint64_t)smc_features_high << SMU_FEATURES_HIGH_SHIFT) & SMU_FEATURES_HIGH_MASK));
 166
 167        return 0;
 168}
 169
 170static bool vega12_is_dpm_running(struct pp_hwmgr *hwmgr)
 171{
 172        uint64_t features_enabled = 0;
 173
 174        vega12_get_enabled_smc_features(hwmgr, &features_enabled);
 175
 176        if (features_enabled & SMC_DPM_FEATURES)
 177                return true;
 178        else
 179                return false;
 180}
 181
 182static int vega12_set_tools_address(struct pp_hwmgr *hwmgr)
 183{
 184        struct vega12_smumgr *priv =
 185                        (struct vega12_smumgr *)(hwmgr->smu_backend);
 186
 187        if (priv->smu_tables.entry[TABLE_PMSTATUSLOG].mc_addr) {
 188                if (!smu9_send_msg_to_smc_with_parameter(hwmgr,
 189                                PPSMC_MSG_SetToolsDramAddrHigh,
 190                                upper_32_bits(priv->smu_tables.entry[TABLE_PMSTATUSLOG].mc_addr)))
 191                        smu9_send_msg_to_smc_with_parameter(hwmgr,
 192                                        PPSMC_MSG_SetToolsDramAddrLow,
 193                                        lower_32_bits(priv->smu_tables.entry[TABLE_PMSTATUSLOG].mc_addr));
 194        }
 195        return 0;
 196}
 197
 198static int vega12_smu_init(struct pp_hwmgr *hwmgr)
 199{
 200        struct vega12_smumgr *priv;
 201        unsigned long tools_size;
 202        struct cgs_firmware_info info = {0};
 203        int ret;
 204
 205        ret = cgs_get_firmware_info(hwmgr->device, CGS_UCODE_ID_SMU,
 206                                &info);
 207        if (ret || !info.kptr)
 208                return -EINVAL;
 209
 210        priv = kzalloc(sizeof(struct vega12_smumgr), GFP_KERNEL);
 211        if (!priv)
 212                return -ENOMEM;
 213
 214        hwmgr->smu_backend = priv;
 215
 216        /* allocate space for pptable */
 217        ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev,
 218                        sizeof(PPTable_t),
 219                        PAGE_SIZE,
 220                        AMDGPU_GEM_DOMAIN_VRAM,
 221                        &priv->smu_tables.entry[TABLE_PPTABLE].handle,
 222                        &priv->smu_tables.entry[TABLE_PPTABLE].mc_addr,
 223                        &priv->smu_tables.entry[TABLE_PPTABLE].table);
 224        if (ret)
 225                goto free_backend;
 226
 227        priv->smu_tables.entry[TABLE_PPTABLE].version = 0x01;
 228        priv->smu_tables.entry[TABLE_PPTABLE].size = sizeof(PPTable_t);
 229
 230        /* allocate space for watermarks table */
 231        ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev,
 232                                      sizeof(Watermarks_t),
 233                                      PAGE_SIZE,
 234                                      AMDGPU_GEM_DOMAIN_VRAM,
 235                                      &priv->smu_tables.entry[TABLE_WATERMARKS].handle,
 236                                      &priv->smu_tables.entry[TABLE_WATERMARKS].mc_addr,
 237                                      &priv->smu_tables.entry[TABLE_WATERMARKS].table);
 238
 239        if (ret)
 240                goto err0;
 241
 242        priv->smu_tables.entry[TABLE_WATERMARKS].version = 0x01;
 243        priv->smu_tables.entry[TABLE_WATERMARKS].size = sizeof(Watermarks_t);
 244
 245        tools_size = 0x19000;
 246        if (tools_size) {
 247                ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev,
 248                                              tools_size,
 249                                              PAGE_SIZE,
 250                                              AMDGPU_GEM_DOMAIN_VRAM,
 251                                              &priv->smu_tables.entry[TABLE_PMSTATUSLOG].handle,
 252                                              &priv->smu_tables.entry[TABLE_PMSTATUSLOG].mc_addr,
 253                                              &priv->smu_tables.entry[TABLE_PMSTATUSLOG].table);
 254                if (ret)
 255                        goto err1;
 256
 257                priv->smu_tables.entry[TABLE_PMSTATUSLOG].version = 0x01;
 258                priv->smu_tables.entry[TABLE_PMSTATUSLOG].size = tools_size;
 259        }
 260
 261        /* allocate space for AVFS Fuse table */
 262        ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev,
 263                                      sizeof(AvfsFuseOverride_t),
 264                                      PAGE_SIZE,
 265                                      AMDGPU_GEM_DOMAIN_VRAM,
 266                                      &priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].handle,
 267                                      &priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].mc_addr,
 268                                      &priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].table);
 269
 270        if (ret)
 271                goto err2;
 272
 273        priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].version = 0x01;
 274        priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].size = sizeof(AvfsFuseOverride_t);
 275
 276        /* allocate space for OverDrive table */
 277        ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev,
 278                                      sizeof(OverDriveTable_t),
 279                                      PAGE_SIZE,
 280                                      AMDGPU_GEM_DOMAIN_VRAM,
 281                                      &priv->smu_tables.entry[TABLE_OVERDRIVE].handle,
 282                                      &priv->smu_tables.entry[TABLE_OVERDRIVE].mc_addr,
 283                                      &priv->smu_tables.entry[TABLE_OVERDRIVE].table);
 284        if (ret)
 285                goto err3;
 286
 287        priv->smu_tables.entry[TABLE_OVERDRIVE].version = 0x01;
 288        priv->smu_tables.entry[TABLE_OVERDRIVE].size = sizeof(OverDriveTable_t);
 289
 290        /* allocate space for SMU_METRICS table */
 291        ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev,
 292                                      sizeof(SmuMetrics_t),
 293                                      PAGE_SIZE,
 294                                      AMDGPU_GEM_DOMAIN_VRAM,
 295                                      &priv->smu_tables.entry[TABLE_SMU_METRICS].handle,
 296                                      &priv->smu_tables.entry[TABLE_SMU_METRICS].mc_addr,
 297                                      &priv->smu_tables.entry[TABLE_SMU_METRICS].table);
 298        if (ret)
 299                goto err4;
 300
 301        priv->smu_tables.entry[TABLE_SMU_METRICS].version = 0x01;
 302        priv->smu_tables.entry[TABLE_SMU_METRICS].size = sizeof(SmuMetrics_t);
 303
 304        return 0;
 305
 306err4:
 307        amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_OVERDRIVE].handle,
 308                                &priv->smu_tables.entry[TABLE_OVERDRIVE].mc_addr,
 309                                &priv->smu_tables.entry[TABLE_OVERDRIVE].table);
 310err3:
 311        amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].handle,
 312                                &priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].mc_addr,
 313                                &priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].table);
 314err2:
 315        if (priv->smu_tables.entry[TABLE_PMSTATUSLOG].table)
 316                amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_PMSTATUSLOG].handle,
 317                                &priv->smu_tables.entry[TABLE_PMSTATUSLOG].mc_addr,
 318                                &priv->smu_tables.entry[TABLE_PMSTATUSLOG].table);
 319err1:
 320        amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_WATERMARKS].handle,
 321                                &priv->smu_tables.entry[TABLE_WATERMARKS].mc_addr,
 322                                &priv->smu_tables.entry[TABLE_WATERMARKS].table);
 323err0:
 324        amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_PPTABLE].handle,
 325                        &priv->smu_tables.entry[TABLE_PPTABLE].mc_addr,
 326                        &priv->smu_tables.entry[TABLE_PPTABLE].table);
 327free_backend:
 328        kfree(hwmgr->smu_backend);
 329
 330        return -EINVAL;
 331}
 332
 333static int vega12_smu_fini(struct pp_hwmgr *hwmgr)
 334{
 335        struct vega12_smumgr *priv =
 336                        (struct vega12_smumgr *)(hwmgr->smu_backend);
 337
 338        if (priv) {
 339                amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_PPTABLE].handle,
 340                                      &priv->smu_tables.entry[TABLE_PPTABLE].mc_addr,
 341                                      &priv->smu_tables.entry[TABLE_PPTABLE].table);
 342                amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_WATERMARKS].handle,
 343                                      &priv->smu_tables.entry[TABLE_WATERMARKS].mc_addr,
 344                                      &priv->smu_tables.entry[TABLE_WATERMARKS].table);
 345                if (priv->smu_tables.entry[TABLE_PMSTATUSLOG].table)
 346                        amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_PMSTATUSLOG].handle,
 347                                              &priv->smu_tables.entry[TABLE_PMSTATUSLOG].mc_addr,
 348                                              &priv->smu_tables.entry[TABLE_PMSTATUSLOG].table);
 349                amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].handle,
 350                                      &priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].mc_addr,
 351                                      &priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].table);
 352                amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_OVERDRIVE].handle,
 353                                      &priv->smu_tables.entry[TABLE_OVERDRIVE].mc_addr,
 354                                      &priv->smu_tables.entry[TABLE_OVERDRIVE].table);
 355                amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_SMU_METRICS].handle,
 356                                      &priv->smu_tables.entry[TABLE_SMU_METRICS].mc_addr,
 357                                      &priv->smu_tables.entry[TABLE_SMU_METRICS].table);
 358                kfree(hwmgr->smu_backend);
 359                hwmgr->smu_backend = NULL;
 360        }
 361        return 0;
 362}
 363
 364static int vega12_start_smu(struct pp_hwmgr *hwmgr)
 365{
 366        PP_ASSERT_WITH_CODE(smu9_is_smc_ram_running(hwmgr),
 367                        "SMC is not running!",
 368                        return -EINVAL);
 369
 370        vega12_set_tools_address(hwmgr);
 371
 372        return 0;
 373}
 374
 375static int vega12_smc_table_manager(struct pp_hwmgr *hwmgr, uint8_t *table,
 376                                    uint16_t table_id, bool rw)
 377{
 378        int ret;
 379
 380        if (rw)
 381                ret = vega12_copy_table_from_smc(hwmgr, table, table_id);
 382        else
 383                ret = vega12_copy_table_to_smc(hwmgr, table, table_id);
 384
 385        return ret;
 386}
 387
 388const struct pp_smumgr_func vega12_smu_funcs = {
 389        .name = "vega12_smu",
 390        .smu_init = &vega12_smu_init,
 391        .smu_fini = &vega12_smu_fini,
 392        .start_smu = &vega12_start_smu,
 393        .request_smu_load_specific_fw = NULL,
 394        .send_msg_to_smc = &smu9_send_msg_to_smc,
 395        .send_msg_to_smc_with_parameter = &smu9_send_msg_to_smc_with_parameter,
 396        .download_pptable_settings = NULL,
 397        .upload_pptable_settings = NULL,
 398        .is_dpm_running = vega12_is_dpm_running,
 399        .get_argument = smu9_get_argument,
 400        .smc_table_manager = vega12_smc_table_manager,
 401};
 402