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 */ 40 static 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 */ 84 static 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 125 int 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 156 int 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 182 static 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 194 static 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 212 static 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 320 err4: 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); 324 err3: 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); 328 err2: 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); 333 err1: 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); 337 err0: 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); 341 free_backend: 342 kfree(hwmgr->smu_backend); 343 344 return -EINVAL; 345 } 346 347 static 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 378 static 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 389 static 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 402 const 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