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