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