1 /* 2 * Copyright 2016 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 <linux/pci.h> 25 26 #include "smumgr.h" 27 #include "vega10_inc.h" 28 #include "soc15_common.h" 29 #include "vega10_smumgr.h" 30 #include "vega10_hwmgr.h" 31 #include "vega10_ppsmc.h" 32 #include "smu9_driver_if.h" 33 #include "smu9_smumgr.h" 34 #include "ppatomctrl.h" 35 #include "pp_debug.h" 36 37 38 static int vega10_copy_table_from_smc(struct pp_hwmgr *hwmgr, 39 uint8_t *table, int16_t table_id) 40 { 41 struct vega10_smumgr *priv = hwmgr->smu_backend; 42 struct amdgpu_device *adev = hwmgr->adev; 43 44 PP_ASSERT_WITH_CODE(table_id < MAX_SMU_TABLE, 45 "Invalid SMU Table ID!", return -EINVAL); 46 PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].version != 0, 47 "Invalid SMU Table version!", return -EINVAL); 48 PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].size != 0, 49 "Invalid SMU Table Length!", return -EINVAL); 50 smum_send_msg_to_smc_with_parameter(hwmgr, 51 PPSMC_MSG_SetDriverDramAddrHigh, 52 upper_32_bits(priv->smu_tables.entry[table_id].mc_addr), 53 NULL); 54 smum_send_msg_to_smc_with_parameter(hwmgr, 55 PPSMC_MSG_SetDriverDramAddrLow, 56 lower_32_bits(priv->smu_tables.entry[table_id].mc_addr), 57 NULL); 58 smum_send_msg_to_smc_with_parameter(hwmgr, 59 PPSMC_MSG_TransferTableSmu2Dram, 60 priv->smu_tables.entry[table_id].table_id, 61 NULL); 62 63 amdgpu_asic_invalidate_hdp(adev, NULL); 64 65 memcpy(table, priv->smu_tables.entry[table_id].table, 66 priv->smu_tables.entry[table_id].size); 67 68 return 0; 69 } 70 71 static int vega10_copy_table_to_smc(struct pp_hwmgr *hwmgr, 72 uint8_t *table, int16_t table_id) 73 { 74 struct vega10_smumgr *priv = hwmgr->smu_backend; 75 struct amdgpu_device *adev = hwmgr->adev; 76 77 /* under sriov, vbios or hypervisor driver 78 * has already copy table to smc so here only skip it 79 */ 80 if (!hwmgr->not_vf) 81 return 0; 82 83 PP_ASSERT_WITH_CODE(table_id < MAX_SMU_TABLE, 84 "Invalid SMU Table ID!", return -EINVAL); 85 PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].version != 0, 86 "Invalid SMU Table version!", return -EINVAL); 87 PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].size != 0, 88 "Invalid SMU Table Length!", return -EINVAL); 89 90 memcpy(priv->smu_tables.entry[table_id].table, table, 91 priv->smu_tables.entry[table_id].size); 92 93 amdgpu_asic_flush_hdp(adev, NULL); 94 95 smum_send_msg_to_smc_with_parameter(hwmgr, 96 PPSMC_MSG_SetDriverDramAddrHigh, 97 upper_32_bits(priv->smu_tables.entry[table_id].mc_addr), 98 NULL); 99 smum_send_msg_to_smc_with_parameter(hwmgr, 100 PPSMC_MSG_SetDriverDramAddrLow, 101 lower_32_bits(priv->smu_tables.entry[table_id].mc_addr), 102 NULL); 103 smum_send_msg_to_smc_with_parameter(hwmgr, 104 PPSMC_MSG_TransferTableDram2Smu, 105 priv->smu_tables.entry[table_id].table_id, 106 NULL); 107 108 return 0; 109 } 110 111 int vega10_enable_smc_features(struct pp_hwmgr *hwmgr, 112 bool enable, uint32_t feature_mask) 113 { 114 int msg = enable ? PPSMC_MSG_EnableSmuFeatures : 115 PPSMC_MSG_DisableSmuFeatures; 116 117 /* VF has no permission to change smu feature due 118 * to security concern even under pp one vf mode 119 * it still can't do it. For vega10, the smu in 120 * vbios will enable the appropriate features. 121 * */ 122 if (!hwmgr->not_vf) 123 return 0; 124 125 return smum_send_msg_to_smc_with_parameter(hwmgr, 126 msg, feature_mask, NULL); 127 } 128 129 int vega10_get_enabled_smc_features(struct pp_hwmgr *hwmgr, 130 uint64_t *features_enabled) 131 { 132 uint32_t enabled_features; 133 int ret; 134 135 if (features_enabled == NULL) 136 return -EINVAL; 137 138 ret = smum_send_msg_to_smc(hwmgr, 139 PPSMC_MSG_GetEnabledSmuFeatures, 140 &enabled_features); 141 if (ret) 142 return ret; 143 144 *features_enabled = enabled_features; 145 146 return 0; 147 } 148 149 static bool vega10_is_dpm_running(struct pp_hwmgr *hwmgr) 150 { 151 uint64_t features_enabled = 0; 152 153 vega10_get_enabled_smc_features(hwmgr, &features_enabled); 154 155 if (features_enabled & SMC_DPM_FEATURES) 156 return true; 157 else 158 return false; 159 } 160 161 static int vega10_set_tools_address(struct pp_hwmgr *hwmgr) 162 { 163 struct vega10_smumgr *priv = hwmgr->smu_backend; 164 165 if (priv->smu_tables.entry[TOOLSTABLE].mc_addr) { 166 smum_send_msg_to_smc_with_parameter(hwmgr, 167 PPSMC_MSG_SetToolsDramAddrHigh, 168 upper_32_bits(priv->smu_tables.entry[TOOLSTABLE].mc_addr), 169 NULL); 170 smum_send_msg_to_smc_with_parameter(hwmgr, 171 PPSMC_MSG_SetToolsDramAddrLow, 172 lower_32_bits(priv->smu_tables.entry[TOOLSTABLE].mc_addr), 173 NULL); 174 } 175 return 0; 176 } 177 178 static int vega10_verify_smc_interface(struct pp_hwmgr *hwmgr) 179 { 180 uint32_t smc_driver_if_version; 181 struct amdgpu_device *adev = hwmgr->adev; 182 uint32_t dev_id; 183 uint32_t rev_id; 184 185 PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc(hwmgr, 186 PPSMC_MSG_GetDriverIfVersion, 187 &smc_driver_if_version), 188 "Attempt to get SMC IF Version Number Failed!", 189 return -EINVAL); 190 191 dev_id = adev->pdev->device; 192 rev_id = adev->pdev->revision; 193 194 if (!((dev_id == 0x687f) && 195 ((rev_id == 0xc0) || 196 (rev_id == 0xc1) || 197 (rev_id == 0xc3)))) { 198 if (smc_driver_if_version != SMU9_DRIVER_IF_VERSION) { 199 pr_err("Your firmware(0x%x) doesn't match SMU9_DRIVER_IF_VERSION(0x%x). Please update your firmware!\n", 200 smc_driver_if_version, SMU9_DRIVER_IF_VERSION); 201 return -EINVAL; 202 } 203 } 204 205 return 0; 206 } 207 208 static int vega10_smu_init(struct pp_hwmgr *hwmgr) 209 { 210 struct vega10_smumgr *priv; 211 unsigned long tools_size; 212 int ret; 213 struct cgs_firmware_info info = {0}; 214 215 ret = cgs_get_firmware_info(hwmgr->device, 216 CGS_UCODE_ID_SMU, 217 &info); 218 if (ret || !info.kptr) 219 return -EINVAL; 220 221 priv = kzalloc(sizeof(struct vega10_smumgr), GFP_KERNEL); 222 223 if (!priv) 224 return -ENOMEM; 225 226 hwmgr->smu_backend = priv; 227 228 /* allocate space for pptable */ 229 ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, 230 sizeof(PPTable_t), 231 PAGE_SIZE, 232 AMDGPU_GEM_DOMAIN_VRAM, 233 &priv->smu_tables.entry[PPTABLE].handle, 234 &priv->smu_tables.entry[PPTABLE].mc_addr, 235 &priv->smu_tables.entry[PPTABLE].table); 236 if (ret) 237 goto free_backend; 238 239 priv->smu_tables.entry[PPTABLE].version = 0x01; 240 priv->smu_tables.entry[PPTABLE].size = sizeof(PPTable_t); 241 priv->smu_tables.entry[PPTABLE].table_id = TABLE_PPTABLE; 242 243 /* allocate space for watermarks table */ 244 ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, 245 sizeof(Watermarks_t), 246 PAGE_SIZE, 247 AMDGPU_GEM_DOMAIN_VRAM, 248 &priv->smu_tables.entry[WMTABLE].handle, 249 &priv->smu_tables.entry[WMTABLE].mc_addr, 250 &priv->smu_tables.entry[WMTABLE].table); 251 252 if (ret) 253 goto err0; 254 255 priv->smu_tables.entry[WMTABLE].version = 0x01; 256 priv->smu_tables.entry[WMTABLE].size = sizeof(Watermarks_t); 257 priv->smu_tables.entry[WMTABLE].table_id = TABLE_WATERMARKS; 258 259 /* allocate space for AVFS table */ 260 ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, 261 sizeof(AvfsTable_t), 262 PAGE_SIZE, 263 AMDGPU_GEM_DOMAIN_VRAM, 264 &priv->smu_tables.entry[AVFSTABLE].handle, 265 &priv->smu_tables.entry[AVFSTABLE].mc_addr, 266 &priv->smu_tables.entry[AVFSTABLE].table); 267 268 if (ret) 269 goto err1; 270 271 priv->smu_tables.entry[AVFSTABLE].version = 0x01; 272 priv->smu_tables.entry[AVFSTABLE].size = sizeof(AvfsTable_t); 273 priv->smu_tables.entry[AVFSTABLE].table_id = TABLE_AVFS; 274 275 tools_size = 0x19000; 276 if (tools_size) { 277 ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, 278 tools_size, 279 PAGE_SIZE, 280 AMDGPU_GEM_DOMAIN_VRAM, 281 &priv->smu_tables.entry[TOOLSTABLE].handle, 282 &priv->smu_tables.entry[TOOLSTABLE].mc_addr, 283 &priv->smu_tables.entry[TOOLSTABLE].table); 284 if (ret) 285 goto err2; 286 priv->smu_tables.entry[TOOLSTABLE].version = 0x01; 287 priv->smu_tables.entry[TOOLSTABLE].size = tools_size; 288 priv->smu_tables.entry[TOOLSTABLE].table_id = TABLE_PMSTATUSLOG; 289 } 290 291 /* allocate space for AVFS Fuse table */ 292 ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, 293 sizeof(AvfsFuseOverride_t), 294 PAGE_SIZE, 295 AMDGPU_GEM_DOMAIN_VRAM, 296 &priv->smu_tables.entry[AVFSFUSETABLE].handle, 297 &priv->smu_tables.entry[AVFSFUSETABLE].mc_addr, 298 &priv->smu_tables.entry[AVFSFUSETABLE].table); 299 if (ret) 300 goto err3; 301 302 priv->smu_tables.entry[AVFSFUSETABLE].version = 0x01; 303 priv->smu_tables.entry[AVFSFUSETABLE].size = sizeof(AvfsFuseOverride_t); 304 priv->smu_tables.entry[AVFSFUSETABLE].table_id = TABLE_AVFS_FUSE_OVERRIDE; 305 306 307 return 0; 308 309 err3: 310 if (priv->smu_tables.entry[TOOLSTABLE].table) 311 amdgpu_bo_free_kernel(&priv->smu_tables.entry[TOOLSTABLE].handle, 312 &priv->smu_tables.entry[TOOLSTABLE].mc_addr, 313 &priv->smu_tables.entry[TOOLSTABLE].table); 314 err2: 315 amdgpu_bo_free_kernel(&priv->smu_tables.entry[AVFSTABLE].handle, 316 &priv->smu_tables.entry[AVFSTABLE].mc_addr, 317 &priv->smu_tables.entry[AVFSTABLE].table); 318 err1: 319 amdgpu_bo_free_kernel(&priv->smu_tables.entry[WMTABLE].handle, 320 &priv->smu_tables.entry[WMTABLE].mc_addr, 321 &priv->smu_tables.entry[WMTABLE].table); 322 err0: 323 amdgpu_bo_free_kernel(&priv->smu_tables.entry[PPTABLE].handle, 324 &priv->smu_tables.entry[PPTABLE].mc_addr, 325 &priv->smu_tables.entry[PPTABLE].table); 326 free_backend: 327 kfree(hwmgr->smu_backend); 328 329 return -EINVAL; 330 } 331 332 static int vega10_smu_fini(struct pp_hwmgr *hwmgr) 333 { 334 struct vega10_smumgr *priv = hwmgr->smu_backend; 335 336 if (priv) { 337 amdgpu_bo_free_kernel(&priv->smu_tables.entry[PPTABLE].handle, 338 &priv->smu_tables.entry[PPTABLE].mc_addr, 339 &priv->smu_tables.entry[PPTABLE].table); 340 amdgpu_bo_free_kernel(&priv->smu_tables.entry[WMTABLE].handle, 341 &priv->smu_tables.entry[WMTABLE].mc_addr, 342 &priv->smu_tables.entry[WMTABLE].table); 343 amdgpu_bo_free_kernel(&priv->smu_tables.entry[AVFSTABLE].handle, 344 &priv->smu_tables.entry[AVFSTABLE].mc_addr, 345 &priv->smu_tables.entry[AVFSTABLE].table); 346 if (priv->smu_tables.entry[TOOLSTABLE].table) 347 amdgpu_bo_free_kernel(&priv->smu_tables.entry[TOOLSTABLE].handle, 348 &priv->smu_tables.entry[TOOLSTABLE].mc_addr, 349 &priv->smu_tables.entry[TOOLSTABLE].table); 350 amdgpu_bo_free_kernel(&priv->smu_tables.entry[AVFSFUSETABLE].handle, 351 &priv->smu_tables.entry[AVFSFUSETABLE].mc_addr, 352 &priv->smu_tables.entry[AVFSFUSETABLE].table); 353 kfree(hwmgr->smu_backend); 354 hwmgr->smu_backend = NULL; 355 } 356 return 0; 357 } 358 359 static int vega10_start_smu(struct pp_hwmgr *hwmgr) 360 { 361 if (!smu9_is_smc_ram_running(hwmgr)) 362 return -EINVAL; 363 364 PP_ASSERT_WITH_CODE(!vega10_verify_smc_interface(hwmgr), 365 "Failed to verify SMC interface!", 366 return -EINVAL); 367 368 vega10_set_tools_address(hwmgr); 369 370 return 0; 371 } 372 373 static int vega10_smc_table_manager(struct pp_hwmgr *hwmgr, uint8_t *table, 374 uint16_t table_id, bool rw) 375 { 376 int ret; 377 378 if (rw) 379 ret = vega10_copy_table_from_smc(hwmgr, table, table_id); 380 else 381 ret = vega10_copy_table_to_smc(hwmgr, table, table_id); 382 383 return ret; 384 } 385 386 const struct pp_smumgr_func vega10_smu_funcs = { 387 .name = "vega10_smu", 388 .smu_init = &vega10_smu_init, 389 .smu_fini = &vega10_smu_fini, 390 .start_smu = &vega10_start_smu, 391 .request_smu_load_specific_fw = NULL, 392 .send_msg_to_smc = &smu9_send_msg_to_smc, 393 .send_msg_to_smc_with_parameter = &smu9_send_msg_to_smc_with_parameter, 394 .download_pptable_settings = NULL, 395 .upload_pptable_settings = NULL, 396 .is_dpm_running = vega10_is_dpm_running, 397 .get_argument = smu9_get_argument, 398 .smc_table_manager = vega10_smc_table_manager, 399 }; 400