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 ret = cgs_get_firmware_info(hwmgr->device, 213 CGS_UCODE_ID_SMU, 214 &info); 215 if (ret || !info.kptr) 216 return -EINVAL; 217 218 priv = kzalloc(sizeof(struct vega10_smumgr), GFP_KERNEL); 219 220 if (!priv) 221 return -ENOMEM; 222 223 hwmgr->smu_backend = priv; 224 225 /* allocate space for pptable */ 226 ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, 227 sizeof(PPTable_t), 228 PAGE_SIZE, 229 AMDGPU_GEM_DOMAIN_VRAM, 230 &priv->smu_tables.entry[PPTABLE].handle, 231 &priv->smu_tables.entry[PPTABLE].mc_addr, 232 &priv->smu_tables.entry[PPTABLE].table); 233 if (ret) 234 goto free_backend; 235 236 priv->smu_tables.entry[PPTABLE].version = 0x01; 237 priv->smu_tables.entry[PPTABLE].size = sizeof(PPTable_t); 238 priv->smu_tables.entry[PPTABLE].table_id = TABLE_PPTABLE; 239 240 /* allocate space for watermarks table */ 241 ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, 242 sizeof(Watermarks_t), 243 PAGE_SIZE, 244 AMDGPU_GEM_DOMAIN_VRAM, 245 &priv->smu_tables.entry[WMTABLE].handle, 246 &priv->smu_tables.entry[WMTABLE].mc_addr, 247 &priv->smu_tables.entry[WMTABLE].table); 248 249 if (ret) 250 goto err0; 251 252 priv->smu_tables.entry[WMTABLE].version = 0x01; 253 priv->smu_tables.entry[WMTABLE].size = sizeof(Watermarks_t); 254 priv->smu_tables.entry[WMTABLE].table_id = TABLE_WATERMARKS; 255 256 /* allocate space for AVFS table */ 257 ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, 258 sizeof(AvfsTable_t), 259 PAGE_SIZE, 260 AMDGPU_GEM_DOMAIN_VRAM, 261 &priv->smu_tables.entry[AVFSTABLE].handle, 262 &priv->smu_tables.entry[AVFSTABLE].mc_addr, 263 &priv->smu_tables.entry[AVFSTABLE].table); 264 265 if (ret) 266 goto err1; 267 268 priv->smu_tables.entry[AVFSTABLE].version = 0x01; 269 priv->smu_tables.entry[AVFSTABLE].size = sizeof(AvfsTable_t); 270 priv->smu_tables.entry[AVFSTABLE].table_id = TABLE_AVFS; 271 272 tools_size = 0x19000; 273 if (tools_size) { 274 ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, 275 tools_size, 276 PAGE_SIZE, 277 AMDGPU_GEM_DOMAIN_VRAM, 278 &priv->smu_tables.entry[TOOLSTABLE].handle, 279 &priv->smu_tables.entry[TOOLSTABLE].mc_addr, 280 &priv->smu_tables.entry[TOOLSTABLE].table); 281 if (ret) 282 goto err2; 283 priv->smu_tables.entry[TOOLSTABLE].version = 0x01; 284 priv->smu_tables.entry[TOOLSTABLE].size = tools_size; 285 priv->smu_tables.entry[TOOLSTABLE].table_id = TABLE_PMSTATUSLOG; 286 } 287 288 /* allocate space for AVFS Fuse table */ 289 ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, 290 sizeof(AvfsFuseOverride_t), 291 PAGE_SIZE, 292 AMDGPU_GEM_DOMAIN_VRAM, 293 &priv->smu_tables.entry[AVFSFUSETABLE].handle, 294 &priv->smu_tables.entry[AVFSFUSETABLE].mc_addr, 295 &priv->smu_tables.entry[AVFSFUSETABLE].table); 296 if (ret) 297 goto err3; 298 299 priv->smu_tables.entry[AVFSFUSETABLE].version = 0x01; 300 priv->smu_tables.entry[AVFSFUSETABLE].size = sizeof(AvfsFuseOverride_t); 301 priv->smu_tables.entry[AVFSFUSETABLE].table_id = TABLE_AVFS_FUSE_OVERRIDE; 302 303 304 return 0; 305 306 err3: 307 if (priv->smu_tables.entry[TOOLSTABLE].table) 308 amdgpu_bo_free_kernel(&priv->smu_tables.entry[TOOLSTABLE].handle, 309 &priv->smu_tables.entry[TOOLSTABLE].mc_addr, 310 &priv->smu_tables.entry[TOOLSTABLE].table); 311 err2: 312 amdgpu_bo_free_kernel(&priv->smu_tables.entry[AVFSTABLE].handle, 313 &priv->smu_tables.entry[AVFSTABLE].mc_addr, 314 &priv->smu_tables.entry[AVFSTABLE].table); 315 err1: 316 amdgpu_bo_free_kernel(&priv->smu_tables.entry[WMTABLE].handle, 317 &priv->smu_tables.entry[WMTABLE].mc_addr, 318 &priv->smu_tables.entry[WMTABLE].table); 319 err0: 320 amdgpu_bo_free_kernel(&priv->smu_tables.entry[PPTABLE].handle, 321 &priv->smu_tables.entry[PPTABLE].mc_addr, 322 &priv->smu_tables.entry[PPTABLE].table); 323 free_backend: 324 kfree(hwmgr->smu_backend); 325 326 return -EINVAL; 327 } 328 329 static int vega10_smu_fini(struct pp_hwmgr *hwmgr) 330 { 331 struct vega10_smumgr *priv = hwmgr->smu_backend; 332 333 if (priv) { 334 amdgpu_bo_free_kernel(&priv->smu_tables.entry[PPTABLE].handle, 335 &priv->smu_tables.entry[PPTABLE].mc_addr, 336 &priv->smu_tables.entry[PPTABLE].table); 337 amdgpu_bo_free_kernel(&priv->smu_tables.entry[WMTABLE].handle, 338 &priv->smu_tables.entry[WMTABLE].mc_addr, 339 &priv->smu_tables.entry[WMTABLE].table); 340 amdgpu_bo_free_kernel(&priv->smu_tables.entry[AVFSTABLE].handle, 341 &priv->smu_tables.entry[AVFSTABLE].mc_addr, 342 &priv->smu_tables.entry[AVFSTABLE].table); 343 if (priv->smu_tables.entry[TOOLSTABLE].table) 344 amdgpu_bo_free_kernel(&priv->smu_tables.entry[TOOLSTABLE].handle, 345 &priv->smu_tables.entry[TOOLSTABLE].mc_addr, 346 &priv->smu_tables.entry[TOOLSTABLE].table); 347 amdgpu_bo_free_kernel(&priv->smu_tables.entry[AVFSFUSETABLE].handle, 348 &priv->smu_tables.entry[AVFSFUSETABLE].mc_addr, 349 &priv->smu_tables.entry[AVFSFUSETABLE].table); 350 kfree(hwmgr->smu_backend); 351 hwmgr->smu_backend = NULL; 352 } 353 return 0; 354 } 355 356 static int vega10_start_smu(struct pp_hwmgr *hwmgr) 357 { 358 if (!smu9_is_smc_ram_running(hwmgr)) 359 return -EINVAL; 360 361 PP_ASSERT_WITH_CODE(!vega10_verify_smc_interface(hwmgr), 362 "Failed to verify SMC interface!", 363 return -EINVAL); 364 365 vega10_set_tools_address(hwmgr); 366 367 return 0; 368 } 369 370 static int vega10_smc_table_manager(struct pp_hwmgr *hwmgr, uint8_t *table, 371 uint16_t table_id, bool rw) 372 { 373 int ret; 374 375 if (rw) 376 ret = vega10_copy_table_from_smc(hwmgr, table, table_id); 377 else 378 ret = vega10_copy_table_to_smc(hwmgr, table, table_id); 379 380 return ret; 381 } 382 383 const struct pp_smumgr_func vega10_smu_funcs = { 384 .name = "vega10_smu", 385 .smu_init = &vega10_smu_init, 386 .smu_fini = &vega10_smu_fini, 387 .start_smu = &vega10_start_smu, 388 .request_smu_load_specific_fw = NULL, 389 .send_msg_to_smc = &smu9_send_msg_to_smc, 390 .send_msg_to_smc_with_parameter = &smu9_send_msg_to_smc_with_parameter, 391 .download_pptable_settings = NULL, 392 .upload_pptable_settings = NULL, 393 .is_dpm_running = vega10_is_dpm_running, 394 .get_argument = smu9_get_argument, 395 .smc_table_manager = vega10_smc_table_manager, 396 }; 397