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 134 if (features_enabled == NULL) 135 return -EINVAL; 136 137 smum_send_msg_to_smc(hwmgr, 138 PPSMC_MSG_GetEnabledSmuFeatures, 139 &enabled_features); 140 *features_enabled = enabled_features; 141 142 return 0; 143 } 144 145 static bool vega10_is_dpm_running(struct pp_hwmgr *hwmgr) 146 { 147 uint64_t features_enabled = 0; 148 149 vega10_get_enabled_smc_features(hwmgr, &features_enabled); 150 151 if (features_enabled & SMC_DPM_FEATURES) 152 return true; 153 else 154 return false; 155 } 156 157 static int vega10_set_tools_address(struct pp_hwmgr *hwmgr) 158 { 159 struct vega10_smumgr *priv = hwmgr->smu_backend; 160 161 if (priv->smu_tables.entry[TOOLSTABLE].mc_addr) { 162 smum_send_msg_to_smc_with_parameter(hwmgr, 163 PPSMC_MSG_SetToolsDramAddrHigh, 164 upper_32_bits(priv->smu_tables.entry[TOOLSTABLE].mc_addr), 165 NULL); 166 smum_send_msg_to_smc_with_parameter(hwmgr, 167 PPSMC_MSG_SetToolsDramAddrLow, 168 lower_32_bits(priv->smu_tables.entry[TOOLSTABLE].mc_addr), 169 NULL); 170 } 171 return 0; 172 } 173 174 static int vega10_verify_smc_interface(struct pp_hwmgr *hwmgr) 175 { 176 uint32_t smc_driver_if_version; 177 struct amdgpu_device *adev = hwmgr->adev; 178 uint32_t dev_id; 179 uint32_t rev_id; 180 181 PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc(hwmgr, 182 PPSMC_MSG_GetDriverIfVersion, 183 &smc_driver_if_version), 184 "Attempt to get SMC IF Version Number Failed!", 185 return -EINVAL); 186 187 dev_id = adev->pdev->device; 188 rev_id = adev->pdev->revision; 189 190 if (!((dev_id == 0x687f) && 191 ((rev_id == 0xc0) || 192 (rev_id == 0xc1) || 193 (rev_id == 0xc3)))) { 194 if (smc_driver_if_version != SMU9_DRIVER_IF_VERSION) { 195 pr_err("Your firmware(0x%x) doesn't match SMU9_DRIVER_IF_VERSION(0x%x). Please update your firmware!\n", 196 smc_driver_if_version, SMU9_DRIVER_IF_VERSION); 197 return -EINVAL; 198 } 199 } 200 201 return 0; 202 } 203 204 static int vega10_smu_init(struct pp_hwmgr *hwmgr) 205 { 206 struct vega10_smumgr *priv; 207 unsigned long tools_size; 208 int ret; 209 struct cgs_firmware_info info = {0}; 210 211 ret = cgs_get_firmware_info(hwmgr->device, 212 CGS_UCODE_ID_SMU, 213 &info); 214 if (ret || !info.kptr) 215 return -EINVAL; 216 217 priv = kzalloc(sizeof(struct vega10_smumgr), GFP_KERNEL); 218 219 if (!priv) 220 return -ENOMEM; 221 222 hwmgr->smu_backend = priv; 223 224 /* allocate space for pptable */ 225 ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, 226 sizeof(PPTable_t), 227 PAGE_SIZE, 228 AMDGPU_GEM_DOMAIN_VRAM, 229 &priv->smu_tables.entry[PPTABLE].handle, 230 &priv->smu_tables.entry[PPTABLE].mc_addr, 231 &priv->smu_tables.entry[PPTABLE].table); 232 if (ret) 233 goto free_backend; 234 235 priv->smu_tables.entry[PPTABLE].version = 0x01; 236 priv->smu_tables.entry[PPTABLE].size = sizeof(PPTable_t); 237 priv->smu_tables.entry[PPTABLE].table_id = TABLE_PPTABLE; 238 239 /* allocate space for watermarks table */ 240 ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, 241 sizeof(Watermarks_t), 242 PAGE_SIZE, 243 AMDGPU_GEM_DOMAIN_VRAM, 244 &priv->smu_tables.entry[WMTABLE].handle, 245 &priv->smu_tables.entry[WMTABLE].mc_addr, 246 &priv->smu_tables.entry[WMTABLE].table); 247 248 if (ret) 249 goto err0; 250 251 priv->smu_tables.entry[WMTABLE].version = 0x01; 252 priv->smu_tables.entry[WMTABLE].size = sizeof(Watermarks_t); 253 priv->smu_tables.entry[WMTABLE].table_id = TABLE_WATERMARKS; 254 255 /* allocate space for AVFS table */ 256 ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, 257 sizeof(AvfsTable_t), 258 PAGE_SIZE, 259 AMDGPU_GEM_DOMAIN_VRAM, 260 &priv->smu_tables.entry[AVFSTABLE].handle, 261 &priv->smu_tables.entry[AVFSTABLE].mc_addr, 262 &priv->smu_tables.entry[AVFSTABLE].table); 263 264 if (ret) 265 goto err1; 266 267 priv->smu_tables.entry[AVFSTABLE].version = 0x01; 268 priv->smu_tables.entry[AVFSTABLE].size = sizeof(AvfsTable_t); 269 priv->smu_tables.entry[AVFSTABLE].table_id = TABLE_AVFS; 270 271 tools_size = 0x19000; 272 if (tools_size) { 273 ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, 274 tools_size, 275 PAGE_SIZE, 276 AMDGPU_GEM_DOMAIN_VRAM, 277 &priv->smu_tables.entry[TOOLSTABLE].handle, 278 &priv->smu_tables.entry[TOOLSTABLE].mc_addr, 279 &priv->smu_tables.entry[TOOLSTABLE].table); 280 if (ret) 281 goto err2; 282 priv->smu_tables.entry[TOOLSTABLE].version = 0x01; 283 priv->smu_tables.entry[TOOLSTABLE].size = tools_size; 284 priv->smu_tables.entry[TOOLSTABLE].table_id = TABLE_PMSTATUSLOG; 285 } 286 287 /* allocate space for AVFS Fuse table */ 288 ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, 289 sizeof(AvfsFuseOverride_t), 290 PAGE_SIZE, 291 AMDGPU_GEM_DOMAIN_VRAM, 292 &priv->smu_tables.entry[AVFSFUSETABLE].handle, 293 &priv->smu_tables.entry[AVFSFUSETABLE].mc_addr, 294 &priv->smu_tables.entry[AVFSFUSETABLE].table); 295 if (ret) 296 goto err3; 297 298 priv->smu_tables.entry[AVFSFUSETABLE].version = 0x01; 299 priv->smu_tables.entry[AVFSFUSETABLE].size = sizeof(AvfsFuseOverride_t); 300 priv->smu_tables.entry[AVFSFUSETABLE].table_id = TABLE_AVFS_FUSE_OVERRIDE; 301 302 303 return 0; 304 305 err3: 306 if (priv->smu_tables.entry[TOOLSTABLE].table) 307 amdgpu_bo_free_kernel(&priv->smu_tables.entry[TOOLSTABLE].handle, 308 &priv->smu_tables.entry[TOOLSTABLE].mc_addr, 309 &priv->smu_tables.entry[TOOLSTABLE].table); 310 err2: 311 amdgpu_bo_free_kernel(&priv->smu_tables.entry[AVFSTABLE].handle, 312 &priv->smu_tables.entry[AVFSTABLE].mc_addr, 313 &priv->smu_tables.entry[AVFSTABLE].table); 314 err1: 315 amdgpu_bo_free_kernel(&priv->smu_tables.entry[WMTABLE].handle, 316 &priv->smu_tables.entry[WMTABLE].mc_addr, 317 &priv->smu_tables.entry[WMTABLE].table); 318 err0: 319 amdgpu_bo_free_kernel(&priv->smu_tables.entry[PPTABLE].handle, 320 &priv->smu_tables.entry[PPTABLE].mc_addr, 321 &priv->smu_tables.entry[PPTABLE].table); 322 free_backend: 323 kfree(hwmgr->smu_backend); 324 325 return -EINVAL; 326 } 327 328 static int vega10_smu_fini(struct pp_hwmgr *hwmgr) 329 { 330 struct vega10_smumgr *priv = hwmgr->smu_backend; 331 332 if (priv) { 333 amdgpu_bo_free_kernel(&priv->smu_tables.entry[PPTABLE].handle, 334 &priv->smu_tables.entry[PPTABLE].mc_addr, 335 &priv->smu_tables.entry[PPTABLE].table); 336 amdgpu_bo_free_kernel(&priv->smu_tables.entry[WMTABLE].handle, 337 &priv->smu_tables.entry[WMTABLE].mc_addr, 338 &priv->smu_tables.entry[WMTABLE].table); 339 amdgpu_bo_free_kernel(&priv->smu_tables.entry[AVFSTABLE].handle, 340 &priv->smu_tables.entry[AVFSTABLE].mc_addr, 341 &priv->smu_tables.entry[AVFSTABLE].table); 342 if (priv->smu_tables.entry[TOOLSTABLE].table) 343 amdgpu_bo_free_kernel(&priv->smu_tables.entry[TOOLSTABLE].handle, 344 &priv->smu_tables.entry[TOOLSTABLE].mc_addr, 345 &priv->smu_tables.entry[TOOLSTABLE].table); 346 amdgpu_bo_free_kernel(&priv->smu_tables.entry[AVFSFUSETABLE].handle, 347 &priv->smu_tables.entry[AVFSFUSETABLE].mc_addr, 348 &priv->smu_tables.entry[AVFSFUSETABLE].table); 349 kfree(hwmgr->smu_backend); 350 hwmgr->smu_backend = NULL; 351 } 352 return 0; 353 } 354 355 static int vega10_start_smu(struct pp_hwmgr *hwmgr) 356 { 357 if (!smu9_is_smc_ram_running(hwmgr)) 358 return -EINVAL; 359 360 PP_ASSERT_WITH_CODE(!vega10_verify_smc_interface(hwmgr), 361 "Failed to verify SMC interface!", 362 return -EINVAL); 363 364 vega10_set_tools_address(hwmgr); 365 366 return 0; 367 } 368 369 static int vega10_smc_table_manager(struct pp_hwmgr *hwmgr, uint8_t *table, 370 uint16_t table_id, bool rw) 371 { 372 int ret; 373 374 if (rw) 375 ret = vega10_copy_table_from_smc(hwmgr, table, table_id); 376 else 377 ret = vega10_copy_table_to_smc(hwmgr, table, table_id); 378 379 return ret; 380 } 381 382 const struct pp_smumgr_func vega10_smu_funcs = { 383 .name = "vega10_smu", 384 .smu_init = &vega10_smu_init, 385 .smu_fini = &vega10_smu_fini, 386 .start_smu = &vega10_start_smu, 387 .request_smu_load_specific_fw = NULL, 388 .send_msg_to_smc = &smu9_send_msg_to_smc, 389 .send_msg_to_smc_with_parameter = &smu9_send_msg_to_smc_with_parameter, 390 .download_pptable_settings = NULL, 391 .upload_pptable_settings = NULL, 392 .is_dpm_running = vega10_is_dpm_running, 393 .get_argument = smu9_get_argument, 394 .smc_table_manager = vega10_smc_table_manager, 395 }; 396