Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/amd/powerplay: add Carrizo smu support

This implements the SMU firmware manager interface for CZ.
Some header files are moved from amdgpu folder to powerplay as well.

v3: delete peci sub-module.
v2: use cgs interface directly
add load_mec_firmware function

Signed-off-by: Rex Zhu <Rex.Zhu@amd.com>
Signed-off-by: Jammy Zhou <Jammy.Zhou@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>

authored by

Jammy Zhou and committed by
Alex Deucher
4630f0fa 3bace359

+963 -2
drivers/gpu/drm/amd/amdgpu/cz_ppsmc.h drivers/gpu/drm/amd/powerplay/inc/cz_ppsmc.h
drivers/gpu/drm/amd/amdgpu/smu8.h drivers/gpu/drm/amd/powerplay/inc/smu8.h
drivers/gpu/drm/amd/amdgpu/smu8_fusion.h drivers/gpu/drm/amd/powerplay/inc/smu8_fusion.h
drivers/gpu/drm/amd/amdgpu/smu_ucode_xfer_cz.h drivers/gpu/drm/amd/powerplay/inc/smu_ucode_xfer_cz.h
+1 -1
drivers/gpu/drm/amd/powerplay/smumgr/Makefile
··· 2 2 # Makefile for the 'smu manager' sub-component of powerplay. 3 3 # It provides the smu management services for the driver. 4 4 5 - SMU_MGR = smumgr.o 5 + SMU_MGR = smumgr.o cz_smumgr.o 6 6 7 7 AMD_PP_SMUMGR = $(addprefix $(AMD_PP_PATH)/smumgr/,$(SMU_MGR)) 8 8
+858
drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.c
··· 1 + /* 2 + * Copyright 2015 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 + #include <linux/types.h> 24 + #include <linux/kernel.h> 25 + #include <linux/slab.h> 26 + #include <linux/gfp.h> 27 + #include "linux/delay.h" 28 + #include "cgs_common.h" 29 + #include "smu/smu_8_0_d.h" 30 + #include "smu/smu_8_0_sh_mask.h" 31 + #include "smu8.h" 32 + #include "smu8_fusion.h" 33 + #include "cz_smumgr.h" 34 + #include "cz_ppsmc.h" 35 + #include "smu_ucode_xfer_cz.h" 36 + #include "gca/gfx_8_0_d.h" 37 + #include "gca/gfx_8_0_sh_mask.h" 38 + #include "smumgr.h" 39 + 40 + #define SIZE_ALIGN_32(x) (((x) + 31) / 32 * 32) 41 + 42 + static enum cz_scratch_entry firmware_list[] = { 43 + CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0, 44 + CZ_SCRATCH_ENTRY_UCODE_ID_SDMA1, 45 + CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE, 46 + CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP, 47 + CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME, 48 + CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, 49 + CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2, 50 + CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G, 51 + }; 52 + 53 + static int cz_smum_get_argument(struct pp_smumgr *smumgr) 54 + { 55 + if (smumgr == NULL || smumgr->device == NULL) 56 + return -EINVAL; 57 + 58 + return cgs_read_register(smumgr->device, 59 + mmSMU_MP1_SRBM2P_ARG_0); 60 + } 61 + 62 + static int cz_send_msg_to_smc_async(struct pp_smumgr *smumgr, 63 + uint16_t msg) 64 + { 65 + int result = 0; 66 + 67 + if (smumgr == NULL || smumgr->device == NULL) 68 + return -EINVAL; 69 + 70 + result = SMUM_WAIT_FIELD_UNEQUAL(smumgr, 71 + SMU_MP1_SRBM2P_RESP_0, CONTENT, 0); 72 + if (result != 0) { 73 + printk(KERN_ERR "[ powerplay ] cz_send_msg_to_smc_async failed\n"); 74 + return result; 75 + } 76 + 77 + cgs_write_register(smumgr->device, mmSMU_MP1_SRBM2P_RESP_0, 0); 78 + cgs_write_register(smumgr->device, mmSMU_MP1_SRBM2P_MSG_0, msg); 79 + 80 + return 0; 81 + } 82 + 83 + /* Send a message to the SMC, and wait for its response.*/ 84 + static int cz_send_msg_to_smc(struct pp_smumgr *smumgr, uint16_t msg) 85 + { 86 + int result = 0; 87 + 88 + result = cz_send_msg_to_smc_async(smumgr, msg); 89 + if (result != 0) 90 + return result; 91 + 92 + result = SMUM_WAIT_FIELD_UNEQUAL(smumgr, 93 + SMU_MP1_SRBM2P_RESP_0, CONTENT, 0); 94 + 95 + if (result != 0) 96 + return result; 97 + 98 + return 0; 99 + } 100 + 101 + static int cz_set_smc_sram_address(struct pp_smumgr *smumgr, 102 + uint32_t smc_address, uint32_t limit) 103 + { 104 + if (smumgr == NULL || smumgr->device == NULL) 105 + return -EINVAL; 106 + 107 + if (0 != (3 & smc_address)) { 108 + printk(KERN_ERR "[ powerplay ] SMC address must be 4 byte aligned\n"); 109 + return -1; 110 + } 111 + 112 + if (limit <= (smc_address + 3)) { 113 + printk(KERN_ERR "[ powerplay ] SMC address beyond the SMC RAM area\n"); 114 + return -1; 115 + } 116 + 117 + cgs_write_register(smumgr->device, mmMP0PUB_IND_INDEX_0, 118 + SMN_MP1_SRAM_START_ADDR + smc_address); 119 + 120 + return 0; 121 + } 122 + 123 + static int cz_write_smc_sram_dword(struct pp_smumgr *smumgr, 124 + uint32_t smc_address, uint32_t value, uint32_t limit) 125 + { 126 + int result; 127 + 128 + if (smumgr == NULL || smumgr->device == NULL) 129 + return -EINVAL; 130 + 131 + result = cz_set_smc_sram_address(smumgr, smc_address, limit); 132 + cgs_write_register(smumgr->device, mmMP0PUB_IND_DATA_0, value); 133 + 134 + return 0; 135 + } 136 + 137 + static int cz_send_msg_to_smc_with_parameter(struct pp_smumgr *smumgr, 138 + uint16_t msg, uint32_t parameter) 139 + { 140 + if (smumgr == NULL || smumgr->device == NULL) 141 + return -EINVAL; 142 + 143 + cgs_write_register(smumgr->device, mmSMU_MP1_SRBM2P_ARG_0, parameter); 144 + 145 + return cz_send_msg_to_smc(smumgr, msg); 146 + } 147 + 148 + static int cz_request_smu_load_fw(struct pp_smumgr *smumgr) 149 + { 150 + struct cz_smumgr *cz_smu = (struct cz_smumgr *)(smumgr->backend); 151 + int result = 0; 152 + uint32_t smc_address; 153 + 154 + if (!smumgr->reload_fw) { 155 + printk(KERN_INFO "[ powerplay ] skip reloading...\n"); 156 + return 0; 157 + } 158 + 159 + smc_address = SMU8_FIRMWARE_HEADER_LOCATION + 160 + offsetof(struct SMU8_Firmware_Header, UcodeLoadStatus); 161 + 162 + cz_write_smc_sram_dword(smumgr, smc_address, 0, smc_address+4); 163 + 164 + cz_send_msg_to_smc_with_parameter(smumgr, 165 + PPSMC_MSG_DriverDramAddrHi, 166 + cz_smu->toc_buffer.mc_addr_high); 167 + 168 + cz_send_msg_to_smc_with_parameter(smumgr, 169 + PPSMC_MSG_DriverDramAddrLo, 170 + cz_smu->toc_buffer.mc_addr_low); 171 + 172 + cz_send_msg_to_smc(smumgr, PPSMC_MSG_InitJobs); 173 + 174 + cz_send_msg_to_smc_with_parameter(smumgr, 175 + PPSMC_MSG_ExecuteJob, 176 + cz_smu->toc_entry_aram); 177 + cz_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_ExecuteJob, 178 + cz_smu->toc_entry_power_profiling_index); 179 + 180 + result = cz_send_msg_to_smc_with_parameter(smumgr, 181 + PPSMC_MSG_ExecuteJob, 182 + cz_smu->toc_entry_initialize_index); 183 + 184 + return result; 185 + } 186 + 187 + static int cz_check_fw_load_finish(struct pp_smumgr *smumgr, 188 + uint32_t firmware) 189 + { 190 + int i; 191 + uint32_t index = SMN_MP1_SRAM_START_ADDR + 192 + SMU8_FIRMWARE_HEADER_LOCATION + 193 + offsetof(struct SMU8_Firmware_Header, UcodeLoadStatus); 194 + 195 + if (smumgr == NULL || smumgr->device == NULL) 196 + return -EINVAL; 197 + 198 + return cgs_read_register(smumgr->device, 199 + mmSMU_MP1_SRBM2P_ARG_0); 200 + 201 + cgs_write_register(smumgr->device, mmMP0PUB_IND_INDEX, index); 202 + 203 + for (i = 0; i < smumgr->usec_timeout; i++) { 204 + if (firmware == 205 + (cgs_read_register(smumgr->device, mmMP0PUB_IND_DATA) & firmware)) 206 + break; 207 + udelay(1); 208 + } 209 + 210 + if (i >= smumgr->usec_timeout) { 211 + printk(KERN_ERR "[ powerplay ] SMU check loaded firmware failed.\n"); 212 + return -EINVAL; 213 + } 214 + 215 + return 0; 216 + } 217 + 218 + static int cz_load_mec_firmware(struct pp_smumgr *smumgr) 219 + { 220 + uint32_t reg_data; 221 + uint32_t tmp; 222 + int ret = 0; 223 + struct cgs_firmware_info info = {0}; 224 + struct cz_smumgr *cz_smu; 225 + 226 + if (smumgr == NULL || smumgr->device == NULL) 227 + return -EINVAL; 228 + 229 + cz_smu = (struct cz_smumgr *)smumgr->backend; 230 + ret = cgs_get_firmware_info(smumgr->device, 231 + CGS_UCODE_ID_CP_MEC, &info); 232 + 233 + if (ret) 234 + return -EINVAL; 235 + 236 + /* Disable MEC parsing/prefetching */ 237 + tmp = cgs_read_register(smumgr->device, 238 + mmCP_MEC_CNTL); 239 + tmp = SMUM_SET_FIELD(tmp, CP_MEC_CNTL, MEC_ME1_HALT, 1); 240 + tmp = SMUM_SET_FIELD(tmp, CP_MEC_CNTL, MEC_ME2_HALT, 1); 241 + cgs_write_register(smumgr->device, mmCP_MEC_CNTL, tmp); 242 + 243 + tmp = cgs_read_register(smumgr->device, 244 + mmCP_CPC_IC_BASE_CNTL); 245 + 246 + tmp = SMUM_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, VMID, 0); 247 + tmp = SMUM_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, ATC, 0); 248 + tmp = SMUM_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, CACHE_POLICY, 0); 249 + tmp = SMUM_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, MTYPE, 1); 250 + cgs_write_register(smumgr->device, mmCP_CPC_IC_BASE_CNTL, tmp); 251 + 252 + reg_data = smu_lower_32_bits(info.mc_addr) & 253 + SMUM_FIELD_MASK(CP_CPC_IC_BASE_LO, IC_BASE_LO); 254 + cgs_write_register(smumgr->device, mmCP_CPC_IC_BASE_LO, reg_data); 255 + 256 + reg_data = smu_upper_32_bits(info.mc_addr) & 257 + SMUM_FIELD_MASK(CP_CPC_IC_BASE_HI, IC_BASE_HI); 258 + cgs_write_register(smumgr->device, mmCP_CPC_IC_BASE_HI, reg_data); 259 + 260 + return 0; 261 + } 262 + 263 + static int cz_start_smu(struct pp_smumgr *smumgr) 264 + { 265 + int ret = 0; 266 + uint32_t fw_to_check = UCODE_ID_RLC_G_MASK | 267 + UCODE_ID_SDMA0_MASK | 268 + UCODE_ID_SDMA1_MASK | 269 + UCODE_ID_CP_CE_MASK | 270 + UCODE_ID_CP_ME_MASK | 271 + UCODE_ID_CP_PFP_MASK | 272 + UCODE_ID_CP_MEC_JT1_MASK | 273 + UCODE_ID_CP_MEC_JT2_MASK; 274 + 275 + cz_request_smu_load_fw(smumgr); 276 + cz_check_fw_load_finish(smumgr, fw_to_check); 277 + 278 + ret = cz_load_mec_firmware(smumgr); 279 + if (ret) 280 + printk(KERN_ERR "[ powerplay ] Mec Firmware load failed\n"); 281 + 282 + return ret; 283 + } 284 + 285 + static uint8_t cz_translate_firmware_enum_to_arg( 286 + enum cz_scratch_entry firmware_enum) 287 + { 288 + uint8_t ret = 0; 289 + 290 + switch (firmware_enum) { 291 + case CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0: 292 + ret = UCODE_ID_SDMA0; 293 + break; 294 + case CZ_SCRATCH_ENTRY_UCODE_ID_SDMA1: 295 + ret = UCODE_ID_SDMA1; 296 + break; 297 + case CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE: 298 + ret = UCODE_ID_CP_CE; 299 + break; 300 + case CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP: 301 + ret = UCODE_ID_CP_PFP; 302 + break; 303 + case CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME: 304 + ret = UCODE_ID_CP_ME; 305 + break; 306 + case CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1: 307 + ret = UCODE_ID_CP_MEC_JT1; 308 + break; 309 + case CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2: 310 + ret = UCODE_ID_CP_MEC_JT2; 311 + break; 312 + case CZ_SCRATCH_ENTRY_UCODE_ID_GMCON_RENG: 313 + ret = UCODE_ID_GMCON_RENG; 314 + break; 315 + case CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G: 316 + ret = UCODE_ID_RLC_G; 317 + break; 318 + case CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH: 319 + ret = UCODE_ID_RLC_SCRATCH; 320 + break; 321 + case CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM: 322 + ret = UCODE_ID_RLC_SRM_ARAM; 323 + break; 324 + case CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM: 325 + ret = UCODE_ID_RLC_SRM_DRAM; 326 + break; 327 + case CZ_SCRATCH_ENTRY_UCODE_ID_DMCU_ERAM: 328 + ret = UCODE_ID_DMCU_ERAM; 329 + break; 330 + case CZ_SCRATCH_ENTRY_UCODE_ID_DMCU_IRAM: 331 + ret = UCODE_ID_DMCU_IRAM; 332 + break; 333 + case CZ_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING: 334 + ret = TASK_ARG_INIT_MM_PWR_LOG; 335 + break; 336 + case CZ_SCRATCH_ENTRY_DATA_ID_SDMA_HALT: 337 + case CZ_SCRATCH_ENTRY_DATA_ID_SYS_CLOCKGATING: 338 + case CZ_SCRATCH_ENTRY_DATA_ID_SDMA_RING_REGS: 339 + case CZ_SCRATCH_ENTRY_DATA_ID_NONGFX_REINIT: 340 + case CZ_SCRATCH_ENTRY_DATA_ID_SDMA_START: 341 + case CZ_SCRATCH_ENTRY_DATA_ID_IH_REGISTERS: 342 + ret = TASK_ARG_REG_MMIO; 343 + break; 344 + case CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE: 345 + ret = TASK_ARG_INIT_CLK_TABLE; 346 + break; 347 + } 348 + 349 + return ret; 350 + } 351 + 352 + static enum cgs_ucode_id cz_convert_fw_type_to_cgs(uint32_t fw_type) 353 + { 354 + enum cgs_ucode_id result = CGS_UCODE_ID_MAXIMUM; 355 + 356 + switch (fw_type) { 357 + case UCODE_ID_SDMA0: 358 + result = CGS_UCODE_ID_SDMA0; 359 + break; 360 + case UCODE_ID_SDMA1: 361 + result = CGS_UCODE_ID_SDMA1; 362 + break; 363 + case UCODE_ID_CP_CE: 364 + result = CGS_UCODE_ID_CP_CE; 365 + break; 366 + case UCODE_ID_CP_PFP: 367 + result = CGS_UCODE_ID_CP_PFP; 368 + break; 369 + case UCODE_ID_CP_ME: 370 + result = CGS_UCODE_ID_CP_ME; 371 + break; 372 + case UCODE_ID_CP_MEC_JT1: 373 + result = CGS_UCODE_ID_CP_MEC_JT1; 374 + break; 375 + case UCODE_ID_CP_MEC_JT2: 376 + result = CGS_UCODE_ID_CP_MEC_JT2; 377 + break; 378 + case UCODE_ID_RLC_G: 379 + result = CGS_UCODE_ID_RLC_G; 380 + break; 381 + default: 382 + break; 383 + } 384 + 385 + return result; 386 + } 387 + 388 + static int cz_smu_populate_single_scratch_task( 389 + struct pp_smumgr *smumgr, 390 + enum cz_scratch_entry fw_enum, 391 + uint8_t type, bool is_last) 392 + { 393 + uint8_t i; 394 + struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend; 395 + struct TOC *toc = (struct TOC *)cz_smu->toc_buffer.kaddr; 396 + struct SMU_Task *task = &toc->tasks[cz_smu->toc_entry_used_count++]; 397 + 398 + task->type = type; 399 + task->arg = cz_translate_firmware_enum_to_arg(fw_enum); 400 + task->next = is_last ? END_OF_TASK_LIST : cz_smu->toc_entry_used_count; 401 + 402 + for (i = 0; i < cz_smu->scratch_buffer_length; i++) 403 + if (cz_smu->scratch_buffer[i].firmware_ID == fw_enum) 404 + break; 405 + 406 + if (i >= cz_smu->scratch_buffer_length) { 407 + printk(KERN_ERR "[ powerplay ] Invalid Firmware Type\n"); 408 + return -EINVAL; 409 + } 410 + 411 + task->addr.low = cz_smu->scratch_buffer[i].mc_addr_low; 412 + task->addr.high = cz_smu->scratch_buffer[i].mc_addr_high; 413 + task->size_bytes = cz_smu->scratch_buffer[i].data_size; 414 + 415 + if (CZ_SCRATCH_ENTRY_DATA_ID_IH_REGISTERS == fw_enum) { 416 + struct cz_ih_meta_data *pIHReg_restore = 417 + (struct cz_ih_meta_data *)cz_smu->scratch_buffer[i].kaddr; 418 + pIHReg_restore->command = 419 + METADATA_CMD_MODE0 | METADATA_PERFORM_ON_LOAD; 420 + } 421 + 422 + return 0; 423 + } 424 + 425 + static int cz_smu_populate_single_ucode_load_task( 426 + struct pp_smumgr *smumgr, 427 + enum cz_scratch_entry fw_enum, 428 + bool is_last) 429 + { 430 + uint8_t i; 431 + struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend; 432 + struct TOC *toc = (struct TOC *)cz_smu->toc_buffer.kaddr; 433 + struct SMU_Task *task = &toc->tasks[cz_smu->toc_entry_used_count++]; 434 + 435 + task->type = TASK_TYPE_UCODE_LOAD; 436 + task->arg = cz_translate_firmware_enum_to_arg(fw_enum); 437 + task->next = is_last ? END_OF_TASK_LIST : cz_smu->toc_entry_used_count; 438 + 439 + for (i = 0; i < cz_smu->driver_buffer_length; i++) 440 + if (cz_smu->driver_buffer[i].firmware_ID == fw_enum) 441 + break; 442 + 443 + if (i >= cz_smu->driver_buffer_length) { 444 + printk(KERN_ERR "[ powerplay ] Invalid Firmware Type\n"); 445 + return -EINVAL; 446 + } 447 + 448 + task->addr.low = cz_smu->driver_buffer[i].mc_addr_low; 449 + task->addr.high = cz_smu->driver_buffer[i].mc_addr_high; 450 + task->size_bytes = cz_smu->driver_buffer[i].data_size; 451 + 452 + return 0; 453 + } 454 + 455 + static int cz_smu_construct_toc_for_rlc_aram_save(struct pp_smumgr *smumgr) 456 + { 457 + struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend; 458 + 459 + cz_smu->toc_entry_aram = cz_smu->toc_entry_used_count; 460 + cz_smu_populate_single_scratch_task(smumgr, 461 + CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM, 462 + TASK_TYPE_UCODE_SAVE, true); 463 + 464 + return 0; 465 + } 466 + 467 + static int cz_smu_initialize_toc_empty_job_list(struct pp_smumgr *smumgr) 468 + { 469 + int i; 470 + struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend; 471 + struct TOC *toc = (struct TOC *)cz_smu->toc_buffer.kaddr; 472 + 473 + for (i = 0; i < NUM_JOBLIST_ENTRIES; i++) 474 + toc->JobList[i] = (uint8_t)IGNORE_JOB; 475 + 476 + return 0; 477 + } 478 + 479 + static int cz_smu_construct_toc_for_vddgfx_enter(struct pp_smumgr *smumgr) 480 + { 481 + struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend; 482 + struct TOC *toc = (struct TOC *)cz_smu->toc_buffer.kaddr; 483 + 484 + toc->JobList[JOB_GFX_SAVE] = (uint8_t)cz_smu->toc_entry_used_count; 485 + cz_smu_populate_single_scratch_task(smumgr, 486 + CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH, 487 + TASK_TYPE_UCODE_SAVE, false); 488 + 489 + cz_smu_populate_single_scratch_task(smumgr, 490 + CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM, 491 + TASK_TYPE_UCODE_SAVE, true); 492 + 493 + return 0; 494 + } 495 + 496 + 497 + static int cz_smu_construct_toc_for_vddgfx_exit(struct pp_smumgr *smumgr) 498 + { 499 + struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend; 500 + struct TOC *toc = (struct TOC *)cz_smu->toc_buffer.kaddr; 501 + 502 + toc->JobList[JOB_GFX_RESTORE] = (uint8_t)cz_smu->toc_entry_used_count; 503 + 504 + cz_smu_populate_single_ucode_load_task(smumgr, 505 + CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE, false); 506 + cz_smu_populate_single_ucode_load_task(smumgr, 507 + CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP, false); 508 + cz_smu_populate_single_ucode_load_task(smumgr, 509 + CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME, false); 510 + cz_smu_populate_single_ucode_load_task(smumgr, 511 + CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, false); 512 + cz_smu_populate_single_ucode_load_task(smumgr, 513 + CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2, false); 514 + cz_smu_populate_single_ucode_load_task(smumgr, 515 + CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G, false); 516 + 517 + /* populate scratch */ 518 + cz_smu_populate_single_scratch_task(smumgr, 519 + CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH, 520 + TASK_TYPE_UCODE_LOAD, false); 521 + 522 + cz_smu_populate_single_scratch_task(smumgr, 523 + CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM, 524 + TASK_TYPE_UCODE_LOAD, false); 525 + 526 + cz_smu_populate_single_scratch_task(smumgr, 527 + CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM, 528 + TASK_TYPE_UCODE_LOAD, true); 529 + 530 + return 0; 531 + } 532 + 533 + static int cz_smu_construct_toc_for_power_profiling( 534 + struct pp_smumgr *smumgr) 535 + { 536 + struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend; 537 + 538 + cz_smu->toc_entry_power_profiling_index = cz_smu->toc_entry_used_count; 539 + 540 + cz_smu_populate_single_scratch_task(smumgr, 541 + CZ_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING, 542 + TASK_TYPE_INITIALIZE, true); 543 + return 0; 544 + } 545 + 546 + static int cz_smu_construct_toc_for_bootup(struct pp_smumgr *smumgr) 547 + { 548 + struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend; 549 + 550 + cz_smu->toc_entry_initialize_index = cz_smu->toc_entry_used_count; 551 + 552 + cz_smu_populate_single_ucode_load_task(smumgr, 553 + CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0, false); 554 + cz_smu_populate_single_ucode_load_task(smumgr, 555 + CZ_SCRATCH_ENTRY_UCODE_ID_SDMA1, false); 556 + cz_smu_populate_single_ucode_load_task(smumgr, 557 + CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE, false); 558 + cz_smu_populate_single_ucode_load_task(smumgr, 559 + CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP, false); 560 + cz_smu_populate_single_ucode_load_task(smumgr, 561 + CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME, false); 562 + cz_smu_populate_single_ucode_load_task(smumgr, 563 + CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, false); 564 + cz_smu_populate_single_ucode_load_task(smumgr, 565 + CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2, false); 566 + cz_smu_populate_single_ucode_load_task(smumgr, 567 + CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G, true); 568 + 569 + return 0; 570 + } 571 + 572 + static int cz_smu_construct_toc_for_clock_table(struct pp_smumgr *smumgr) 573 + { 574 + struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend; 575 + 576 + cz_smu->toc_entry_clock_table = cz_smu->toc_entry_used_count; 577 + 578 + cz_smu_populate_single_scratch_task(smumgr, 579 + CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE, 580 + TASK_TYPE_INITIALIZE, true); 581 + 582 + return 0; 583 + } 584 + 585 + static int cz_smu_construct_toc(struct pp_smumgr *smumgr) 586 + { 587 + struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend; 588 + 589 + cz_smu->toc_entry_used_count = 0; 590 + 591 + cz_smu_initialize_toc_empty_job_list(smumgr); 592 + 593 + cz_smu_construct_toc_for_rlc_aram_save(smumgr); 594 + 595 + cz_smu_construct_toc_for_vddgfx_enter(smumgr); 596 + 597 + cz_smu_construct_toc_for_vddgfx_exit(smumgr); 598 + 599 + cz_smu_construct_toc_for_power_profiling(smumgr); 600 + 601 + cz_smu_construct_toc_for_bootup(smumgr); 602 + 603 + cz_smu_construct_toc_for_clock_table(smumgr); 604 + 605 + return 0; 606 + } 607 + 608 + static int cz_smu_populate_firmware_entries(struct pp_smumgr *smumgr) 609 + { 610 + struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend; 611 + uint32_t firmware_type; 612 + uint32_t i; 613 + int ret; 614 + enum cgs_ucode_id ucode_id; 615 + struct cgs_firmware_info info = {0}; 616 + 617 + cz_smu->driver_buffer_length = 0; 618 + 619 + for (i = 0; i < sizeof(firmware_list)/sizeof(*firmware_list); i++) { 620 + 621 + firmware_type = cz_translate_firmware_enum_to_arg( 622 + firmware_list[i]); 623 + 624 + ucode_id = cz_convert_fw_type_to_cgs(firmware_type); 625 + 626 + ret = cgs_get_firmware_info(smumgr->device, 627 + ucode_id, &info); 628 + 629 + if (ret == 0) { 630 + cz_smu->driver_buffer[i].mc_addr_high = 631 + smu_upper_32_bits(info.mc_addr); 632 + 633 + cz_smu->driver_buffer[i].mc_addr_low = 634 + smu_lower_32_bits(info.mc_addr); 635 + 636 + cz_smu->driver_buffer[i].data_size = info.image_size; 637 + 638 + cz_smu->driver_buffer[i].firmware_ID = firmware_list[i]; 639 + cz_smu->driver_buffer_length++; 640 + } 641 + } 642 + 643 + return 0; 644 + } 645 + 646 + static int cz_smu_populate_single_scratch_entry( 647 + struct pp_smumgr *smumgr, 648 + enum cz_scratch_entry scratch_type, 649 + uint32_t ulsize_byte, 650 + struct cz_buffer_entry *entry) 651 + { 652 + struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend; 653 + long long mc_addr = 654 + ((long long)(cz_smu->smu_buffer.mc_addr_high) << 32) 655 + | cz_smu->smu_buffer.mc_addr_low; 656 + 657 + uint32_t ulsize_aligned = SIZE_ALIGN_32(ulsize_byte); 658 + 659 + mc_addr += cz_smu->smu_buffer_used_bytes; 660 + 661 + entry->data_size = ulsize_byte; 662 + entry->kaddr = (char *) cz_smu->smu_buffer.kaddr + 663 + cz_smu->smu_buffer_used_bytes; 664 + entry->mc_addr_low = smu_lower_32_bits(mc_addr); 665 + entry->mc_addr_high = smu_upper_32_bits(mc_addr); 666 + entry->firmware_ID = scratch_type; 667 + 668 + cz_smu->smu_buffer_used_bytes += ulsize_aligned; 669 + 670 + return 0; 671 + } 672 + 673 + static int cz_download_pptable_settings(struct pp_smumgr *smumgr, void **table) 674 + { 675 + struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend; 676 + unsigned long i; 677 + 678 + for (i = 0; i < cz_smu->scratch_buffer_length; i++) { 679 + if (cz_smu->scratch_buffer[i].firmware_ID 680 + == CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE) 681 + break; 682 + } 683 + 684 + *table = (struct SMU8_Fusion_ClkTable *)cz_smu->scratch_buffer[i].kaddr; 685 + 686 + cz_send_msg_to_smc_with_parameter(smumgr, 687 + PPSMC_MSG_SetClkTableAddrHi, 688 + cz_smu->scratch_buffer[i].mc_addr_high); 689 + 690 + cz_send_msg_to_smc_with_parameter(smumgr, 691 + PPSMC_MSG_SetClkTableAddrLo, 692 + cz_smu->scratch_buffer[i].mc_addr_low); 693 + 694 + cz_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_ExecuteJob, 695 + cz_smu->toc_entry_clock_table); 696 + 697 + cz_send_msg_to_smc(smumgr, PPSMC_MSG_ClkTableXferToDram); 698 + 699 + return 0; 700 + } 701 + 702 + static int cz_upload_pptable_settings(struct pp_smumgr *smumgr) 703 + { 704 + struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend; 705 + unsigned long i; 706 + 707 + for (i = 0; i < cz_smu->scratch_buffer_length; i++) { 708 + if (cz_smu->scratch_buffer[i].firmware_ID 709 + == CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE) 710 + break; 711 + } 712 + 713 + cz_send_msg_to_smc_with_parameter(smumgr, 714 + PPSMC_MSG_SetClkTableAddrHi, 715 + cz_smu->scratch_buffer[i].mc_addr_high); 716 + 717 + cz_send_msg_to_smc_with_parameter(smumgr, 718 + PPSMC_MSG_SetClkTableAddrLo, 719 + cz_smu->scratch_buffer[i].mc_addr_low); 720 + 721 + cz_send_msg_to_smc_with_parameter(smumgr, PPSMC_MSG_ExecuteJob, 722 + cz_smu->toc_entry_clock_table); 723 + 724 + cz_send_msg_to_smc(smumgr, PPSMC_MSG_ClkTableXferToSmu); 725 + 726 + return 0; 727 + } 728 + 729 + static int cz_smu_init(struct pp_smumgr *smumgr) 730 + { 731 + struct cz_smumgr *cz_smu = (struct cz_smumgr *)smumgr->backend; 732 + uint64_t mc_addr = 0; 733 + int ret = 0; 734 + 735 + cz_smu->toc_buffer.data_size = 4096; 736 + cz_smu->smu_buffer.data_size = 737 + ALIGN(UCODE_ID_RLC_SCRATCH_SIZE_BYTE, 32) + 738 + ALIGN(UCODE_ID_RLC_SRM_ARAM_SIZE_BYTE, 32) + 739 + ALIGN(UCODE_ID_RLC_SRM_DRAM_SIZE_BYTE, 32) + 740 + ALIGN(sizeof(struct SMU8_MultimediaPowerLogData), 32) + 741 + ALIGN(sizeof(struct SMU8_Fusion_ClkTable), 32); 742 + 743 + ret = smu_allocate_memory(smumgr->device, 744 + cz_smu->toc_buffer.data_size, 745 + CGS_GPU_MEM_TYPE__GART_CACHEABLE, 746 + PAGE_SIZE, 747 + &mc_addr, 748 + &cz_smu->toc_buffer.kaddr, 749 + &cz_smu->toc_buffer.handle); 750 + if (ret != 0) 751 + return -1; 752 + 753 + cz_smu->toc_buffer.mc_addr_high = smu_upper_32_bits(mc_addr); 754 + cz_smu->toc_buffer.mc_addr_low = smu_lower_32_bits(mc_addr); 755 + 756 + ret = smu_allocate_memory(smumgr->device, 757 + cz_smu->smu_buffer.data_size, 758 + CGS_GPU_MEM_TYPE__GART_CACHEABLE, 759 + PAGE_SIZE, 760 + &mc_addr, 761 + &cz_smu->smu_buffer.kaddr, 762 + &cz_smu->smu_buffer.handle); 763 + if (ret != 0) 764 + return -1; 765 + 766 + cz_smu->smu_buffer.mc_addr_high = smu_upper_32_bits(mc_addr); 767 + cz_smu->smu_buffer.mc_addr_low = smu_lower_32_bits(mc_addr); 768 + 769 + cz_smu_populate_firmware_entries(smumgr); 770 + if (0 != cz_smu_populate_single_scratch_entry(smumgr, 771 + CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH, 772 + UCODE_ID_RLC_SCRATCH_SIZE_BYTE, 773 + &cz_smu->scratch_buffer[cz_smu->scratch_buffer_length++])) { 774 + printk(KERN_ERR "[ powerplay ] Error when Populate Firmware Entry.\n"); 775 + return -1; 776 + } 777 + 778 + if (0 != cz_smu_populate_single_scratch_entry(smumgr, 779 + CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM, 780 + UCODE_ID_RLC_SRM_ARAM_SIZE_BYTE, 781 + &cz_smu->scratch_buffer[cz_smu->scratch_buffer_length++])) { 782 + printk(KERN_ERR "[ powerplay ] Error when Populate Firmware Entry.\n"); 783 + return -1; 784 + } 785 + if (0 != cz_smu_populate_single_scratch_entry(smumgr, 786 + CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM, 787 + UCODE_ID_RLC_SRM_DRAM_SIZE_BYTE, 788 + &cz_smu->scratch_buffer[cz_smu->scratch_buffer_length++])) { 789 + printk(KERN_ERR "[ powerplay ] Error when Populate Firmware Entry.\n"); 790 + return -1; 791 + } 792 + 793 + if (0 != cz_smu_populate_single_scratch_entry(smumgr, 794 + CZ_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING, 795 + sizeof(struct SMU8_MultimediaPowerLogData), 796 + &cz_smu->scratch_buffer[cz_smu->scratch_buffer_length++])) { 797 + printk(KERN_ERR "[ powerplay ] Error when Populate Firmware Entry.\n"); 798 + return -1; 799 + } 800 + 801 + if (0 != cz_smu_populate_single_scratch_entry(smumgr, 802 + CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE, 803 + sizeof(struct SMU8_Fusion_ClkTable), 804 + &cz_smu->scratch_buffer[cz_smu->scratch_buffer_length++])) { 805 + printk(KERN_ERR "[ powerplay ] Error when Populate Firmware Entry.\n"); 806 + return -1; 807 + } 808 + cz_smu_construct_toc(smumgr); 809 + 810 + return 0; 811 + } 812 + 813 + static int cz_smu_fini(struct pp_smumgr *smumgr) 814 + { 815 + struct cz_smumgr *cz_smu; 816 + 817 + if (smumgr == NULL || smumgr->device == NULL) 818 + return -EINVAL; 819 + 820 + cz_smu = (struct cz_smumgr *)smumgr->backend; 821 + if (!cz_smu) { 822 + cgs_free_gpu_mem(smumgr->device, 823 + cz_smu->toc_buffer.handle); 824 + cgs_free_gpu_mem(smumgr->device, 825 + cz_smu->smu_buffer.handle); 826 + kfree(cz_smu); 827 + kfree(smumgr); 828 + } 829 + 830 + return 0; 831 + } 832 + 833 + static const struct pp_smumgr_func cz_smu_funcs = { 834 + .smu_init = cz_smu_init, 835 + .smu_fini = cz_smu_fini, 836 + .start_smu = cz_start_smu, 837 + .check_fw_load_finish = cz_check_fw_load_finish, 838 + .request_smu_load_fw = NULL, 839 + .request_smu_load_specific_fw = NULL, 840 + .get_argument = cz_smum_get_argument, 841 + .send_msg_to_smc = cz_send_msg_to_smc, 842 + .send_msg_to_smc_with_parameter = cz_send_msg_to_smc_with_parameter, 843 + .download_pptable_settings = cz_download_pptable_settings, 844 + .upload_pptable_settings = cz_upload_pptable_settings, 845 + }; 846 + 847 + int cz_smum_init(struct pp_smumgr *smumgr) 848 + { 849 + struct cz_smumgr *cz_smu; 850 + 851 + cz_smu = kzalloc(sizeof(struct cz_smumgr), GFP_KERNEL); 852 + if (cz_smu == NULL) 853 + return -ENOMEM; 854 + 855 + smumgr->backend = cz_smu; 856 + smumgr->smumgr_funcs = &cz_smu_funcs; 857 + return 0; 858 + }
+102
drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.h
··· 1 + /* 2 + * Copyright 2015 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 + #ifndef _CZ_SMUMGR_H_ 24 + #define _CZ_SMUMGR_H_ 25 + 26 + 27 + #define MAX_NUM_FIRMWARE 8 28 + #define MAX_NUM_SCRATCH 11 29 + #define CZ_SCRATCH_SIZE_NONGFX_CLOCKGATING 1024 30 + #define CZ_SCRATCH_SIZE_NONGFX_GOLDENSETTING 2048 31 + #define CZ_SCRATCH_SIZE_SDMA_METADATA 1024 32 + #define CZ_SCRATCH_SIZE_IH ((2*256+1)*4) 33 + 34 + enum cz_scratch_entry { 35 + CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0 = 0, 36 + CZ_SCRATCH_ENTRY_UCODE_ID_SDMA1, 37 + CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE, 38 + CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP, 39 + CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME, 40 + CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, 41 + CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2, 42 + CZ_SCRATCH_ENTRY_UCODE_ID_GMCON_RENG, 43 + CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G, 44 + CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH, 45 + CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM, 46 + CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM, 47 + CZ_SCRATCH_ENTRY_UCODE_ID_DMCU_ERAM, 48 + CZ_SCRATCH_ENTRY_UCODE_ID_DMCU_IRAM, 49 + CZ_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING, 50 + CZ_SCRATCH_ENTRY_DATA_ID_SDMA_HALT, 51 + CZ_SCRATCH_ENTRY_DATA_ID_SYS_CLOCKGATING, 52 + CZ_SCRATCH_ENTRY_DATA_ID_SDMA_RING_REGS, 53 + CZ_SCRATCH_ENTRY_DATA_ID_NONGFX_REINIT, 54 + CZ_SCRATCH_ENTRY_DATA_ID_SDMA_START, 55 + CZ_SCRATCH_ENTRY_DATA_ID_IH_REGISTERS, 56 + CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE 57 + }; 58 + 59 + struct cz_buffer_entry { 60 + uint32_t data_size; 61 + uint32_t mc_addr_low; 62 + uint32_t mc_addr_high; 63 + void *kaddr; 64 + enum cz_scratch_entry firmware_ID; 65 + unsigned long handle; /* as bo handle used when release bo */ 66 + }; 67 + 68 + struct cz_register_index_data_pair { 69 + uint32_t offset; 70 + uint32_t value; 71 + }; 72 + 73 + struct cz_ih_meta_data { 74 + uint32_t command; 75 + struct cz_register_index_data_pair register_index_value_pair[1]; 76 + }; 77 + 78 + struct cz_smumgr { 79 + uint8_t driver_buffer_length; 80 + uint8_t scratch_buffer_length; 81 + uint16_t toc_entry_used_count; 82 + uint16_t toc_entry_initialize_index; 83 + uint16_t toc_entry_power_profiling_index; 84 + uint16_t toc_entry_aram; 85 + uint16_t toc_entry_ih_register_restore_task_index; 86 + uint16_t toc_entry_clock_table; 87 + uint16_t ih_register_restore_task_size; 88 + uint16_t smu_buffer_used_bytes; 89 + 90 + struct cz_buffer_entry toc_buffer; 91 + struct cz_buffer_entry smu_buffer; 92 + struct cz_buffer_entry firmware_buffer; 93 + struct cz_buffer_entry driver_buffer[MAX_NUM_FIRMWARE]; 94 + struct cz_buffer_entry meta_data_buffer[MAX_NUM_FIRMWARE]; 95 + struct cz_buffer_entry scratch_buffer[MAX_NUM_SCRATCH]; 96 + }; 97 + 98 + struct pp_smumgr; 99 + 100 + extern int cz_smum_init(struct pp_smumgr *smumgr); 101 + 102 + #endif
+2 -1
drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c
··· 27 27 #include "smumgr.h" 28 28 #include "cgs_common.h" 29 29 #include "linux/delay.h" 30 + #include "cz_smumgr.h" 30 31 31 32 int smum_init(struct amd_pp_init *pp_init, struct pp_instance *handle) 32 33 { ··· 50 49 51 50 switch (smumgr->chip_family) { 52 51 case AMD_FAMILY_CZ: 53 - /* TODO */ 52 + cz_smum_init(smumgr); 54 53 break; 55 54 case AMD_FAMILY_VI: 56 55 /* TODO */