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