/* * Copyright 2016 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Author: Huang Rui * */ #include <linux/firmware.h>#include <drm/drm_drv.h> #include "amdgpu.h"#include "amdgpu_psp.h"#include "amdgpu_ucode.h"#include "amdgpu_xgmi.h"#include "soc15_common.h"#include "psp_v3_1.h"#include "psp_v10_0.h"#include "psp_v11_0.h"#include "psp_v11_0_8.h"#include "psp_v12_0.h"#include "psp_v13_0.h"#include "psp_v13_0_4.h"#include "psp_v14_0.h"#include "psp_v15_0.h"#include "psp_v15_0_8.h" #include "amdgpu_ras.h"#include "amdgpu_securedisplay.h"#include "amdgpu_atomfirmware.h" #define AMD_VBIOS_FILE_MAX_SIZE_B (1024*1024*16) static int psp_load_smu_fw(struct psp_context *psp);static int psp_rap_terminate(struct psp_context *psp);static int psp_securedisplay_terminate(struct psp_context *psp); static const char * const amdgpu_ptl_fmt_str[] = { [AMDGPU_PTL_FMT_I8] = "I8", [AMDGPU_PTL_FMT_F16] = "F16", [AMDGPU_PTL_FMT_BF16] = "BF16", [AMDGPU_PTL_FMT_F32] = "F32", [AMDGPU_PTL_FMT_F64] = "F64", [AMDGPU_PTL_FMT_F8] = "F8", [AMDGPU_PTL_FMT_VECTOR] = "VECTOR", [AMDGPU_PTL_FMT_INVALID] = "INVALID",}; static int psp_ring_init(struct psp_context *psp, enum psp_ring_type ring_type){ int ret = 0; struct psp_ring *ring; struct amdgpu_device *adev = psp->adev; ring = &psp->km_ring; ring->ring_type = ring_type; /* allocate 4k Page of Local Frame Buffer memory for ring */ ring->ring_size = 0x1000; ret = amdgpu_bo_create_kernel(adev, ring->ring_size, PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT, &adev->firmware.rbuf, &ring->ring_mem_mc_addr, (void **)&ring->ring_mem); if (ret) { ring->ring_size = 0; return ret; } return 0;} /* * Due to DF Cstate management centralized to PMFW, the firmware * loading sequence will be updated as below: * - Load KDB * - Load SYS_DRV * - Load tOS * - Load PMFW * - Setup TMR * - Load other non-psp fw * - Load ASD * - Load XGMI/RAS/HDCP/DTM TA if any * * This new sequence is required for * - Arcturus and onwards */static void psp_check_pmfw_centralized_cstate_management(struct psp_context *psp){ struct amdgpu_device *adev = psp->adev; if (amdgpu_sriov_vf(adev)) { psp->pmfw_centralized_cstate_management = false; return; } switch (amdgpu_ip_version(adev, MP0_HWIP, 0)) { case IP_VERSION(11, 0, 0): case IP_VERSION(11, 0, 4): case IP_VERSION(11, 0, 5): case IP_VERSION(11, 0, 7): case IP_VERSION(11, 0, 9): case IP_VERSION(11, 0, 11): case IP_VERSION(11, 0, 12): case IP_VERSION(11, 0, 13): case IP_VERSION(13, 0, 0): case IP_VERSION(13, 0, 2): case IP_VERSION(13, 0, 7): psp->pmfw_centralized_cstate_management = true; break; default: psp->pmfw_centralized_cstate_management = false; break; }} static int psp_init_sriov_microcode(struct psp_context *psp){ struct amdgpu_device *adev = psp->adev; char ucode_prefix[30]; int ret = 0; amdgpu_ucode_ip_version_decode(adev, MP0_HWIP, ucode_prefix, sizeof(ucode_prefix)); switch (amdgpu_ip_version(adev, MP0_HWIP, 0)) { case IP_VERSION(9, 0, 0): case IP_VERSION(11, 0, 7): case IP_VERSION(11, 0, 9): adev->virt.autoload_ucode_id = AMDGPU_UCODE_ID_CP_MEC2; ret = psp_init_cap_microcode(psp, ucode_prefix); break; case IP_VERSION(13, 0, 2): adev->virt.autoload_ucode_id = AMDGPU_UCODE_ID_CP_MEC2; ret = psp_init_cap_microcode(psp, ucode_prefix); ret &= psp_init_ta_microcode(psp, ucode_prefix); break; case IP_VERSION(13, 0, 0): adev->virt.autoload_ucode_id = 0; break; case IP_VERSION(13, 0, 6): case IP_VERSION(13, 0, 14): case IP_VERSION(13, 0, 15): ret = psp_init_cap_microcode(psp, ucode_prefix); ret &= psp_init_ta_microcode(psp, ucode_prefix); break; case IP_VERSION(13, 0, 10): adev->virt.autoload_ucode_id = AMDGPU_UCODE_ID_CP_MES1_DATA; ret = psp_init_cap_microcode(psp, ucode_prefix); break; case IP_VERSION(13, 0, 12): ret = psp_init_ta_microcode(psp, ucode_prefix); break; default: return -EINVAL; } return ret;} static int psp_early_init(struct amdgpu_ip_block *ip_block){ struct amdgpu_device *adev = ip_block->adev; struct psp_context *psp = &adev->psp; psp->autoload_supported = true; psp->boot_time_tmr = true; switch (amdgpu_ip_version(adev, MP0_HWIP, 0)) { case IP_VERSION(9, 0, 0): psp_v3_1_set_psp_funcs(psp); psp->autoload_supported = false; psp->boot_time_tmr = false; break; case IP_VERSION(10, 0, 0): case IP_VERSION(10, 0, 1): psp_v10_0_set_psp_funcs(psp); psp->autoload_supported = false; psp->boot_time_tmr = false; break; case IP_VERSION(11, 0, 2): case IP_VERSION(11, 0, 4): psp_v11_0_set_psp_funcs(psp); psp->autoload_supported = false; psp->boot_time_tmr = false; break; case IP_VERSION(11, 0, 0): case IP_VERSION(11, 0, 7): adev->psp.sup_pd_fw_up = !amdgpu_sriov_vf(adev); fallthrough; case IP_VERSION(11, 0, 5): case IP_VERSION(11, 0, 9): case IP_VERSION(11, 0, 11): case IP_VERSION(11, 5, 0): case IP_VERSION(11, 5, 2): case IP_VERSION(11, 0, 12): case IP_VERSION(11, 0, 13): psp_v11_0_set_psp_funcs(psp); psp->boot_time_tmr = false; break; case IP_VERSION(11, 0, 3): case IP_VERSION(12, 0, 1): psp_v12_0_set_psp_funcs(psp); psp->autoload_supported = false; psp->boot_time_tmr = false; break; case IP_VERSION(13, 0, 2): psp->boot_time_tmr = false; fallthrough; case IP_VERSION(13, 0, 6): case IP_VERSION(13, 0, 14): psp_v13_0_set_psp_funcs(psp); psp->autoload_supported = false; break; case IP_VERSION(13, 0, 12): case IP_VERSION(13, 0, 15): psp_v13_0_set_psp_funcs(psp); psp->autoload_supported = false; adev->psp.sup_ifwi_up = !amdgpu_sriov_vf(adev); break; case IP_VERSION(13, 0, 1): case IP_VERSION(13, 0, 3): case IP_VERSION(13, 0, 5): case IP_VERSION(13, 0, 8): case IP_VERSION(13, 0, 11): case IP_VERSION(14, 0, 0): case IP_VERSION(14, 0, 1): case IP_VERSION(14, 0, 4): psp_v13_0_set_psp_funcs(psp); psp->boot_time_tmr = false; break; case IP_VERSION(11, 0, 8): if (adev->apu_flags & AMD_APU_IS_CYAN_SKILLFISH2) { psp_v11_0_8_set_psp_funcs(psp); } psp->autoload_supported = false; psp->boot_time_tmr = false; break; case IP_VERSION(13, 0, 0): case IP_VERSION(13, 0, 7): case IP_VERSION(13, 0, 10): psp_v13_0_set_psp_funcs(psp); adev->psp.sup_ifwi_up = !amdgpu_sriov_vf(adev); psp->boot_time_tmr = false; break; case IP_VERSION(13, 0, 4): psp_v13_0_4_set_psp_funcs(psp); psp->boot_time_tmr = false; break; case IP_VERSION(14, 0, 2): case IP_VERSION(14, 0, 3): adev->psp.sup_ifwi_up = !amdgpu_sriov_vf(adev); psp_v14_0_set_psp_funcs(psp); break; case IP_VERSION(14, 0, 5): psp_v14_0_set_psp_funcs(psp); psp->boot_time_tmr = false; break; case IP_VERSION(15, 0, 0): case IP_VERSION(15, 0, 5): case IP_VERSION(15, 0, 9): psp_v15_0_0_set_psp_funcs(psp); psp->boot_time_tmr = false; break; case IP_VERSION(15, 0, 8): psp_v15_0_8_set_psp_funcs(psp); break; default: return -EINVAL; } psp->adev = adev; adev->psp_timeout = 20000; psp_check_pmfw_centralized_cstate_management(psp); if (amdgpu_sriov_vf(adev)) return psp_init_sriov_microcode(psp); else return psp_init_microcode(psp);} void psp_ta_free_shared_buf(struct ta_mem_context *mem_ctx){ amdgpu_bo_free_kernel(&mem_ctx->shared_bo, &mem_ctx->shared_mc_addr, &mem_ctx->shared_buf); mem_ctx->shared_bo = NULL;} static void psp_free_shared_bufs(struct psp_context *psp){ void *tmr_buf; void **pptr; /* free TMR memory buffer */ pptr = amdgpu_sriov_vf(psp->adev) ? &tmr_buf : NULL; amdgpu_bo_free_kernel(&psp->tmr_bo, &psp->tmr_mc_addr, pptr); psp->tmr_bo = NULL; /* free xgmi shared memory */ psp_ta_free_shared_buf(&psp->xgmi_context.context.mem_context); /* free ras shared memory */ psp_ta_free_shared_buf(&psp->ras_context.context.mem_context); /* free hdcp shared memory */ psp_ta_free_shared_buf(&psp->hdcp_context.context.mem_context); /* free dtm shared memory */ psp_ta_free_shared_buf(&psp->dtm_context.context.mem_context); /* free rap shared memory */ psp_ta_free_shared_buf(&psp->rap_context.context.mem_context); /* free securedisplay shared memory */ psp_ta_free_shared_buf(&psp->securedisplay_context.context.mem_context); } static void psp_memory_training_fini(struct psp_context *psp){ struct psp_memory_training_context *ctx = &psp->mem_train_ctx; ctx->init = PSP_MEM_TRAIN_NOT_SUPPORT; kfree(ctx->sys_cache); ctx->sys_cache = NULL;} static int psp_memory_training_init(struct psp_context *psp){ int ret; struct psp_memory_training_context *ctx = &psp->mem_train_ctx; if (ctx->init != PSP_MEM_TRAIN_RESERVE_SUCCESS) { dev_dbg(psp->adev->dev, "memory training is not supported!\n"); return 0; } ctx->sys_cache = kzalloc(ctx->train_data_size, GFP_KERNEL); if (ctx->sys_cache == NULL) { dev_err(psp->adev->dev, "alloc mem_train_ctx.sys_cache failed!\n"); ret = -ENOMEM; goto Err_out; } dev_dbg(psp->adev->dev, "train_data_size:%llx,p2c_train_data_offset:%llx,c2p_train_data_offset:%llx.\n", ctx->train_data_size, ctx->p2c_train_data_offset, ctx->c2p_train_data_offset); ctx->init = PSP_MEM_TRAIN_INIT_SUCCESS; return 0; Err_out: psp_memory_training_fini(psp); return ret;} /* * Helper funciton to query psp runtime database entry * * @adev: amdgpu_device pointer * @entry_type: the type of psp runtime database entry * @db_entry: runtime database entry pointer * * Return false if runtime database doesn't exit or entry is invalid * or true if the specific database entry is found, and copy to @db_entry */static bool psp_get_runtime_db_entry(struct amdgpu_device *adev, enum psp_runtime_entry_type entry_type, void *db_entry){ uint64_t db_header_pos, db_dir_pos; struct psp_runtime_data_header db_header = {0}; struct psp_runtime_data_directory db_dir = {0}; bool ret = false; int i; /* * Runtime DB is for dGPUs only. */ if (adev->flags & AMD_IS_APU) return false; if (amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(13, 0, 6) || amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(13, 0, 12) || amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(13, 0, 14) || amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(13, 0, 15)) return false; db_header_pos = adev->gmc.mc_vram_size - PSP_RUNTIME_DB_OFFSET; db_dir_pos = db_header_pos + sizeof(struct psp_runtime_data_header); /* read runtime db header from vram */ amdgpu_device_vram_access(adev, db_header_pos, (uint32_t *)&db_header, sizeof(struct psp_runtime_data_header), false); if (db_header.cookie != PSP_RUNTIME_DB_COOKIE_ID) { /* runtime db doesn't exist, exit */ dev_dbg(adev->dev, "PSP runtime database doesn't exist\n"); return false; } /* read runtime database entry from vram */ amdgpu_device_vram_access(adev, db_dir_pos, (uint32_t *)&db_dir, sizeof(struct psp_runtime_data_directory), false); if (db_dir.entry_count >= PSP_RUNTIME_DB_DIAG_ENTRY_MAX_COUNT) { /* invalid db entry count, exit */ dev_warn(adev->dev, "Invalid PSP runtime database entry count\n"); return false; } /* look up for requested entry type */ for (i = 0; i < db_dir.entry_count && !ret; i++) { if (db_dir.entry_list[i].entry_type == entry_type) { switch (entry_type) { case PSP_RUNTIME_ENTRY_TYPE_BOOT_CONFIG: if (db_dir.entry_list[i].size < sizeof(struct psp_runtime_boot_cfg_entry)) { /* invalid db entry size */ dev_warn(adev->dev, "Invalid PSP runtime database boot cfg entry size\n"); return false; } /* read runtime database entry */ amdgpu_device_vram_access(adev, db_header_pos + db_dir.entry_list[i].offset, (uint32_t *)db_entry, sizeof(struct psp_runtime_boot_cfg_entry), false); ret = true; break; case PSP_RUNTIME_ENTRY_TYPE_PPTABLE_ERR_STATUS: if (db_dir.entry_list[i].size < sizeof(struct psp_runtime_scpm_entry)) { /* invalid db entry size */ dev_warn(adev->dev, "Invalid PSP runtime database scpm entry size\n"); return false; } /* read runtime database entry */ amdgpu_device_vram_access(adev, db_header_pos + db_dir.entry_list[i].offset, (uint32_t *)db_entry, sizeof(struct psp_runtime_scpm_entry), false); ret = true; break; default: ret = false; break; } } } return ret;} static int psp_sw_init(struct amdgpu_ip_block *ip_block){ struct amdgpu_device *adev = ip_block->adev; struct psp_context *psp = &adev->psp; int ret; struct psp_runtime_boot_cfg_entry boot_cfg_entry; struct psp_memory_training_context *mem_training_ctx = &psp->mem_train_ctx; struct psp_runtime_scpm_entry scpm_entry; psp->cmd = kzalloc_obj(struct psp_gfx_cmd_resp); if (!psp->cmd) { dev_err(adev->dev, "Failed to allocate memory to command buffer!\n"); return -ENOMEM; } adev->psp.xgmi_context.supports_extended_data = !adev->gmc.xgmi.connected_to_cpu && amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(13, 0, 2); memset(&scpm_entry, 0, sizeof(scpm_entry)); if ((psp_get_runtime_db_entry(adev, PSP_RUNTIME_ENTRY_TYPE_PPTABLE_ERR_STATUS, &scpm_entry)) && (scpm_entry.scpm_status != SCPM_DISABLE)) { adev->scpm_enabled = true; adev->scpm_status = scpm_entry.scpm_status; } else { adev->scpm_enabled = false; adev->scpm_status = SCPM_DISABLE; } Lines 1–500 of 5075. Load more
/* * Copyright 2016 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Author: Huang Rui * */ #include <linux/firmware.h> #include <drm/drm_drv.h> #include "amdgpu.h" #include "amdgpu_psp.h" #include "amdgpu_ucode.h" #include "amdgpu_xgmi.h" #include "soc15_common.h" #include "psp_v3_1.h" #include "psp_v10_0.h" #include "psp_v11_0.h" #include "psp_v11_0_8.h" #include "psp_v12_0.h" #include "psp_v13_0.h" #include "psp_v13_0_4.h" #include "psp_v14_0.h" #include "psp_v15_0.h" #include "psp_v15_0_8.h" #include "amdgpu_ras.h" #include "amdgpu_securedisplay.h" #include "amdgpu_atomfirmware.h" #define AMD_VBIOS_FILE_MAX_SIZE_B (1024*1024*16) static int psp_load_smu_fw(struct psp_context *psp); static int psp_rap_terminate(struct psp_context *psp); static int psp_securedisplay_terminate(struct psp_context *psp); static const char * const amdgpu_ptl_fmt_str[] = { [AMDGPU_PTL_FMT_I8] = "I8", [AMDGPU_PTL_FMT_F16] = "F16", [AMDGPU_PTL_FMT_BF16] = "BF16", [AMDGPU_PTL_FMT_F32] = "F32", [AMDGPU_PTL_FMT_F64] = "F64", [AMDGPU_PTL_FMT_F8] = "F8", [AMDGPU_PTL_FMT_VECTOR] = "VECTOR", [AMDGPU_PTL_FMT_INVALID] = "INVALID", }; static int psp_ring_init(struct psp_context *psp, enum psp_ring_type ring_type) { int ret = 0; struct psp_ring *ring; struct amdgpu_device *adev = psp->adev; ring = &psp->km_ring; ring->ring_type = ring_type; /* allocate 4k Page of Local Frame Buffer memory for ring */ ring->ring_size = 0x1000; ret = amdgpu_bo_create_kernel(adev, ring->ring_size, PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT, &adev->firmware.rbuf, &ring->ring_mem_mc_addr, (void **)&ring->ring_mem); if (ret) { ring->ring_size = 0; return ret; } return 0; } /* * Due to DF Cstate management centralized to PMFW, the firmware * loading sequence will be updated as below: * - Load KDB * - Load SYS_DRV * - Load tOS * - Load PMFW * - Setup TMR * - Load other non-psp fw * - Load ASD * - Load XGMI/RAS/HDCP/DTM TA if any * * This new sequence is required for * - Arcturus and onwards */ static void psp_check_pmfw_centralized_cstate_management(struct psp_context *psp) { struct amdgpu_device *adev = psp->adev; if (amdgpu_sriov_vf(adev)) { psp->pmfw_centralized_cstate_management = false; return; } switch (amdgpu_ip_version(adev, MP0_HWIP, 0)) { case IP_VERSION(11, 0, 0): case IP_VERSION(11, 0, 4): case IP_VERSION(11, 0, 5): case IP_VERSION(11, 0, 7): case IP_VERSION(11, 0, 9): case IP_VERSION(11, 0, 11): case IP_VERSION(11, 0, 12): case IP_VERSION(11, 0, 13): case IP_VERSION(13, 0, 0): case IP_VERSION(13, 0, 2): case IP_VERSION(13, 0, 7): psp->pmfw_centralized_cstate_management = true; break; default: psp->pmfw_centralized_cstate_management = false; break; } } static int psp_init_sriov_microcode(struct psp_context *psp) { struct amdgpu_device *adev = psp->adev; char ucode_prefix[30]; int ret = 0; amdgpu_ucode_ip_version_decode(adev, MP0_HWIP, ucode_prefix, sizeof(ucode_prefix)); switch (amdgpu_ip_version(adev, MP0_HWIP, 0)) { case IP_VERSION(9, 0, 0): case IP_VERSION(11, 0, 7): case IP_VERSION(11, 0, 9): adev->virt.autoload_ucode_id = AMDGPU_UCODE_ID_CP_MEC2; ret = psp_init_cap_microcode(psp, ucode_prefix); break; case IP_VERSION(13, 0, 2): adev->virt.autoload_ucode_id = AMDGPU_UCODE_ID_CP_MEC2; ret = psp_init_cap_microcode(psp, ucode_prefix); ret &= psp_init_ta_microcode(psp, ucode_prefix); break; case IP_VERSION(13, 0, 0): adev->virt.autoload_ucode_id = 0; break; case IP_VERSION(13, 0, 6): case IP_VERSION(13, 0, 14): case IP_VERSION(13, 0, 15): ret = psp_init_cap_microcode(psp, ucode_prefix); ret &= psp_init_ta_microcode(psp, ucode_prefix); break; case IP_VERSION(13, 0, 10): adev->virt.autoload_ucode_id = AMDGPU_UCODE_ID_CP_MES1_DATA; ret = psp_init_cap_microcode(psp, ucode_prefix); break; case IP_VERSION(13, 0, 12): ret = psp_init_ta_microcode(psp, ucode_prefix); break; default: return -EINVAL; } return ret; } static int psp_early_init(struct amdgpu_ip_block *ip_block) { struct amdgpu_device *adev = ip_block->adev; struct psp_context *psp = &adev->psp; psp->autoload_supported = true; psp->boot_time_tmr = true; switch (amdgpu_ip_version(adev, MP0_HWIP, 0)) { case IP_VERSION(9, 0, 0): psp_v3_1_set_psp_funcs(psp); psp->autoload_supported = false; psp->boot_time_tmr = false; break; case IP_VERSION(10, 0, 0): case IP_VERSION(10, 0, 1): psp_v10_0_set_psp_funcs(psp); psp->autoload_supported = false; psp->boot_time_tmr = false; break; case IP_VERSION(11, 0, 2): case IP_VERSION(11, 0, 4): psp_v11_0_set_psp_funcs(psp); psp->autoload_supported = false; psp->boot_time_tmr = false; break; case IP_VERSION(11, 0, 0): case IP_VERSION(11, 0, 7): adev->psp.sup_pd_fw_up = !amdgpu_sriov_vf(adev); fallthrough; case IP_VERSION(11, 0, 5): case IP_VERSION(11, 0, 9): case IP_VERSION(11, 0, 11): case IP_VERSION(11, 5, 0): case IP_VERSION(11, 5, 2): case IP_VERSION(11, 0, 12): case IP_VERSION(11, 0, 13): psp_v11_0_set_psp_funcs(psp); psp->boot_time_tmr = false; break; case IP_VERSION(11, 0, 3): case IP_VERSION(12, 0, 1): psp_v12_0_set_psp_funcs(psp); psp->autoload_supported = false; psp->boot_time_tmr = false; break; case IP_VERSION(13, 0, 2): psp->boot_time_tmr = false; fallthrough; case IP_VERSION(13, 0, 6): case IP_VERSION(13, 0, 14): psp_v13_0_set_psp_funcs(psp); psp->autoload_supported = false; break; case IP_VERSION(13, 0, 12): case IP_VERSION(13, 0, 15): psp_v13_0_set_psp_funcs(psp); psp->autoload_supported = false; adev->psp.sup_ifwi_up = !amdgpu_sriov_vf(adev); break; case IP_VERSION(13, 0, 1): case IP_VERSION(13, 0, 3): case IP_VERSION(13, 0, 5): case IP_VERSION(13, 0, 8): case IP_VERSION(13, 0, 11): case IP_VERSION(14, 0, 0): case IP_VERSION(14, 0, 1): case IP_VERSION(14, 0, 4): psp_v13_0_set_psp_funcs(psp); psp->boot_time_tmr = false; break; case IP_VERSION(11, 0, 8): if (adev->apu_flags & AMD_APU_IS_CYAN_SKILLFISH2) { psp_v11_0_8_set_psp_funcs(psp); } psp->autoload_supported = false; psp->boot_time_tmr = false; break; case IP_VERSION(13, 0, 0): case IP_VERSION(13, 0, 7): case IP_VERSION(13, 0, 10): psp_v13_0_set_psp_funcs(psp); adev->psp.sup_ifwi_up = !amdgpu_sriov_vf(adev); psp->boot_time_tmr = false; break; case IP_VERSION(13, 0, 4): psp_v13_0_4_set_psp_funcs(psp); psp->boot_time_tmr = false; break; case IP_VERSION(14, 0, 2): case IP_VERSION(14, 0, 3): adev->psp.sup_ifwi_up = !amdgpu_sriov_vf(adev); psp_v14_0_set_psp_funcs(psp); break; case IP_VERSION(14, 0, 5): psp_v14_0_set_psp_funcs(psp); psp->boot_time_tmr = false; break; case IP_VERSION(15, 0, 0): case IP_VERSION(15, 0, 5): case IP_VERSION(15, 0, 9): psp_v15_0_0_set_psp_funcs(psp); psp->boot_time_tmr = false; break; case IP_VERSION(15, 0, 8): psp_v15_0_8_set_psp_funcs(psp); break; default: return -EINVAL; } psp->adev = adev; adev->psp_timeout = 20000; psp_check_pmfw_centralized_cstate_management(psp); if (amdgpu_sriov_vf(adev)) return psp_init_sriov_microcode(psp); else return psp_init_microcode(psp); } void psp_ta_free_shared_buf(struct ta_mem_context *mem_ctx) { amdgpu_bo_free_kernel(&mem_ctx->shared_bo, &mem_ctx->shared_mc_addr, &mem_ctx->shared_buf); mem_ctx->shared_bo = NULL; } static void psp_free_shared_bufs(struct psp_context *psp) { void *tmr_buf; void **pptr; /* free TMR memory buffer */ pptr = amdgpu_sriov_vf(psp->adev) ? &tmr_buf : NULL; amdgpu_bo_free_kernel(&psp->tmr_bo, &psp->tmr_mc_addr, pptr); psp->tmr_bo = NULL; /* free xgmi shared memory */ psp_ta_free_shared_buf(&psp->xgmi_context.context.mem_context); /* free ras shared memory */ psp_ta_free_shared_buf(&psp->ras_context.context.mem_context); /* free hdcp shared memory */ psp_ta_free_shared_buf(&psp->hdcp_context.context.mem_context); /* free dtm shared memory */ psp_ta_free_shared_buf(&psp->dtm_context.context.mem_context); /* free rap shared memory */ psp_ta_free_shared_buf(&psp->rap_context.context.mem_context); /* free securedisplay shared memory */ psp_ta_free_shared_buf(&psp->securedisplay_context.context.mem_context); } static void psp_memory_training_fini(struct psp_context *psp) { struct psp_memory_training_context *ctx = &psp->mem_train_ctx; ctx->init = PSP_MEM_TRAIN_NOT_SUPPORT; kfree(ctx->sys_cache); ctx->sys_cache = NULL; } static int psp_memory_training_init(struct psp_context *psp) { int ret; struct psp_memory_training_context *ctx = &psp->mem_train_ctx; if (ctx->init != PSP_MEM_TRAIN_RESERVE_SUCCESS) { dev_dbg(psp->adev->dev, "memory training is not supported!\n"); return 0; } ctx->sys_cache = kzalloc(ctx->train_data_size, GFP_KERNEL); if (ctx->sys_cache == NULL) { dev_err(psp->adev->dev, "alloc mem_train_ctx.sys_cache failed!\n"); ret = -ENOMEM; goto Err_out; } dev_dbg(psp->adev->dev, "train_data_size:%llx,p2c_train_data_offset:%llx,c2p_train_data_offset:%llx.\n", ctx->train_data_size, ctx->p2c_train_data_offset, ctx->c2p_train_data_offset); ctx->init = PSP_MEM_TRAIN_INIT_SUCCESS; return 0; Err_out: psp_memory_training_fini(psp); return ret; } /* * Helper funciton to query psp runtime database entry * * @adev: amdgpu_device pointer * @entry_type: the type of psp runtime database entry * @db_entry: runtime database entry pointer * * Return false if runtime database doesn't exit or entry is invalid * or true if the specific database entry is found, and copy to @db_entry */ static bool psp_get_runtime_db_entry(struct amdgpu_device *adev, enum psp_runtime_entry_type entry_type, void *db_entry) { uint64_t db_header_pos, db_dir_pos; struct psp_runtime_data_header db_header = {0}; struct psp_runtime_data_directory db_dir = {0}; bool ret = false; int i; /* * Runtime DB is for dGPUs only. */ if (adev->flags & AMD_IS_APU) return false; if (amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(13, 0, 6) || amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(13, 0, 12) || amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(13, 0, 14) || amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(13, 0, 15)) return false; db_header_pos = adev->gmc.mc_vram_size - PSP_RUNTIME_DB_OFFSET; db_dir_pos = db_header_pos + sizeof(struct psp_runtime_data_header); /* read runtime db header from vram */ amdgpu_device_vram_access(adev, db_header_pos, (uint32_t *)&db_header, sizeof(struct psp_runtime_data_header), false); if (db_header.cookie != PSP_RUNTIME_DB_COOKIE_ID) { /* runtime db doesn't exist, exit */ dev_dbg(adev->dev, "PSP runtime database doesn't exist\n"); return false; } /* read runtime database entry from vram */ amdgpu_device_vram_access(adev, db_dir_pos, (uint32_t *)&db_dir, sizeof(struct psp_runtime_data_directory), false); if (db_dir.entry_count >= PSP_RUNTIME_DB_DIAG_ENTRY_MAX_COUNT) { /* invalid db entry count, exit */ dev_warn(adev->dev, "Invalid PSP runtime database entry count\n"); return false; } /* look up for requested entry type */ for (i = 0; i < db_dir.entry_count && !ret; i++) { if (db_dir.entry_list[i].entry_type == entry_type) { switch (entry_type) { case PSP_RUNTIME_ENTRY_TYPE_BOOT_CONFIG: if (db_dir.entry_list[i].size < sizeof(struct psp_runtime_boot_cfg_entry)) { /* invalid db entry size */ dev_warn(adev->dev, "Invalid PSP runtime database boot cfg entry size\n"); return false; } /* read runtime database entry */ amdgpu_device_vram_access(adev, db_header_pos + db_dir.entry_list[i].offset, (uint32_t *)db_entry, sizeof(struct psp_runtime_boot_cfg_entry), false); ret = true; break; case PSP_RUNTIME_ENTRY_TYPE_PPTABLE_ERR_STATUS: if (db_dir.entry_list[i].size < sizeof(struct psp_runtime_scpm_entry)) { /* invalid db entry size */ dev_warn(adev->dev, "Invalid PSP runtime database scpm entry size\n"); return false; } /* read runtime database entry */ amdgpu_device_vram_access(adev, db_header_pos + db_dir.entry_list[i].offset, (uint32_t *)db_entry, sizeof(struct psp_runtime_scpm_entry), false); ret = true; break; default: ret = false; break; } } } return ret; } static int psp_sw_init(struct amdgpu_ip_block *ip_block) { struct amdgpu_device *adev = ip_block->adev; struct psp_context *psp = &adev->psp; int ret; struct psp_runtime_boot_cfg_entry boot_cfg_entry; struct psp_memory_training_context *mem_training_ctx = &psp->mem_train_ctx; struct psp_runtime_scpm_entry scpm_entry; psp->cmd = kzalloc_obj(struct psp_gfx_cmd_resp); if (!psp->cmd) { dev_err(adev->dev, "Failed to allocate memory to command buffer!\n"); return -ENOMEM; } adev->psp.xgmi_context.supports_extended_data = !adev->gmc.xgmi.connected_to_cpu && amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(13, 0, 2); memset(&scpm_entry, 0, sizeof(scpm_entry)); if ((psp_get_runtime_db_entry(adev, PSP_RUNTIME_ENTRY_TYPE_PPTABLE_ERR_STATUS, &scpm_entry)) && (scpm_entry.scpm_status != SCPM_DISABLE)) { adev->scpm_enabled = true; adev->scpm_status = scpm_entry.scpm_status; } else { adev->scpm_enabled = false; adev->scpm_status = SCPM_DISABLE; }