3
0
mirror of https://github.com/Qortal/Brooklyn.git synced 2025-02-01 07:42:18 +00:00
Brooklyn/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
Raziel K. Crowe 04c1822c0a There is a moose on the mool buff
Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey! Ring the door. Take your seat moosey!
2022-03-15 21:13:23 +05:00

3587 lines
91 KiB
C

/*
* 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 "amdgpu_ras.h"
#include "amdgpu_securedisplay.h"
#include "amdgpu_atomfirmware.h"
static int psp_sysfs_init(struct amdgpu_device *adev);
static void psp_sysfs_fini(struct amdgpu_device *adev);
static int psp_load_smu_fw(struct psp_context *psp);
/*
* 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
* - Navi12 and onwards
*/
static void psp_check_pmfw_centralized_cstate_management(struct psp_context *psp)
{
struct amdgpu_device *adev = psp->adev;
psp->pmfw_centralized_cstate_management = false;
if (amdgpu_sriov_vf(adev))
return;
if (adev->flags & AMD_IS_APU)
return;
if ((adev->asic_type >= CHIP_ARCTURUS) ||
(adev->asic_type >= CHIP_NAVI12))
psp->pmfw_centralized_cstate_management = true;
}
static int psp_early_init(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
struct psp_context *psp = &adev->psp;
switch (adev->asic_type) {
case CHIP_VEGA10:
case CHIP_VEGA12:
psp_v3_1_set_psp_funcs(psp);
psp->autoload_supported = false;
break;
case CHIP_RAVEN:
psp_v10_0_set_psp_funcs(psp);
psp->autoload_supported = false;
break;
case CHIP_VEGA20:
case CHIP_ARCTURUS:
psp_v11_0_set_psp_funcs(psp);
psp->autoload_supported = false;
break;
case CHIP_NAVI10:
case CHIP_NAVI14:
case CHIP_NAVI12:
case CHIP_SIENNA_CICHLID:
case CHIP_NAVY_FLOUNDER:
case CHIP_VANGOGH:
case CHIP_DIMGREY_CAVEFISH:
case CHIP_BEIGE_GOBY:
psp_v11_0_set_psp_funcs(psp);
psp->autoload_supported = true;
break;
case CHIP_RENOIR:
psp_v12_0_set_psp_funcs(psp);
break;
case CHIP_ALDEBARAN:
psp_v13_0_set_psp_funcs(psp);
break;
case CHIP_YELLOW_CARP:
psp_v13_0_set_psp_funcs(psp);
psp->autoload_supported = true;
break;
case CHIP_CYAN_SKILLFISH:
if (adev->apu_flags & AMD_APU_IS_CYAN_SKILLFISH2) {
psp_v11_0_8_set_psp_funcs(psp);
psp->autoload_supported = false;
}
break;
default:
return -EINVAL;
}
psp->adev = adev;
psp_check_pmfw_centralized_cstate_management(psp);
return 0;
}
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) {
DRM_DEBUG("memory training is not supported!\n");
return 0;
}
ctx->sys_cache = kzalloc(ctx->train_data_size, GFP_KERNEL);
if (ctx->sys_cache == NULL) {
DRM_ERROR("alloc mem_train_ctx.sys_cache failed!\n");
ret = -ENOMEM;
goto Err_out;
}
DRM_DEBUG("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;
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_warn(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 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;
default:
ret = false;
break;
}
}
}
return ret;
}
static int psp_sw_init(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
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;
psp->cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL);
if (!psp->cmd) {
DRM_ERROR("Failed to allocate memory to command buffer!\n");
ret = -ENOMEM;
}
if (!amdgpu_sriov_vf(adev)) {
ret = psp_init_microcode(psp);
if (ret) {
DRM_ERROR("Failed to load psp firmware!\n");
return ret;
}
} else if (amdgpu_sriov_vf(adev) && adev->asic_type == CHIP_ALDEBARAN) {
ret = psp_init_ta_microcode(psp, "aldebaran");
if (ret) {
DRM_ERROR("Failed to initialize ta microcode!\n");
return ret;
}
}
memset(&boot_cfg_entry, 0, sizeof(boot_cfg_entry));
if (psp_get_runtime_db_entry(adev,
PSP_RUNTIME_ENTRY_TYPE_BOOT_CONFIG,
&boot_cfg_entry)) {
psp->boot_cfg_bitmask = boot_cfg_entry.boot_cfg_bitmask;
if ((psp->boot_cfg_bitmask) &
BOOT_CFG_FEATURE_TWO_STAGE_DRAM_TRAINING) {
/* If psp runtime database exists, then
* only enable two stage memory training
* when TWO_STAGE_DRAM_TRAINING bit is set
* in runtime database */
mem_training_ctx->enable_mem_training = true;
}
} else {
/* If psp runtime database doesn't exist or
* is invalid, force enable two stage memory
* training */
mem_training_ctx->enable_mem_training = true;
}
if (mem_training_ctx->enable_mem_training) {
ret = psp_memory_training_init(psp);
if (ret) {
DRM_ERROR("Failed to initialize memory training!\n");
return ret;
}
ret = psp_mem_training(psp, PSP_MEM_TRAIN_COLD_BOOT);
if (ret) {
DRM_ERROR("Failed to process memory training!\n");
return ret;
}
}
if (adev->asic_type == CHIP_NAVI10 || adev->asic_type == CHIP_SIENNA_CICHLID) {
ret= psp_sysfs_init(adev);
if (ret) {
return ret;
}
}
return 0;
}
static int psp_sw_fini(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
struct psp_context *psp = &adev->psp;
struct psp_gfx_cmd_resp *cmd = psp->cmd;
psp_memory_training_fini(psp);
if (psp->sos_fw) {
release_firmware(psp->sos_fw);
psp->sos_fw = NULL;
}
if (psp->asd_fw) {
release_firmware(psp->asd_fw);
psp->asd_fw = NULL;
}
if (psp->ta_fw) {
release_firmware(psp->ta_fw);
psp->ta_fw = NULL;
}
if (adev->asic_type == CHIP_NAVI10 ||
adev->asic_type == CHIP_SIENNA_CICHLID)
psp_sysfs_fini(adev);
kfree(cmd);
cmd = NULL;
return 0;
}
int psp_wait_for(struct psp_context *psp, uint32_t reg_index,
uint32_t reg_val, uint32_t mask, bool check_changed)
{
uint32_t val;
int i;
struct amdgpu_device *adev = psp->adev;
if (psp->adev->no_hw_access)
return 0;
for (i = 0; i < adev->usec_timeout; i++) {
val = RREG32(reg_index);
if (check_changed) {
if (val != reg_val)
return 0;
} else {
if ((val & mask) == reg_val)
return 0;
}
udelay(1);
}
return -ETIME;
}
static const char *psp_gfx_cmd_name(enum psp_gfx_cmd_id cmd_id)
{
switch (cmd_id) {
case GFX_CMD_ID_LOAD_TA:
return "LOAD_TA";
case GFX_CMD_ID_UNLOAD_TA:
return "UNLOAD_TA";
case GFX_CMD_ID_INVOKE_CMD:
return "INVOKE_CMD";
case GFX_CMD_ID_LOAD_ASD:
return "LOAD_ASD";
case GFX_CMD_ID_SETUP_TMR:
return "SETUP_TMR";
case GFX_CMD_ID_LOAD_IP_FW:
return "LOAD_IP_FW";
case GFX_CMD_ID_DESTROY_TMR:
return "DESTROY_TMR";
case GFX_CMD_ID_SAVE_RESTORE:
return "SAVE_RESTORE_IP_FW";
case GFX_CMD_ID_SETUP_VMR:
return "SETUP_VMR";
case GFX_CMD_ID_DESTROY_VMR:
return "DESTROY_VMR";
case GFX_CMD_ID_PROG_REG:
return "PROG_REG";
case GFX_CMD_ID_GET_FW_ATTESTATION:
return "GET_FW_ATTESTATION";
case GFX_CMD_ID_LOAD_TOC:
return "ID_LOAD_TOC";
case GFX_CMD_ID_AUTOLOAD_RLC:
return "AUTOLOAD_RLC";
case GFX_CMD_ID_BOOT_CFG:
return "BOOT_CFG";
default:
return "UNKNOWN CMD";
}
}
static int
psp_cmd_submit_buf(struct psp_context *psp,
struct amdgpu_firmware_info *ucode,
struct psp_gfx_cmd_resp *cmd, uint64_t fence_mc_addr)
{
int ret;
int index, idx;
int timeout = 20000;
bool ras_intr = false;
bool skip_unsupport = false;
if (psp->adev->no_hw_access)
return 0;
if (!drm_dev_enter(&psp->adev->ddev, &idx))
return 0;
memset(psp->cmd_buf_mem, 0, PSP_CMD_BUFFER_SIZE);
memcpy(psp->cmd_buf_mem, cmd, sizeof(struct psp_gfx_cmd_resp));
index = atomic_inc_return(&psp->fence_value);
ret = psp_ring_cmd_submit(psp, psp->cmd_buf_mc_addr, fence_mc_addr, index);
if (ret) {
atomic_dec(&psp->fence_value);
goto exit;
}
amdgpu_device_invalidate_hdp(psp->adev, NULL);
while (*((unsigned int *)psp->fence_buf) != index) {
if (--timeout == 0)
break;
/*
* Shouldn't wait for timeout when err_event_athub occurs,
* because gpu reset thread triggered and lock resource should
* be released for psp resume sequence.
*/
ras_intr = amdgpu_ras_intr_triggered();
if (ras_intr)
break;
usleep_range(10, 100);
amdgpu_device_invalidate_hdp(psp->adev, NULL);
}
/* We allow TEE_ERROR_NOT_SUPPORTED for VMR command and PSP_ERR_UNKNOWN_COMMAND in SRIOV */
skip_unsupport = (psp->cmd_buf_mem->resp.status == TEE_ERROR_NOT_SUPPORTED ||
psp->cmd_buf_mem->resp.status == PSP_ERR_UNKNOWN_COMMAND) && amdgpu_sriov_vf(psp->adev);
memcpy((void*)&cmd->resp, (void*)&psp->cmd_buf_mem->resp, sizeof(struct psp_gfx_resp));
/* In some cases, psp response status is not 0 even there is no
* problem while the command is submitted. Some version of PSP FW
* doesn't write 0 to that field.
* So here we would like to only print a warning instead of an error
* during psp initialization to avoid breaking hw_init and it doesn't
* return -EINVAL.
*/
if (!skip_unsupport && (psp->cmd_buf_mem->resp.status || !timeout) && !ras_intr) {
if (ucode)
DRM_WARN("failed to load ucode %s(0x%X) ",
amdgpu_ucode_name(ucode->ucode_id), ucode->ucode_id);
DRM_WARN("psp gfx command %s(0x%X) failed and response status is (0x%X)\n",
psp_gfx_cmd_name(psp->cmd_buf_mem->cmd_id), psp->cmd_buf_mem->cmd_id,
psp->cmd_buf_mem->resp.status);
if (!timeout) {
ret = -EINVAL;
goto exit;
}
}
if (ucode) {
ucode->tmr_mc_addr_lo = psp->cmd_buf_mem->resp.fw_addr_lo;
ucode->tmr_mc_addr_hi = psp->cmd_buf_mem->resp.fw_addr_hi;
}
exit:
drm_dev_exit(idx);
return ret;
}
static struct psp_gfx_cmd_resp *acquire_psp_cmd_buf(struct psp_context *psp)
{
struct psp_gfx_cmd_resp *cmd = psp->cmd;
mutex_lock(&psp->mutex);
memset(cmd, 0, sizeof(struct psp_gfx_cmd_resp));
return cmd;
}
void release_psp_cmd_buf(struct psp_context *psp)
{
mutex_unlock(&psp->mutex);
}
static void psp_prep_tmr_cmd_buf(struct psp_context *psp,
struct psp_gfx_cmd_resp *cmd,
uint64_t tmr_mc, struct amdgpu_bo *tmr_bo)
{
struct amdgpu_device *adev = psp->adev;
uint32_t size = amdgpu_bo_size(tmr_bo);
uint64_t tmr_pa = amdgpu_gmc_vram_pa(adev, tmr_bo);
if (amdgpu_sriov_vf(psp->adev))
cmd->cmd_id = GFX_CMD_ID_SETUP_VMR;
else
cmd->cmd_id = GFX_CMD_ID_SETUP_TMR;
cmd->cmd.cmd_setup_tmr.buf_phy_addr_lo = lower_32_bits(tmr_mc);
cmd->cmd.cmd_setup_tmr.buf_phy_addr_hi = upper_32_bits(tmr_mc);
cmd->cmd.cmd_setup_tmr.buf_size = size;
cmd->cmd.cmd_setup_tmr.bitfield.virt_phy_addr = 1;
cmd->cmd.cmd_setup_tmr.system_phy_addr_lo = lower_32_bits(tmr_pa);
cmd->cmd.cmd_setup_tmr.system_phy_addr_hi = upper_32_bits(tmr_pa);
}
static void psp_prep_load_toc_cmd_buf(struct psp_gfx_cmd_resp *cmd,
uint64_t pri_buf_mc, uint32_t size)
{
cmd->cmd_id = GFX_CMD_ID_LOAD_TOC;
cmd->cmd.cmd_load_toc.toc_phy_addr_lo = lower_32_bits(pri_buf_mc);
cmd->cmd.cmd_load_toc.toc_phy_addr_hi = upper_32_bits(pri_buf_mc);
cmd->cmd.cmd_load_toc.toc_size = size;
}
/* Issue LOAD TOC cmd to PSP to part toc and calculate tmr size needed */
static int psp_load_toc(struct psp_context *psp,
uint32_t *tmr_size)
{
int ret;
struct psp_gfx_cmd_resp *cmd = acquire_psp_cmd_buf(psp);
/* Copy toc to psp firmware private buffer */
psp_copy_fw(psp, psp->toc.start_addr, psp->toc.size_bytes);
psp_prep_load_toc_cmd_buf(cmd, psp->fw_pri_mc_addr, psp->toc.size_bytes);
ret = psp_cmd_submit_buf(psp, NULL, cmd,
psp->fence_buf_mc_addr);
if (!ret)
*tmr_size = psp->cmd_buf_mem->resp.tmr_size;
release_psp_cmd_buf(psp);
return ret;
}
/* Set up Trusted Memory Region */
static int psp_tmr_init(struct psp_context *psp)
{
int ret;
int tmr_size;
void *tmr_buf;
void **pptr;
/*
* According to HW engineer, they prefer the TMR address be "naturally
* aligned" , e.g. the start address be an integer divide of TMR size.
*
* Note: this memory need be reserved till the driver
* uninitializes.
*/
tmr_size = PSP_TMR_SIZE(psp->adev);
/* For ASICs support RLC autoload, psp will parse the toc
* and calculate the total size of TMR needed */
if (!amdgpu_sriov_vf(psp->adev) &&
psp->toc.start_addr &&
psp->toc.size_bytes &&
psp->fw_pri_buf) {
ret = psp_load_toc(psp, &tmr_size);
if (ret) {
DRM_ERROR("Failed to load toc\n");
return ret;
}
}
pptr = amdgpu_sriov_vf(psp->adev) ? &tmr_buf : NULL;
ret = amdgpu_bo_create_kernel(psp->adev, tmr_size, PSP_TMR_SIZE(psp->adev),
AMDGPU_GEM_DOMAIN_VRAM,
&psp->tmr_bo, &psp->tmr_mc_addr, pptr);
return ret;
}
static bool psp_skip_tmr(struct psp_context *psp)
{
switch (psp->adev->asic_type) {
case CHIP_NAVI12:
case CHIP_SIENNA_CICHLID:
case CHIP_ALDEBARAN:
return true;
default:
return false;
}
}
static int psp_tmr_load(struct psp_context *psp)
{
int ret;
struct psp_gfx_cmd_resp *cmd;
/* For Navi12 and CHIP_SIENNA_CICHLID SRIOV, do not set up TMR.
* Already set up by host driver.
*/
if (amdgpu_sriov_vf(psp->adev) && psp_skip_tmr(psp))
return 0;
cmd = acquire_psp_cmd_buf(psp);
psp_prep_tmr_cmd_buf(psp, cmd, psp->tmr_mc_addr, psp->tmr_bo);
DRM_INFO("reserve 0x%lx from 0x%llx for PSP TMR\n",
amdgpu_bo_size(psp->tmr_bo), psp->tmr_mc_addr);
ret = psp_cmd_submit_buf(psp, NULL, cmd,
psp->fence_buf_mc_addr);
release_psp_cmd_buf(psp);
return ret;
}
static void psp_prep_tmr_unload_cmd_buf(struct psp_context *psp,
struct psp_gfx_cmd_resp *cmd)
{
if (amdgpu_sriov_vf(psp->adev))
cmd->cmd_id = GFX_CMD_ID_DESTROY_VMR;
else
cmd->cmd_id = GFX_CMD_ID_DESTROY_TMR;
}
static int psp_tmr_unload(struct psp_context *psp)
{
int ret;
struct psp_gfx_cmd_resp *cmd = acquire_psp_cmd_buf(psp);
psp_prep_tmr_unload_cmd_buf(psp, cmd);
DRM_INFO("free PSP TMR buffer\n");
ret = psp_cmd_submit_buf(psp, NULL, cmd,
psp->fence_buf_mc_addr);
release_psp_cmd_buf(psp);
return ret;
}
static int psp_tmr_terminate(struct psp_context *psp)
{
int ret;
void *tmr_buf;
void **pptr;
ret = psp_tmr_unload(psp);
if (ret)
return ret;
/* 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);
return 0;
}
int psp_get_fw_attestation_records_addr(struct psp_context *psp,
uint64_t *output_ptr)
{
int ret;
struct psp_gfx_cmd_resp *cmd;
if (!output_ptr)
return -EINVAL;
if (amdgpu_sriov_vf(psp->adev))
return 0;
cmd = acquire_psp_cmd_buf(psp);
cmd->cmd_id = GFX_CMD_ID_GET_FW_ATTESTATION;
ret = psp_cmd_submit_buf(psp, NULL, cmd,
psp->fence_buf_mc_addr);
if (!ret) {
*output_ptr = ((uint64_t)cmd->resp.uresp.fwar_db_info.fwar_db_addr_lo) +
((uint64_t)cmd->resp.uresp.fwar_db_info.fwar_db_addr_hi << 32);
}
release_psp_cmd_buf(psp);
return ret;
}
static int psp_boot_config_get(struct amdgpu_device *adev, uint32_t *boot_cfg)
{
struct psp_context *psp = &adev->psp;
struct psp_gfx_cmd_resp *cmd;
int ret;
if (amdgpu_sriov_vf(adev))
return 0;
cmd = acquire_psp_cmd_buf(psp);
cmd->cmd_id = GFX_CMD_ID_BOOT_CFG;
cmd->cmd.boot_cfg.sub_cmd = BOOTCFG_CMD_GET;
ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr);
if (!ret) {
*boot_cfg =
(cmd->resp.uresp.boot_cfg.boot_cfg & BOOT_CONFIG_GECC) ? 1 : 0;
}
release_psp_cmd_buf(psp);
return ret;
}
static int psp_boot_config_set(struct amdgpu_device *adev, uint32_t boot_cfg)
{
int ret;
struct psp_context *psp = &adev->psp;
struct psp_gfx_cmd_resp *cmd;
if (amdgpu_sriov_vf(adev))
return 0;
cmd = acquire_psp_cmd_buf(psp);
cmd->cmd_id = GFX_CMD_ID_BOOT_CFG;
cmd->cmd.boot_cfg.sub_cmd = BOOTCFG_CMD_SET;
cmd->cmd.boot_cfg.boot_config = boot_cfg;
cmd->cmd.boot_cfg.boot_config_valid = boot_cfg;
ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr);
release_psp_cmd_buf(psp);
return ret;
}
static int psp_rl_load(struct amdgpu_device *adev)
{
int ret;
struct psp_context *psp = &adev->psp;
struct psp_gfx_cmd_resp *cmd;
if (!is_psp_fw_valid(psp->rl))
return 0;
cmd = acquire_psp_cmd_buf(psp);
memset(psp->fw_pri_buf, 0, PSP_1_MEG);
memcpy(psp->fw_pri_buf, psp->rl.start_addr, psp->rl.size_bytes);
cmd->cmd_id = GFX_CMD_ID_LOAD_IP_FW;
cmd->cmd.cmd_load_ip_fw.fw_phy_addr_lo = lower_32_bits(psp->fw_pri_mc_addr);
cmd->cmd.cmd_load_ip_fw.fw_phy_addr_hi = upper_32_bits(psp->fw_pri_mc_addr);
cmd->cmd.cmd_load_ip_fw.fw_size = psp->rl.size_bytes;
cmd->cmd.cmd_load_ip_fw.fw_type = GFX_FW_TYPE_REG_LIST;
ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr);
release_psp_cmd_buf(psp);
return ret;
}
static void psp_prep_asd_load_cmd_buf(struct psp_gfx_cmd_resp *cmd,
uint64_t asd_mc, uint32_t size)
{
cmd->cmd_id = GFX_CMD_ID_LOAD_ASD;
cmd->cmd.cmd_load_ta.app_phy_addr_lo = lower_32_bits(asd_mc);
cmd->cmd.cmd_load_ta.app_phy_addr_hi = upper_32_bits(asd_mc);
cmd->cmd.cmd_load_ta.app_len = size;
cmd->cmd.cmd_load_ta.cmd_buf_phy_addr_lo = 0;
cmd->cmd.cmd_load_ta.cmd_buf_phy_addr_hi = 0;
cmd->cmd.cmd_load_ta.cmd_buf_len = 0;
}
static int psp_asd_load(struct psp_context *psp)
{
int ret;
struct psp_gfx_cmd_resp *cmd;
/* If PSP version doesn't match ASD version, asd loading will be failed.
* add workaround to bypass it for sriov now.
* TODO: add version check to make it common
*/
if (amdgpu_sriov_vf(psp->adev) || !psp->asd.size_bytes)
return 0;
cmd = acquire_psp_cmd_buf(psp);
psp_copy_fw(psp, psp->asd.start_addr, psp->asd.size_bytes);
psp_prep_asd_load_cmd_buf(cmd, psp->fw_pri_mc_addr,
psp->asd.size_bytes);
ret = psp_cmd_submit_buf(psp, NULL, cmd,
psp->fence_buf_mc_addr);
if (!ret) {
psp->asd_context.asd_initialized = true;
psp->asd_context.session_id = cmd->resp.session_id;
}
release_psp_cmd_buf(psp);
return ret;
}
static void psp_prep_ta_unload_cmd_buf(struct psp_gfx_cmd_resp *cmd,
uint32_t session_id)
{
cmd->cmd_id = GFX_CMD_ID_UNLOAD_TA;
cmd->cmd.cmd_unload_ta.session_id = session_id;
}
static int psp_asd_unload(struct psp_context *psp)
{
int ret;
struct psp_gfx_cmd_resp *cmd;
if (amdgpu_sriov_vf(psp->adev))
return 0;
if (!psp->asd_context.asd_initialized)
return 0;
cmd = acquire_psp_cmd_buf(psp);
psp_prep_ta_unload_cmd_buf(cmd, psp->asd_context.session_id);
ret = psp_cmd_submit_buf(psp, NULL, cmd,
psp->fence_buf_mc_addr);
if (!ret)
psp->asd_context.asd_initialized = false;
release_psp_cmd_buf(psp);
return ret;
}
static void psp_prep_reg_prog_cmd_buf(struct psp_gfx_cmd_resp *cmd,
uint32_t id, uint32_t value)
{
cmd->cmd_id = GFX_CMD_ID_PROG_REG;
cmd->cmd.cmd_setup_reg_prog.reg_value = value;
cmd->cmd.cmd_setup_reg_prog.reg_id = id;
}
int psp_reg_program(struct psp_context *psp, enum psp_reg_prog_id reg,
uint32_t value)
{
struct psp_gfx_cmd_resp *cmd;
int ret = 0;
if (reg >= PSP_REG_LAST)
return -EINVAL;
cmd = acquire_psp_cmd_buf(psp);
psp_prep_reg_prog_cmd_buf(cmd, reg, value);
ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr);
if (ret)
DRM_ERROR("PSP failed to program reg id %d", reg);
release_psp_cmd_buf(psp);
return ret;
}
static void psp_prep_ta_load_cmd_buf(struct psp_gfx_cmd_resp *cmd,
uint64_t ta_bin_mc,
uint32_t ta_bin_size,
uint64_t ta_shared_mc,
uint32_t ta_shared_size)
{
cmd->cmd_id = GFX_CMD_ID_LOAD_TA;
cmd->cmd.cmd_load_ta.app_phy_addr_lo = lower_32_bits(ta_bin_mc);
cmd->cmd.cmd_load_ta.app_phy_addr_hi = upper_32_bits(ta_bin_mc);
cmd->cmd.cmd_load_ta.app_len = ta_bin_size;
cmd->cmd.cmd_load_ta.cmd_buf_phy_addr_lo = lower_32_bits(ta_shared_mc);
cmd->cmd.cmd_load_ta.cmd_buf_phy_addr_hi = upper_32_bits(ta_shared_mc);
cmd->cmd.cmd_load_ta.cmd_buf_len = ta_shared_size;
}
static int psp_ta_init_shared_buf(struct psp_context *psp,
struct ta_mem_context *mem_ctx,
uint32_t shared_mem_size)
{
int ret;
/*
* Allocate 16k memory aligned to 4k from Frame Buffer (local
* physical) for ta to host memory
*/
ret = amdgpu_bo_create_kernel(psp->adev, shared_mem_size, PAGE_SIZE,
AMDGPU_GEM_DOMAIN_VRAM,
&mem_ctx->shared_bo,
&mem_ctx->shared_mc_addr,
&mem_ctx->shared_buf);
return ret;
}
static 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);
}
static int psp_xgmi_init_shared_buf(struct psp_context *psp)
{
return psp_ta_init_shared_buf(psp, &psp->xgmi_context.context.mem_context,
PSP_XGMI_SHARED_MEM_SIZE);
}
static void psp_prep_ta_invoke_cmd_buf(struct psp_gfx_cmd_resp *cmd,
uint32_t ta_cmd_id,
uint32_t session_id)
{
cmd->cmd_id = GFX_CMD_ID_INVOKE_CMD;
cmd->cmd.cmd_invoke_cmd.session_id = session_id;
cmd->cmd.cmd_invoke_cmd.ta_cmd_id = ta_cmd_id;
}
static int psp_ta_invoke(struct psp_context *psp,
uint32_t ta_cmd_id,
uint32_t session_id)
{
int ret;
struct psp_gfx_cmd_resp *cmd = acquire_psp_cmd_buf(psp);
psp_prep_ta_invoke_cmd_buf(cmd, ta_cmd_id, session_id);
ret = psp_cmd_submit_buf(psp, NULL, cmd,
psp->fence_buf_mc_addr);
release_psp_cmd_buf(psp);
return ret;
}
static int psp_xgmi_load(struct psp_context *psp)
{
int ret;
struct psp_gfx_cmd_resp *cmd;
/*
* TODO: bypass the loading in sriov for now
*/
cmd = acquire_psp_cmd_buf(psp);
psp_copy_fw(psp, psp->xgmi.start_addr, psp->xgmi.size_bytes);
psp_prep_ta_load_cmd_buf(cmd,
psp->fw_pri_mc_addr,
psp->xgmi.size_bytes,
psp->xgmi_context.context.mem_context.shared_mc_addr,
PSP_XGMI_SHARED_MEM_SIZE);
ret = psp_cmd_submit_buf(psp, NULL, cmd,
psp->fence_buf_mc_addr);
if (!ret) {
psp->xgmi_context.context.initialized = true;
psp->xgmi_context.context.session_id = cmd->resp.session_id;
}
release_psp_cmd_buf(psp);
return ret;
}
static int psp_xgmi_unload(struct psp_context *psp)
{
int ret;
struct psp_gfx_cmd_resp *cmd;
struct amdgpu_device *adev = psp->adev;
/* XGMI TA unload currently is not supported on Arcturus/Aldebaran A+A */
if (adev->asic_type == CHIP_ARCTURUS ||
(adev->asic_type == CHIP_ALDEBARAN && adev->gmc.xgmi.connected_to_cpu))
return 0;
/*
* TODO: bypass the unloading in sriov for now
*/
cmd = acquire_psp_cmd_buf(psp);
psp_prep_ta_unload_cmd_buf(cmd, psp->xgmi_context.context.session_id);
ret = psp_cmd_submit_buf(psp, NULL, cmd,
psp->fence_buf_mc_addr);
release_psp_cmd_buf(psp);
return ret;
}
int psp_xgmi_invoke(struct psp_context *psp, uint32_t ta_cmd_id)
{
return psp_ta_invoke(psp, ta_cmd_id, psp->xgmi_context.context.session_id);
}
int psp_xgmi_terminate(struct psp_context *psp)
{
int ret;
if (!psp->xgmi_context.context.initialized)
return 0;
ret = psp_xgmi_unload(psp);
if (ret)
return ret;
psp->xgmi_context.context.initialized = false;
/* free xgmi shared memory */
psp_ta_free_shared_buf(&psp->xgmi_context.context.mem_context);
return 0;
}
int psp_xgmi_initialize(struct psp_context *psp, bool set_extended_data, bool load_ta)
{
struct ta_xgmi_shared_memory *xgmi_cmd;
int ret;
if (!psp->ta_fw ||
!psp->xgmi.size_bytes ||
!psp->xgmi.start_addr)
return -ENOENT;
if (!load_ta)
goto invoke;
if (!psp->xgmi_context.context.initialized) {
ret = psp_xgmi_init_shared_buf(psp);
if (ret)
return ret;
}
/* Load XGMI TA */
ret = psp_xgmi_load(psp);
if (ret)
return ret;
invoke:
/* Initialize XGMI session */
xgmi_cmd = (struct ta_xgmi_shared_memory *)(psp->xgmi_context.context.mem_context.shared_buf);
memset(xgmi_cmd, 0, sizeof(struct ta_xgmi_shared_memory));
xgmi_cmd->flag_extend_link_record = set_extended_data;
xgmi_cmd->cmd_id = TA_COMMAND_XGMI__INITIALIZE;
ret = psp_xgmi_invoke(psp, xgmi_cmd->cmd_id);
return ret;
}
int psp_xgmi_get_hive_id(struct psp_context *psp, uint64_t *hive_id)
{
struct ta_xgmi_shared_memory *xgmi_cmd;
int ret;
xgmi_cmd = (struct ta_xgmi_shared_memory *)psp->xgmi_context.context.mem_context.shared_buf;
memset(xgmi_cmd, 0, sizeof(struct ta_xgmi_shared_memory));
xgmi_cmd->cmd_id = TA_COMMAND_XGMI__GET_HIVE_ID;
/* Invoke xgmi ta to get hive id */
ret = psp_xgmi_invoke(psp, xgmi_cmd->cmd_id);
if (ret)
return ret;
*hive_id = xgmi_cmd->xgmi_out_message.get_hive_id.hive_id;
return 0;
}
int psp_xgmi_get_node_id(struct psp_context *psp, uint64_t *node_id)
{
struct ta_xgmi_shared_memory *xgmi_cmd;
int ret;
xgmi_cmd = (struct ta_xgmi_shared_memory *)psp->xgmi_context.context.mem_context.shared_buf;
memset(xgmi_cmd, 0, sizeof(struct ta_xgmi_shared_memory));
xgmi_cmd->cmd_id = TA_COMMAND_XGMI__GET_NODE_ID;
/* Invoke xgmi ta to get the node id */
ret = psp_xgmi_invoke(psp, xgmi_cmd->cmd_id);
if (ret)
return ret;
*node_id = xgmi_cmd->xgmi_out_message.get_node_id.node_id;
return 0;
}
static bool psp_xgmi_peer_link_info_supported(struct psp_context *psp)
{
return psp->adev->asic_type == CHIP_ALDEBARAN &&
psp->xgmi.feature_version >= 0x2000000b;
}
/*
* Chips that support extended topology information require the driver to
* reflect topology information in the opposite direction. This is
* because the TA has already exceeded its link record limit and if the
* TA holds bi-directional information, the driver would have to do
* multiple fetches instead of just two.
*/
static void psp_xgmi_reflect_topology_info(struct psp_context *psp,
struct psp_xgmi_node_info node_info)
{
struct amdgpu_device *mirror_adev;
struct amdgpu_hive_info *hive;
uint64_t src_node_id = psp->adev->gmc.xgmi.node_id;
uint64_t dst_node_id = node_info.node_id;
uint8_t dst_num_hops = node_info.num_hops;
uint8_t dst_num_links = node_info.num_links;
hive = amdgpu_get_xgmi_hive(psp->adev);
list_for_each_entry(mirror_adev, &hive->device_list, gmc.xgmi.head) {
struct psp_xgmi_topology_info *mirror_top_info;
int j;
if (mirror_adev->gmc.xgmi.node_id != dst_node_id)
continue;
mirror_top_info = &mirror_adev->psp.xgmi_context.top_info;
for (j = 0; j < mirror_top_info->num_nodes; j++) {
if (mirror_top_info->nodes[j].node_id != src_node_id)
continue;
mirror_top_info->nodes[j].num_hops = dst_num_hops;
/*
* prevent 0 num_links value re-reflection since reflection
* criteria is based on num_hops (direct or indirect).
*
*/
if (dst_num_links)
mirror_top_info->nodes[j].num_links = dst_num_links;
break;
}
break;
}
}
int psp_xgmi_get_topology_info(struct psp_context *psp,
int number_devices,
struct psp_xgmi_topology_info *topology,
bool get_extended_data)
{
struct ta_xgmi_shared_memory *xgmi_cmd;
struct ta_xgmi_cmd_get_topology_info_input *topology_info_input;
struct ta_xgmi_cmd_get_topology_info_output *topology_info_output;
int i;
int ret;
if (!topology || topology->num_nodes > TA_XGMI__MAX_CONNECTED_NODES)
return -EINVAL;
xgmi_cmd = (struct ta_xgmi_shared_memory *)psp->xgmi_context.context.mem_context.shared_buf;
memset(xgmi_cmd, 0, sizeof(struct ta_xgmi_shared_memory));
xgmi_cmd->flag_extend_link_record = get_extended_data;
/* Fill in the shared memory with topology information as input */
topology_info_input = &xgmi_cmd->xgmi_in_message.get_topology_info;
xgmi_cmd->cmd_id = TA_COMMAND_XGMI__GET_GET_TOPOLOGY_INFO;
topology_info_input->num_nodes = number_devices;
for (i = 0; i < topology_info_input->num_nodes; i++) {
topology_info_input->nodes[i].node_id = topology->nodes[i].node_id;
topology_info_input->nodes[i].num_hops = topology->nodes[i].num_hops;
topology_info_input->nodes[i].is_sharing_enabled = topology->nodes[i].is_sharing_enabled;
topology_info_input->nodes[i].sdma_engine = topology->nodes[i].sdma_engine;
}
/* Invoke xgmi ta to get the topology information */
ret = psp_xgmi_invoke(psp, TA_COMMAND_XGMI__GET_GET_TOPOLOGY_INFO);
if (ret)
return ret;
/* Read the output topology information from the shared memory */
topology_info_output = &xgmi_cmd->xgmi_out_message.get_topology_info;
topology->num_nodes = xgmi_cmd->xgmi_out_message.get_topology_info.num_nodes;
for (i = 0; i < topology->num_nodes; i++) {
/* extended data will either be 0 or equal to non-extended data */
if (topology_info_output->nodes[i].num_hops)
topology->nodes[i].num_hops = topology_info_output->nodes[i].num_hops;
/* non-extended data gets everything here so no need to update */
if (!get_extended_data) {
topology->nodes[i].node_id = topology_info_output->nodes[i].node_id;
topology->nodes[i].is_sharing_enabled =
topology_info_output->nodes[i].is_sharing_enabled;
topology->nodes[i].sdma_engine =
topology_info_output->nodes[i].sdma_engine;
}
}
/* Invoke xgmi ta again to get the link information */
if (psp_xgmi_peer_link_info_supported(psp)) {
struct ta_xgmi_cmd_get_peer_link_info_output *link_info_output;
xgmi_cmd->cmd_id = TA_COMMAND_XGMI__GET_PEER_LINKS;
ret = psp_xgmi_invoke(psp, TA_COMMAND_XGMI__GET_PEER_LINKS);
if (ret)
return ret;
link_info_output = &xgmi_cmd->xgmi_out_message.get_link_info;
for (i = 0; i < topology->num_nodes; i++) {
/* accumulate num_links on extended data */
topology->nodes[i].num_links = get_extended_data ?
topology->nodes[i].num_links +
link_info_output->nodes[i].num_links :
link_info_output->nodes[i].num_links;
/* reflect the topology information for bi-directionality */
if (psp->xgmi_context.supports_extended_data &&
get_extended_data && topology->nodes[i].num_hops)
psp_xgmi_reflect_topology_info(psp, topology->nodes[i]);
}
}
return 0;
}
int psp_xgmi_set_topology_info(struct psp_context *psp,
int number_devices,
struct psp_xgmi_topology_info *topology)
{
struct ta_xgmi_shared_memory *xgmi_cmd;
struct ta_xgmi_cmd_get_topology_info_input *topology_info_input;
int i;
if (!topology || topology->num_nodes > TA_XGMI__MAX_CONNECTED_NODES)
return -EINVAL;
xgmi_cmd = (struct ta_xgmi_shared_memory *)psp->xgmi_context.context.mem_context.shared_buf;
memset(xgmi_cmd, 0, sizeof(struct ta_xgmi_shared_memory));
topology_info_input = &xgmi_cmd->xgmi_in_message.get_topology_info;
xgmi_cmd->cmd_id = TA_COMMAND_XGMI__SET_TOPOLOGY_INFO;
topology_info_input->num_nodes = number_devices;
for (i = 0; i < topology_info_input->num_nodes; i++) {
topology_info_input->nodes[i].node_id = topology->nodes[i].node_id;
topology_info_input->nodes[i].num_hops = topology->nodes[i].num_hops;
topology_info_input->nodes[i].is_sharing_enabled = 1;
topology_info_input->nodes[i].sdma_engine = topology->nodes[i].sdma_engine;
}
/* Invoke xgmi ta to set topology information */
return psp_xgmi_invoke(psp, TA_COMMAND_XGMI__SET_TOPOLOGY_INFO);
}
// ras begin
static int psp_ras_init_shared_buf(struct psp_context *psp)
{
return psp_ta_init_shared_buf(psp, &psp->ras_context.context.mem_context,
PSP_RAS_SHARED_MEM_SIZE);
}
static int psp_ras_load(struct psp_context *psp)
{
int ret;
struct psp_gfx_cmd_resp *cmd;
struct ta_ras_shared_memory *ras_cmd;
/*
* TODO: bypass the loading in sriov for now
*/
if (amdgpu_sriov_vf(psp->adev))
return 0;
psp_copy_fw(psp, psp->ras.start_addr, psp->ras.size_bytes);
ras_cmd = (struct ta_ras_shared_memory *)psp->ras_context.context.mem_context.shared_buf;
if (psp->adev->gmc.xgmi.connected_to_cpu)
ras_cmd->ras_in_message.init_flags.poison_mode_en = 1;
else
ras_cmd->ras_in_message.init_flags.dgpu_mode = 1;
cmd = acquire_psp_cmd_buf(psp);
psp_prep_ta_load_cmd_buf(cmd,
psp->fw_pri_mc_addr,
psp->ras.size_bytes,
psp->ras_context.context.mem_context.shared_mc_addr,
PSP_RAS_SHARED_MEM_SIZE);
ret = psp_cmd_submit_buf(psp, NULL, cmd,
psp->fence_buf_mc_addr);
if (!ret) {
psp->ras_context.context.session_id = cmd->resp.session_id;
if (!ras_cmd->ras_status)
psp->ras_context.context.initialized = true;
else
dev_warn(psp->adev->dev, "RAS Init Status: 0x%X\n", ras_cmd->ras_status);
}
release_psp_cmd_buf(psp);
if (ret || ras_cmd->ras_status)
amdgpu_ras_fini(psp->adev);
return ret;
}
static int psp_ras_unload(struct psp_context *psp)
{
int ret;
struct psp_gfx_cmd_resp *cmd;
/*
* TODO: bypass the unloading in sriov for now
*/
if (amdgpu_sriov_vf(psp->adev))
return 0;
cmd = acquire_psp_cmd_buf(psp);
psp_prep_ta_unload_cmd_buf(cmd, psp->ras_context.context.session_id);
ret = psp_cmd_submit_buf(psp, NULL, cmd,
psp->fence_buf_mc_addr);
release_psp_cmd_buf(psp);
return ret;
}
int psp_ras_invoke(struct psp_context *psp, uint32_t ta_cmd_id)
{
struct ta_ras_shared_memory *ras_cmd;
int ret;
ras_cmd = (struct ta_ras_shared_memory *)psp->ras_context.context.mem_context.shared_buf;
/*
* TODO: bypass the loading in sriov for now
*/
if (amdgpu_sriov_vf(psp->adev))
return 0;
ret = psp_ta_invoke(psp, ta_cmd_id, psp->ras_context.context.session_id);
if (amdgpu_ras_intr_triggered())
return ret;
if (ras_cmd->if_version > RAS_TA_HOST_IF_VER)
{
DRM_WARN("RAS: Unsupported Interface");
return -EINVAL;
}
if (!ret) {
if (ras_cmd->ras_out_message.flags.err_inject_switch_disable_flag) {
dev_warn(psp->adev->dev, "ECC switch disabled\n");
ras_cmd->ras_status = TA_RAS_STATUS__ERROR_RAS_NOT_AVAILABLE;
}
else if (ras_cmd->ras_out_message.flags.reg_access_failure_flag)
dev_warn(psp->adev->dev,
"RAS internal register access blocked\n");
}
return ret;
}
static int psp_ras_status_to_errno(struct amdgpu_device *adev,
enum ta_ras_status ras_status)
{
int ret = -EINVAL;
switch (ras_status) {
case TA_RAS_STATUS__SUCCESS:
ret = 0;
break;
case TA_RAS_STATUS__RESET_NEEDED:
ret = -EAGAIN;
break;
case TA_RAS_STATUS__ERROR_RAS_NOT_AVAILABLE:
dev_warn(adev->dev, "RAS WARN: ras function unavailable\n");
break;
case TA_RAS_STATUS__ERROR_ASD_READ_WRITE:
dev_warn(adev->dev, "RAS WARN: asd read or write failed\n");
break;
default:
dev_err(adev->dev, "RAS ERROR: ras function failed ret 0x%X\n", ret);
}
return ret;
}
int psp_ras_enable_features(struct psp_context *psp,
union ta_ras_cmd_input *info, bool enable)
{
struct ta_ras_shared_memory *ras_cmd;
int ret;
if (!psp->ras_context.context.initialized)
return -EINVAL;
ras_cmd = (struct ta_ras_shared_memory *)psp->ras_context.context.mem_context.shared_buf;
memset(ras_cmd, 0, sizeof(struct ta_ras_shared_memory));
if (enable)
ras_cmd->cmd_id = TA_RAS_COMMAND__ENABLE_FEATURES;
else
ras_cmd->cmd_id = TA_RAS_COMMAND__DISABLE_FEATURES;
ras_cmd->ras_in_message = *info;
ret = psp_ras_invoke(psp, ras_cmd->cmd_id);
if (ret)
return -EINVAL;
return psp_ras_status_to_errno(psp->adev, ras_cmd->ras_status);
}
static int psp_ras_terminate(struct psp_context *psp)
{
int ret;
/*
* TODO: bypass the terminate in sriov for now
*/
if (amdgpu_sriov_vf(psp->adev))
return 0;
if (!psp->ras_context.context.initialized)
return 0;
ret = psp_ras_unload(psp);
if (ret)
return ret;
psp->ras_context.context.initialized = false;
/* free ras shared memory */
psp_ta_free_shared_buf(&psp->ras_context.context.mem_context);
return 0;
}
static int psp_ras_initialize(struct psp_context *psp)
{
int ret;
uint32_t boot_cfg = 0xFF;
struct amdgpu_device *adev = psp->adev;
/*
* TODO: bypass the initialize in sriov for now
*/
if (amdgpu_sriov_vf(adev))
return 0;
if (!adev->psp.ras.size_bytes ||
!adev->psp.ras.start_addr) {
dev_info(adev->dev, "RAS: optional ras ta ucode is not available\n");
return 0;
}
if (amdgpu_atomfirmware_dynamic_boot_config_supported(adev)) {
/* query GECC enablement status from boot config
* boot_cfg: 1: GECC is enabled or 0: GECC is disabled
*/
ret = psp_boot_config_get(adev, &boot_cfg);
if (ret)
dev_warn(adev->dev, "PSP get boot config failed\n");
if (!amdgpu_ras_is_supported(psp->adev, AMDGPU_RAS_BLOCK__UMC)) {
if (!boot_cfg) {
dev_info(adev->dev, "GECC is disabled\n");
} else {
/* disable GECC in next boot cycle if ras is
* disabled by module parameter amdgpu_ras_enable
* and/or amdgpu_ras_mask, or boot_config_get call
* is failed
*/
ret = psp_boot_config_set(adev, 0);
if (ret)
dev_warn(adev->dev, "PSP set boot config failed\n");
else
dev_warn(adev->dev, "GECC will be disabled in next boot cycle "
"if set amdgpu_ras_enable and/or amdgpu_ras_mask to 0x0\n");
}
} else {
if (1 == boot_cfg) {
dev_info(adev->dev, "GECC is enabled\n");
} else {
/* enable GECC in next boot cycle if it is disabled
* in boot config, or force enable GECC if failed to
* get boot configuration
*/
ret = psp_boot_config_set(adev, BOOT_CONFIG_GECC);
if (ret)
dev_warn(adev->dev, "PSP set boot config failed\n");
else
dev_warn(adev->dev, "GECC will be enabled in next boot cycle\n");
}
}
}
if (!psp->ras_context.context.initialized) {
ret = psp_ras_init_shared_buf(psp);
if (ret)
return ret;
}
ret = psp_ras_load(psp);
if (ret)
return ret;
return 0;
}
int psp_ras_trigger_error(struct psp_context *psp,
struct ta_ras_trigger_error_input *info)
{
struct ta_ras_shared_memory *ras_cmd;
int ret;
if (!psp->ras_context.context.initialized)
return -EINVAL;
ras_cmd = (struct ta_ras_shared_memory *)psp->ras_context.context.mem_context.shared_buf;
memset(ras_cmd, 0, sizeof(struct ta_ras_shared_memory));
ras_cmd->cmd_id = TA_RAS_COMMAND__TRIGGER_ERROR;
ras_cmd->ras_in_message.trigger_error = *info;
ret = psp_ras_invoke(psp, ras_cmd->cmd_id);
if (ret)
return -EINVAL;
/* If err_event_athub occurs error inject was successful, however
return status from TA is no long reliable */
if (amdgpu_ras_intr_triggered())
return 0;
return psp_ras_status_to_errno(psp->adev, ras_cmd->ras_status);
}
// ras end
// HDCP start
static int psp_hdcp_init_shared_buf(struct psp_context *psp)
{
return psp_ta_init_shared_buf(psp, &psp->hdcp_context.context.mem_context,
PSP_HDCP_SHARED_MEM_SIZE);
}
static int psp_hdcp_load(struct psp_context *psp)
{
int ret;
struct psp_gfx_cmd_resp *cmd;
/*
* TODO: bypass the loading in sriov for now
*/
if (amdgpu_sriov_vf(psp->adev))
return 0;
psp_copy_fw(psp, psp->hdcp.start_addr,
psp->hdcp.size_bytes);
cmd = acquire_psp_cmd_buf(psp);
psp_prep_ta_load_cmd_buf(cmd,
psp->fw_pri_mc_addr,
psp->hdcp.size_bytes,
psp->hdcp_context.context.mem_context.shared_mc_addr,
PSP_HDCP_SHARED_MEM_SIZE);
ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr);
if (!ret) {
psp->hdcp_context.context.initialized = true;
psp->hdcp_context.context.session_id = cmd->resp.session_id;
mutex_init(&psp->hdcp_context.mutex);
}
release_psp_cmd_buf(psp);
return ret;
}
static int psp_hdcp_initialize(struct psp_context *psp)
{
int ret;
/*
* TODO: bypass the initialize in sriov for now
*/
if (amdgpu_sriov_vf(psp->adev))
return 0;
if (!psp->hdcp.size_bytes ||
!psp->hdcp.start_addr) {
dev_info(psp->adev->dev, "HDCP: optional hdcp ta ucode is not available\n");
return 0;
}
if (!psp->hdcp_context.context.initialized) {
ret = psp_hdcp_init_shared_buf(psp);
if (ret)
return ret;
}
ret = psp_hdcp_load(psp);
if (ret)
return ret;
return 0;
}
static int psp_hdcp_unload(struct psp_context *psp)
{
int ret;
struct psp_gfx_cmd_resp *cmd;
/*
* TODO: bypass the unloading in sriov for now
*/
if (amdgpu_sriov_vf(psp->adev))
return 0;
cmd = acquire_psp_cmd_buf(psp);
psp_prep_ta_unload_cmd_buf(cmd, psp->hdcp_context.context.session_id);
ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr);
release_psp_cmd_buf(psp);
return ret;
}
int psp_hdcp_invoke(struct psp_context *psp, uint32_t ta_cmd_id)
{
/*
* TODO: bypass the loading in sriov for now
*/
if (amdgpu_sriov_vf(psp->adev))
return 0;
return psp_ta_invoke(psp, ta_cmd_id, psp->hdcp_context.context.session_id);
}
static int psp_hdcp_terminate(struct psp_context *psp)
{
int ret;
/*
* TODO: bypass the terminate in sriov for now
*/
if (amdgpu_sriov_vf(psp->adev))
return 0;
if (!psp->hdcp_context.context.initialized) {
if (psp->hdcp_context.context.mem_context.shared_buf)
goto out;
else
return 0;
}
ret = psp_hdcp_unload(psp);
if (ret)
return ret;
psp->hdcp_context.context.initialized = false;
out:
/* free hdcp shared memory */
psp_ta_free_shared_buf(&psp->hdcp_context.context.mem_context);
return 0;
}
// HDCP end
// DTM start
static int psp_dtm_init_shared_buf(struct psp_context *psp)
{
return psp_ta_init_shared_buf(psp, &psp->dtm_context.context.mem_context,
PSP_DTM_SHARED_MEM_SIZE);
}
static int psp_dtm_load(struct psp_context *psp)
{
int ret;
struct psp_gfx_cmd_resp *cmd;
/*
* TODO: bypass the loading in sriov for now
*/
if (amdgpu_sriov_vf(psp->adev))
return 0;
psp_copy_fw(psp, psp->dtm.start_addr, psp->dtm.size_bytes);
cmd = acquire_psp_cmd_buf(psp);
psp_prep_ta_load_cmd_buf(cmd,
psp->fw_pri_mc_addr,
psp->dtm.size_bytes,
psp->dtm_context.context.mem_context.shared_mc_addr,
PSP_DTM_SHARED_MEM_SIZE);
ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr);
if (!ret) {
psp->dtm_context.context.initialized = true;
psp->dtm_context.context.session_id = cmd->resp.session_id;
mutex_init(&psp->dtm_context.mutex);
}
release_psp_cmd_buf(psp);
return ret;
}
static int psp_dtm_initialize(struct psp_context *psp)
{
int ret;
/*
* TODO: bypass the initialize in sriov for now
*/
if (amdgpu_sriov_vf(psp->adev))
return 0;
if (!psp->dtm.size_bytes ||
!psp->dtm.start_addr) {
dev_info(psp->adev->dev, "DTM: optional dtm ta ucode is not available\n");
return 0;
}
if (!psp->dtm_context.context.initialized) {
ret = psp_dtm_init_shared_buf(psp);
if (ret)
return ret;
}
ret = psp_dtm_load(psp);
if (ret)
return ret;
return 0;
}
static int psp_dtm_unload(struct psp_context *psp)
{
int ret;
struct psp_gfx_cmd_resp *cmd;
/*
* TODO: bypass the unloading in sriov for now
*/
if (amdgpu_sriov_vf(psp->adev))
return 0;
cmd = acquire_psp_cmd_buf(psp);
psp_prep_ta_unload_cmd_buf(cmd, psp->dtm_context.context.session_id);
ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr);
release_psp_cmd_buf(psp);
return ret;
}
int psp_dtm_invoke(struct psp_context *psp, uint32_t ta_cmd_id)
{
/*
* TODO: bypass the loading in sriov for now
*/
if (amdgpu_sriov_vf(psp->adev))
return 0;
return psp_ta_invoke(psp, ta_cmd_id, psp->dtm_context.context.session_id);
}
static int psp_dtm_terminate(struct psp_context *psp)
{
int ret;
/*
* TODO: bypass the terminate in sriov for now
*/
if (amdgpu_sriov_vf(psp->adev))
return 0;
if (!psp->dtm_context.context.initialized) {
if (psp->dtm_context.context.mem_context.shared_buf)
goto out;
else
return 0;
}
ret = psp_dtm_unload(psp);
if (ret)
return ret;
psp->dtm_context.context.initialized = false;
out:
/* free dtm shared memory */
psp_ta_free_shared_buf(&psp->dtm_context.context.mem_context);
return 0;
}
// DTM end
// RAP start
static int psp_rap_init_shared_buf(struct psp_context *psp)
{
return psp_ta_init_shared_buf(psp, &psp->rap_context.context.mem_context,
PSP_RAP_SHARED_MEM_SIZE);
}
static int psp_rap_load(struct psp_context *psp)
{
int ret;
struct psp_gfx_cmd_resp *cmd;
psp_copy_fw(psp, psp->rap.start_addr, psp->rap.size_bytes);
cmd = acquire_psp_cmd_buf(psp);
psp_prep_ta_load_cmd_buf(cmd,
psp->fw_pri_mc_addr,
psp->rap.size_bytes,
psp->rap_context.context.mem_context.shared_mc_addr,
PSP_RAP_SHARED_MEM_SIZE);
ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr);
if (!ret) {
psp->rap_context.context.initialized = true;
psp->rap_context.context.session_id = cmd->resp.session_id;
mutex_init(&psp->rap_context.mutex);
}
release_psp_cmd_buf(psp);
return ret;
}
static int psp_rap_unload(struct psp_context *psp)
{
int ret;
struct psp_gfx_cmd_resp *cmd = acquire_psp_cmd_buf(psp);
psp_prep_ta_unload_cmd_buf(cmd, psp->rap_context.context.session_id);
ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr);
release_psp_cmd_buf(psp);
return ret;
}
static int psp_rap_initialize(struct psp_context *psp)
{
int ret;
enum ta_rap_status status = TA_RAP_STATUS__SUCCESS;
/*
* TODO: bypass the initialize in sriov for now
*/
if (amdgpu_sriov_vf(psp->adev))
return 0;
if (!psp->rap.size_bytes ||
!psp->rap.start_addr) {
dev_info(psp->adev->dev, "RAP: optional rap ta ucode is not available\n");
return 0;
}
if (!psp->rap_context.context.initialized) {
ret = psp_rap_init_shared_buf(psp);
if (ret)
return ret;
}
ret = psp_rap_load(psp);
if (ret)
return ret;
ret = psp_rap_invoke(psp, TA_CMD_RAP__INITIALIZE, &status);
if (ret || status != TA_RAP_STATUS__SUCCESS) {
psp_rap_unload(psp);
psp_ta_free_shared_buf(&psp->rap_context.context.mem_context);
psp->rap_context.context.initialized = false;
dev_warn(psp->adev->dev, "RAP TA initialize fail (%d) status %d.\n",
ret, status);
return ret;
}
return 0;
}
static int psp_rap_terminate(struct psp_context *psp)
{
int ret;
if (!psp->rap_context.context.initialized)
return 0;
ret = psp_rap_unload(psp);
psp->rap_context.context.initialized = false;
/* free rap shared memory */
psp_ta_free_shared_buf(&psp->rap_context.context.mem_context);
return ret;
}
int psp_rap_invoke(struct psp_context *psp, uint32_t ta_cmd_id, enum ta_rap_status *status)
{
struct ta_rap_shared_memory *rap_cmd;
int ret = 0;
if (!psp->rap_context.context.initialized)
return 0;
if (ta_cmd_id != TA_CMD_RAP__INITIALIZE &&
ta_cmd_id != TA_CMD_RAP__VALIDATE_L0)
return -EINVAL;
mutex_lock(&psp->rap_context.mutex);
rap_cmd = (struct ta_rap_shared_memory *)
psp->rap_context.context.mem_context.shared_buf;
memset(rap_cmd, 0, sizeof(struct ta_rap_shared_memory));
rap_cmd->cmd_id = ta_cmd_id;
rap_cmd->validation_method_id = METHOD_A;
ret = psp_ta_invoke(psp, rap_cmd->cmd_id, psp->rap_context.context.session_id);
if (ret)
goto out_unlock;
if (status)
*status = rap_cmd->rap_status;
out_unlock:
mutex_unlock(&psp->rap_context.mutex);
return ret;
}
// RAP end
/* securedisplay start */
static int psp_securedisplay_init_shared_buf(struct psp_context *psp)
{
return psp_ta_init_shared_buf(
psp, &psp->securedisplay_context.context.mem_context,
PSP_SECUREDISPLAY_SHARED_MEM_SIZE);
}
static int psp_securedisplay_load(struct psp_context *psp)
{
int ret;
struct psp_gfx_cmd_resp *cmd = acquire_psp_cmd_buf(psp);
memset(psp->fw_pri_buf, 0, PSP_1_MEG);
memcpy(psp->fw_pri_buf, psp->securedisplay.start_addr, psp->securedisplay.size_bytes);
psp_prep_ta_load_cmd_buf(cmd,
psp->fw_pri_mc_addr,
psp->securedisplay.size_bytes,
psp->securedisplay_context.context.mem_context.shared_mc_addr,
PSP_SECUREDISPLAY_SHARED_MEM_SIZE);
ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr);
if (!ret) {
psp->securedisplay_context.context.initialized = true;
psp->securedisplay_context.context.session_id = cmd->resp.session_id;
mutex_init(&psp->securedisplay_context.mutex);
}
release_psp_cmd_buf(psp);
return ret;
}
static int psp_securedisplay_unload(struct psp_context *psp)
{
int ret;
struct psp_gfx_cmd_resp *cmd = acquire_psp_cmd_buf(psp);
psp_prep_ta_unload_cmd_buf(cmd, psp->securedisplay_context.context.session_id);
ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr);
release_psp_cmd_buf(psp);
return ret;
}
static int psp_securedisplay_initialize(struct psp_context *psp)
{
int ret;
struct securedisplay_cmd *securedisplay_cmd;
/*
* TODO: bypass the initialize in sriov for now
*/
if (amdgpu_sriov_vf(psp->adev))
return 0;
if (!psp->securedisplay.size_bytes ||
!psp->securedisplay.start_addr) {
dev_info(psp->adev->dev, "SECUREDISPLAY: securedisplay ta ucode is not available\n");
return 0;
}
if (!psp->securedisplay_context.context.initialized) {
ret = psp_securedisplay_init_shared_buf(psp);
if (ret)
return ret;
}
ret = psp_securedisplay_load(psp);
if (ret)
return ret;
psp_prep_securedisplay_cmd_buf(psp, &securedisplay_cmd,
TA_SECUREDISPLAY_COMMAND__QUERY_TA);
ret = psp_securedisplay_invoke(psp, TA_SECUREDISPLAY_COMMAND__QUERY_TA);
if (ret) {
psp_securedisplay_unload(psp);
psp_ta_free_shared_buf(&psp->securedisplay_context.context.mem_context);
psp->securedisplay_context.context.initialized = false;
dev_err(psp->adev->dev, "SECUREDISPLAY TA initialize fail.\n");
return -EINVAL;
}
if (securedisplay_cmd->status != TA_SECUREDISPLAY_STATUS__SUCCESS) {
psp_securedisplay_parse_resp_status(psp, securedisplay_cmd->status);
dev_err(psp->adev->dev, "SECUREDISPLAY: query securedisplay TA failed. ret 0x%x\n",
securedisplay_cmd->securedisplay_out_message.query_ta.query_cmd_ret);
}
return 0;
}
static int psp_securedisplay_terminate(struct psp_context *psp)
{
int ret;
/*
* TODO:bypass the terminate in sriov for now
*/
if (amdgpu_sriov_vf(psp->adev))
return 0;
if (!psp->securedisplay_context.context.initialized)
return 0;
ret = psp_securedisplay_unload(psp);
if (ret)
return ret;
psp->securedisplay_context.context.initialized = false;
/* free securedisplay shared memory */
psp_ta_free_shared_buf(&psp->securedisplay_context.context.mem_context);
return ret;
}
int psp_securedisplay_invoke(struct psp_context *psp, uint32_t ta_cmd_id)
{
int ret;
if (!psp->securedisplay_context.context.initialized)
return -EINVAL;
if (ta_cmd_id != TA_SECUREDISPLAY_COMMAND__QUERY_TA &&
ta_cmd_id != TA_SECUREDISPLAY_COMMAND__SEND_ROI_CRC)
return -EINVAL;
mutex_lock(&psp->securedisplay_context.mutex);
ret = psp_ta_invoke(psp, ta_cmd_id, psp->securedisplay_context.context.session_id);
mutex_unlock(&psp->securedisplay_context.mutex);
return ret;
}
/* SECUREDISPLAY end */
static int psp_hw_start(struct psp_context *psp)
{
struct amdgpu_device *adev = psp->adev;
int ret;
if (!amdgpu_sriov_vf(adev)) {
if ((is_psp_fw_valid(psp->kdb)) &&
(psp->funcs->bootloader_load_kdb != NULL)) {
ret = psp_bootloader_load_kdb(psp);
if (ret) {
DRM_ERROR("PSP load kdb failed!\n");
return ret;
}
}
if ((is_psp_fw_valid(psp->spl)) &&
(psp->funcs->bootloader_load_spl != NULL)) {
ret = psp_bootloader_load_spl(psp);
if (ret) {
DRM_ERROR("PSP load spl failed!\n");
return ret;
}
}
if ((is_psp_fw_valid(psp->sys)) &&
(psp->funcs->bootloader_load_sysdrv != NULL)) {
ret = psp_bootloader_load_sysdrv(psp);
if (ret) {
DRM_ERROR("PSP load sys drv failed!\n");
return ret;
}
}
if ((is_psp_fw_valid(psp->soc_drv)) &&
(psp->funcs->bootloader_load_soc_drv != NULL)) {
ret = psp_bootloader_load_soc_drv(psp);
if (ret) {
DRM_ERROR("PSP load soc drv failed!\n");
return ret;
}
}
if ((is_psp_fw_valid(psp->intf_drv)) &&
(psp->funcs->bootloader_load_intf_drv != NULL)) {
ret = psp_bootloader_load_intf_drv(psp);
if (ret) {
DRM_ERROR("PSP load intf drv failed!\n");
return ret;
}
}
if ((is_psp_fw_valid(psp->dbg_drv)) &&
(psp->funcs->bootloader_load_dbg_drv != NULL)) {
ret = psp_bootloader_load_dbg_drv(psp);
if (ret) {
DRM_ERROR("PSP load dbg drv failed!\n");
return ret;
}
}
if ((is_psp_fw_valid(psp->sos)) &&
(psp->funcs->bootloader_load_sos != NULL)) {
ret = psp_bootloader_load_sos(psp);
if (ret) {
DRM_ERROR("PSP load sos failed!\n");
return ret;
}
}
}
ret = psp_ring_create(psp, PSP_RING_TYPE__KM);
if (ret) {
DRM_ERROR("PSP create ring failed!\n");
return ret;
}
if (amdgpu_sriov_vf(adev) && amdgpu_in_reset(adev))
goto skip_pin_bo;
ret = psp_tmr_init(psp);
if (ret) {
DRM_ERROR("PSP tmr init failed!\n");
return ret;
}
skip_pin_bo:
/*
* For ASICs with DF Cstate management centralized
* to PMFW, TMR setup should be performed after PMFW
* loaded and before other non-psp firmware loaded.
*/
if (psp->pmfw_centralized_cstate_management) {
ret = psp_load_smu_fw(psp);
if (ret)
return ret;
}
ret = psp_tmr_load(psp);
if (ret) {
DRM_ERROR("PSP load tmr failed!\n");
return ret;
}
return 0;
}
static int psp_get_fw_type(struct amdgpu_firmware_info *ucode,
enum psp_gfx_fw_type *type)
{
switch (ucode->ucode_id) {
case AMDGPU_UCODE_ID_SDMA0:
*type = GFX_FW_TYPE_SDMA0;
break;
case AMDGPU_UCODE_ID_SDMA1:
*type = GFX_FW_TYPE_SDMA1;
break;
case AMDGPU_UCODE_ID_SDMA2:
*type = GFX_FW_TYPE_SDMA2;
break;
case AMDGPU_UCODE_ID_SDMA3:
*type = GFX_FW_TYPE_SDMA3;
break;
case AMDGPU_UCODE_ID_SDMA4:
*type = GFX_FW_TYPE_SDMA4;
break;
case AMDGPU_UCODE_ID_SDMA5:
*type = GFX_FW_TYPE_SDMA5;
break;
case AMDGPU_UCODE_ID_SDMA6:
*type = GFX_FW_TYPE_SDMA6;
break;
case AMDGPU_UCODE_ID_SDMA7:
*type = GFX_FW_TYPE_SDMA7;
break;
case AMDGPU_UCODE_ID_CP_MES:
*type = GFX_FW_TYPE_CP_MES;
break;
case AMDGPU_UCODE_ID_CP_MES_DATA:
*type = GFX_FW_TYPE_MES_STACK;
break;
case AMDGPU_UCODE_ID_CP_CE:
*type = GFX_FW_TYPE_CP_CE;
break;
case AMDGPU_UCODE_ID_CP_PFP:
*type = GFX_FW_TYPE_CP_PFP;
break;
case AMDGPU_UCODE_ID_CP_ME:
*type = GFX_FW_TYPE_CP_ME;
break;
case AMDGPU_UCODE_ID_CP_MEC1:
*type = GFX_FW_TYPE_CP_MEC;
break;
case AMDGPU_UCODE_ID_CP_MEC1_JT:
*type = GFX_FW_TYPE_CP_MEC_ME1;
break;
case AMDGPU_UCODE_ID_CP_MEC2:
*type = GFX_FW_TYPE_CP_MEC;
break;
case AMDGPU_UCODE_ID_CP_MEC2_JT:
*type = GFX_FW_TYPE_CP_MEC_ME2;
break;
case AMDGPU_UCODE_ID_RLC_G:
*type = GFX_FW_TYPE_RLC_G;
break;
case AMDGPU_UCODE_ID_RLC_RESTORE_LIST_CNTL:
*type = GFX_FW_TYPE_RLC_RESTORE_LIST_SRM_CNTL;
break;
case AMDGPU_UCODE_ID_RLC_RESTORE_LIST_GPM_MEM:
*type = GFX_FW_TYPE_RLC_RESTORE_LIST_GPM_MEM;
break;
case AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM:
*type = GFX_FW_TYPE_RLC_RESTORE_LIST_SRM_MEM;
break;
case AMDGPU_UCODE_ID_RLC_IRAM:
*type = GFX_FW_TYPE_RLC_IRAM;
break;
case AMDGPU_UCODE_ID_RLC_DRAM:
*type = GFX_FW_TYPE_RLC_DRAM_BOOT;
break;
case AMDGPU_UCODE_ID_SMC:
*type = GFX_FW_TYPE_SMU;
break;
case AMDGPU_UCODE_ID_UVD:
*type = GFX_FW_TYPE_UVD;
break;
case AMDGPU_UCODE_ID_UVD1:
*type = GFX_FW_TYPE_UVD1;
break;
case AMDGPU_UCODE_ID_VCE:
*type = GFX_FW_TYPE_VCE;
break;
case AMDGPU_UCODE_ID_VCN:
*type = GFX_FW_TYPE_VCN;
break;
case AMDGPU_UCODE_ID_VCN1:
*type = GFX_FW_TYPE_VCN1;
break;
case AMDGPU_UCODE_ID_DMCU_ERAM:
*type = GFX_FW_TYPE_DMCU_ERAM;
break;
case AMDGPU_UCODE_ID_DMCU_INTV:
*type = GFX_FW_TYPE_DMCU_ISR;
break;
case AMDGPU_UCODE_ID_VCN0_RAM:
*type = GFX_FW_TYPE_VCN0_RAM;
break;
case AMDGPU_UCODE_ID_VCN1_RAM:
*type = GFX_FW_TYPE_VCN1_RAM;
break;
case AMDGPU_UCODE_ID_DMCUB:
*type = GFX_FW_TYPE_DMUB;
break;
case AMDGPU_UCODE_ID_MAXIMUM:
default:
return -EINVAL;
}
return 0;
}
static void psp_print_fw_hdr(struct psp_context *psp,
struct amdgpu_firmware_info *ucode)
{
struct amdgpu_device *adev = psp->adev;
struct common_firmware_header *hdr;
switch (ucode->ucode_id) {
case AMDGPU_UCODE_ID_SDMA0:
case AMDGPU_UCODE_ID_SDMA1:
case AMDGPU_UCODE_ID_SDMA2:
case AMDGPU_UCODE_ID_SDMA3:
case AMDGPU_UCODE_ID_SDMA4:
case AMDGPU_UCODE_ID_SDMA5:
case AMDGPU_UCODE_ID_SDMA6:
case AMDGPU_UCODE_ID_SDMA7:
hdr = (struct common_firmware_header *)
adev->sdma.instance[ucode->ucode_id - AMDGPU_UCODE_ID_SDMA0].fw->data;
amdgpu_ucode_print_sdma_hdr(hdr);
break;
case AMDGPU_UCODE_ID_CP_CE:
hdr = (struct common_firmware_header *)adev->gfx.ce_fw->data;
amdgpu_ucode_print_gfx_hdr(hdr);
break;
case AMDGPU_UCODE_ID_CP_PFP:
hdr = (struct common_firmware_header *)adev->gfx.pfp_fw->data;
amdgpu_ucode_print_gfx_hdr(hdr);
break;
case AMDGPU_UCODE_ID_CP_ME:
hdr = (struct common_firmware_header *)adev->gfx.me_fw->data;
amdgpu_ucode_print_gfx_hdr(hdr);
break;
case AMDGPU_UCODE_ID_CP_MEC1:
hdr = (struct common_firmware_header *)adev->gfx.mec_fw->data;
amdgpu_ucode_print_gfx_hdr(hdr);
break;
case AMDGPU_UCODE_ID_RLC_G:
hdr = (struct common_firmware_header *)adev->gfx.rlc_fw->data;
amdgpu_ucode_print_rlc_hdr(hdr);
break;
case AMDGPU_UCODE_ID_SMC:
hdr = (struct common_firmware_header *)adev->pm.fw->data;
amdgpu_ucode_print_smc_hdr(hdr);
break;
default:
break;
}
}
static int psp_prep_load_ip_fw_cmd_buf(struct amdgpu_firmware_info *ucode,
struct psp_gfx_cmd_resp *cmd)
{
int ret;
uint64_t fw_mem_mc_addr = ucode->mc_addr;
cmd->cmd_id = GFX_CMD_ID_LOAD_IP_FW;
cmd->cmd.cmd_load_ip_fw.fw_phy_addr_lo = lower_32_bits(fw_mem_mc_addr);
cmd->cmd.cmd_load_ip_fw.fw_phy_addr_hi = upper_32_bits(fw_mem_mc_addr);
cmd->cmd.cmd_load_ip_fw.fw_size = ucode->ucode_size;
ret = psp_get_fw_type(ucode, &cmd->cmd.cmd_load_ip_fw.fw_type);
if (ret)
DRM_ERROR("Unknown firmware type\n");
return ret;
}
static int psp_execute_non_psp_fw_load(struct psp_context *psp,
struct amdgpu_firmware_info *ucode)
{
int ret = 0;
struct psp_gfx_cmd_resp *cmd = acquire_psp_cmd_buf(psp);
ret = psp_prep_load_ip_fw_cmd_buf(ucode, cmd);
if (!ret) {
ret = psp_cmd_submit_buf(psp, ucode, cmd,
psp->fence_buf_mc_addr);
}
release_psp_cmd_buf(psp);
return ret;
}
static int psp_load_smu_fw(struct psp_context *psp)
{
int ret;
struct amdgpu_device *adev = psp->adev;
struct amdgpu_firmware_info *ucode =
&adev->firmware.ucode[AMDGPU_UCODE_ID_SMC];
struct amdgpu_ras *ras = psp->ras_context.ras;
if (!ucode->fw || amdgpu_sriov_vf(psp->adev))
return 0;
if ((amdgpu_in_reset(adev) &&
ras && adev->ras_enabled &&
(adev->asic_type == CHIP_ARCTURUS ||
adev->asic_type == CHIP_VEGA20))) {
ret = amdgpu_dpm_set_mp1_state(adev, PP_MP1_STATE_UNLOAD);
if (ret) {
DRM_WARN("Failed to set MP1 state prepare for reload\n");
}
}
ret = psp_execute_non_psp_fw_load(psp, ucode);
if (ret)
DRM_ERROR("PSP load smu failed!\n");
return ret;
}
static bool fw_load_skip_check(struct psp_context *psp,
struct amdgpu_firmware_info *ucode)
{
if (!ucode->fw)
return true;
if (ucode->ucode_id == AMDGPU_UCODE_ID_SMC &&
(psp_smu_reload_quirk(psp) ||
psp->autoload_supported ||
psp->pmfw_centralized_cstate_management))
return true;
if (amdgpu_sriov_vf(psp->adev) &&
(ucode->ucode_id == AMDGPU_UCODE_ID_SDMA0
|| ucode->ucode_id == AMDGPU_UCODE_ID_SDMA1
|| ucode->ucode_id == AMDGPU_UCODE_ID_SDMA2
|| ucode->ucode_id == AMDGPU_UCODE_ID_SDMA3
|| ucode->ucode_id == AMDGPU_UCODE_ID_SDMA4
|| ucode->ucode_id == AMDGPU_UCODE_ID_SDMA5
|| ucode->ucode_id == AMDGPU_UCODE_ID_SDMA6
|| ucode->ucode_id == AMDGPU_UCODE_ID_SDMA7
|| ucode->ucode_id == AMDGPU_UCODE_ID_RLC_G
|| ucode->ucode_id == AMDGPU_UCODE_ID_RLC_RESTORE_LIST_CNTL
|| ucode->ucode_id == AMDGPU_UCODE_ID_RLC_RESTORE_LIST_GPM_MEM
|| ucode->ucode_id == AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM
|| ucode->ucode_id == AMDGPU_UCODE_ID_SMC))
/*skip ucode loading in SRIOV VF */
return true;
if (psp->autoload_supported &&
(ucode->ucode_id == AMDGPU_UCODE_ID_CP_MEC1_JT ||
ucode->ucode_id == AMDGPU_UCODE_ID_CP_MEC2_JT))
/* skip mec JT when autoload is enabled */
return true;
return false;
}
int psp_load_fw_list(struct psp_context *psp,
struct amdgpu_firmware_info **ucode_list, int ucode_count)
{
int ret = 0, i;
struct amdgpu_firmware_info *ucode;
for (i = 0; i < ucode_count; ++i) {
ucode = ucode_list[i];
psp_print_fw_hdr(psp, ucode);
ret = psp_execute_non_psp_fw_load(psp, ucode);
if (ret)
return ret;
}
return ret;
}
static int psp_load_non_psp_fw(struct psp_context *psp)
{
int i, ret;
struct amdgpu_firmware_info *ucode;
struct amdgpu_device *adev = psp->adev;
if (psp->autoload_supported &&
!psp->pmfw_centralized_cstate_management) {
ret = psp_load_smu_fw(psp);
if (ret)
return ret;
}
for (i = 0; i < adev->firmware.max_ucodes; i++) {
ucode = &adev->firmware.ucode[i];
if (ucode->ucode_id == AMDGPU_UCODE_ID_SMC &&
!fw_load_skip_check(psp, ucode)) {
ret = psp_load_smu_fw(psp);
if (ret)
return ret;
continue;
}
if (fw_load_skip_check(psp, ucode))
continue;
if (psp->autoload_supported &&
(adev->asic_type >= CHIP_SIENNA_CICHLID &&
adev->asic_type <= CHIP_DIMGREY_CAVEFISH) &&
(ucode->ucode_id == AMDGPU_UCODE_ID_SDMA1 ||
ucode->ucode_id == AMDGPU_UCODE_ID_SDMA2 ||
ucode->ucode_id == AMDGPU_UCODE_ID_SDMA3))
/* PSP only receive one SDMA fw for sienna_cichlid,
* as all four sdma fw are same */
continue;
psp_print_fw_hdr(psp, ucode);
ret = psp_execute_non_psp_fw_load(psp, ucode);
if (ret)
return ret;
/* Start rlc autoload after psp recieved all the gfx firmware */
if (psp->autoload_supported && ucode->ucode_id == (amdgpu_sriov_vf(adev) ?
AMDGPU_UCODE_ID_CP_MEC2 : AMDGPU_UCODE_ID_RLC_G)) {
ret = psp_rlc_autoload_start(psp);
if (ret) {
DRM_ERROR("Failed to start rlc autoload\n");
return ret;
}
}
}
return 0;
}
static int psp_load_fw(struct amdgpu_device *adev)
{
int ret;
struct psp_context *psp = &adev->psp;
if (amdgpu_sriov_vf(adev) && amdgpu_in_reset(adev)) {
psp_ring_stop(psp, PSP_RING_TYPE__KM); /* should not destroy ring, only stop */
goto skip_memalloc;
}
if (amdgpu_sriov_vf(adev)) {
ret = amdgpu_bo_create_kernel(adev, PSP_1_MEG, PSP_1_MEG,
AMDGPU_GEM_DOMAIN_VRAM,
&psp->fw_pri_bo,
&psp->fw_pri_mc_addr,
&psp->fw_pri_buf);
} else {
ret = amdgpu_bo_create_kernel(adev, PSP_1_MEG, PSP_1_MEG,
AMDGPU_GEM_DOMAIN_GTT,
&psp->fw_pri_bo,
&psp->fw_pri_mc_addr,
&psp->fw_pri_buf);
}
if (ret)
goto failed;
ret = amdgpu_bo_create_kernel(adev, PSP_FENCE_BUFFER_SIZE, PAGE_SIZE,
AMDGPU_GEM_DOMAIN_VRAM,
&psp->fence_buf_bo,
&psp->fence_buf_mc_addr,
&psp->fence_buf);
if (ret)
goto failed;
ret = amdgpu_bo_create_kernel(adev, PSP_CMD_BUFFER_SIZE, PAGE_SIZE,
AMDGPU_GEM_DOMAIN_VRAM,
&psp->cmd_buf_bo, &psp->cmd_buf_mc_addr,
(void **)&psp->cmd_buf_mem);
if (ret)
goto failed;
memset(psp->fence_buf, 0, PSP_FENCE_BUFFER_SIZE);
ret = psp_ring_init(psp, PSP_RING_TYPE__KM);
if (ret) {
DRM_ERROR("PSP ring init failed!\n");
goto failed;
}
skip_memalloc:
ret = psp_hw_start(psp);
if (ret)
goto failed;
ret = psp_load_non_psp_fw(psp);
if (ret)
goto failed;
ret = psp_asd_load(psp);
if (ret) {
DRM_ERROR("PSP load asd failed!\n");
return ret;
}
ret = psp_rl_load(adev);
if (ret) {
DRM_ERROR("PSP load RL failed!\n");
return ret;
}
if (psp->ta_fw) {
ret = psp_ras_initialize(psp);
if (ret)
dev_err(psp->adev->dev,
"RAS: Failed to initialize RAS\n");
ret = psp_hdcp_initialize(psp);
if (ret)
dev_err(psp->adev->dev,
"HDCP: Failed to initialize HDCP\n");
ret = psp_dtm_initialize(psp);
if (ret)
dev_err(psp->adev->dev,
"DTM: Failed to initialize DTM\n");
ret = psp_rap_initialize(psp);
if (ret)
dev_err(psp->adev->dev,
"RAP: Failed to initialize RAP\n");
ret = psp_securedisplay_initialize(psp);
if (ret)
dev_err(psp->adev->dev,
"SECUREDISPLAY: Failed to initialize SECUREDISPLAY\n");
}
return 0;
failed:
/*
* all cleanup jobs (xgmi terminate, ras terminate,
* ring destroy, cmd/fence/fw buffers destory,
* psp->cmd destory) are delayed to psp_hw_fini
*/
return ret;
}
static int psp_hw_init(void *handle)
{
int ret;
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
mutex_lock(&adev->firmware.mutex);
/*
* This sequence is just used on hw_init only once, no need on
* resume.
*/
ret = amdgpu_ucode_init_bo(adev);
if (ret)
goto failed;
ret = psp_load_fw(adev);
if (ret) {
DRM_ERROR("PSP firmware loading failed\n");
goto failed;
}
mutex_unlock(&adev->firmware.mutex);
return 0;
failed:
adev->firmware.load_type = AMDGPU_FW_LOAD_DIRECT;
mutex_unlock(&adev->firmware.mutex);
return -EINVAL;
}
static int psp_hw_fini(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
struct psp_context *psp = &adev->psp;
if (psp->ta_fw) {
psp_ras_terminate(psp);
psp_securedisplay_terminate(psp);
psp_rap_terminate(psp);
psp_dtm_terminate(psp);
psp_hdcp_terminate(psp);
}
psp_asd_unload(psp);
psp_tmr_terminate(psp);
psp_ring_destroy(psp, PSP_RING_TYPE__KM);
amdgpu_bo_free_kernel(&psp->fw_pri_bo,
&psp->fw_pri_mc_addr, &psp->fw_pri_buf);
amdgpu_bo_free_kernel(&psp->fence_buf_bo,
&psp->fence_buf_mc_addr, &psp->fence_buf);
amdgpu_bo_free_kernel(&psp->cmd_buf_bo, &psp->cmd_buf_mc_addr,
(void **)&psp->cmd_buf_mem);
return 0;
}
static int psp_suspend(void *handle)
{
int ret;
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
struct psp_context *psp = &adev->psp;
if (adev->gmc.xgmi.num_physical_nodes > 1 &&
psp->xgmi_context.context.initialized) {
ret = psp_xgmi_terminate(psp);
if (ret) {
DRM_ERROR("Failed to terminate xgmi ta\n");
return ret;
}
}
if (psp->ta_fw) {
ret = psp_ras_terminate(psp);
if (ret) {
DRM_ERROR("Failed to terminate ras ta\n");
return ret;
}
ret = psp_hdcp_terminate(psp);
if (ret) {
DRM_ERROR("Failed to terminate hdcp ta\n");
return ret;
}
ret = psp_dtm_terminate(psp);
if (ret) {
DRM_ERROR("Failed to terminate dtm ta\n");
return ret;
}
ret = psp_rap_terminate(psp);
if (ret) {
DRM_ERROR("Failed to terminate rap ta\n");
return ret;
}
ret = psp_securedisplay_terminate(psp);
if (ret) {
DRM_ERROR("Failed to terminate securedisplay ta\n");
return ret;
}
}
ret = psp_asd_unload(psp);
if (ret) {
DRM_ERROR("Failed to unload asd\n");
return ret;
}
ret = psp_tmr_terminate(psp);
if (ret) {
DRM_ERROR("Failed to terminate tmr\n");
return ret;
}
ret = psp_ring_stop(psp, PSP_RING_TYPE__KM);
if (ret) {
DRM_ERROR("PSP ring stop failed\n");
return ret;
}
return 0;
}
static int psp_resume(void *handle)
{
int ret;
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
struct psp_context *psp = &adev->psp;
DRM_INFO("PSP is resuming...\n");
if (psp->mem_train_ctx.enable_mem_training) {
ret = psp_mem_training(psp, PSP_MEM_TRAIN_RESUME);
if (ret) {
DRM_ERROR("Failed to process memory training!\n");
return ret;
}
}
mutex_lock(&adev->firmware.mutex);
ret = psp_hw_start(psp);
if (ret)
goto failed;
ret = psp_load_non_psp_fw(psp);
if (ret)
goto failed;
ret = psp_asd_load(psp);
if (ret) {
DRM_ERROR("PSP load asd failed!\n");
goto failed;
}
if (adev->gmc.xgmi.num_physical_nodes > 1) {
ret = psp_xgmi_initialize(psp, false, true);
/* Warning the XGMI seesion initialize failure
* Instead of stop driver initialization
*/
if (ret)
dev_err(psp->adev->dev,
"XGMI: Failed to initialize XGMI session\n");
}
if (psp->ta_fw) {
ret = psp_ras_initialize(psp);
if (ret)
dev_err(psp->adev->dev,
"RAS: Failed to initialize RAS\n");
ret = psp_hdcp_initialize(psp);
if (ret)
dev_err(psp->adev->dev,
"HDCP: Failed to initialize HDCP\n");
ret = psp_dtm_initialize(psp);
if (ret)
dev_err(psp->adev->dev,
"DTM: Failed to initialize DTM\n");
ret = psp_rap_initialize(psp);
if (ret)
dev_err(psp->adev->dev,
"RAP: Failed to initialize RAP\n");
ret = psp_securedisplay_initialize(psp);
if (ret)
dev_err(psp->adev->dev,
"SECUREDISPLAY: Failed to initialize SECUREDISPLAY\n");
}
mutex_unlock(&adev->firmware.mutex);
return 0;
failed:
DRM_ERROR("PSP resume failed\n");
mutex_unlock(&adev->firmware.mutex);
return ret;
}
int psp_gpu_reset(struct amdgpu_device *adev)
{
int ret;
if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP)
return 0;
mutex_lock(&adev->psp.mutex);
ret = psp_mode1_reset(&adev->psp);
mutex_unlock(&adev->psp.mutex);
return ret;
}
int psp_rlc_autoload_start(struct psp_context *psp)
{
int ret;
struct psp_gfx_cmd_resp *cmd = acquire_psp_cmd_buf(psp);
cmd->cmd_id = GFX_CMD_ID_AUTOLOAD_RLC;
ret = psp_cmd_submit_buf(psp, NULL, cmd,
psp->fence_buf_mc_addr);
release_psp_cmd_buf(psp);
return ret;
}
int psp_update_vcn_sram(struct amdgpu_device *adev, int inst_idx,
uint64_t cmd_gpu_addr, int cmd_size)
{
struct amdgpu_firmware_info ucode = {0};
ucode.ucode_id = inst_idx ? AMDGPU_UCODE_ID_VCN1_RAM :
AMDGPU_UCODE_ID_VCN0_RAM;
ucode.mc_addr = cmd_gpu_addr;
ucode.ucode_size = cmd_size;
return psp_execute_non_psp_fw_load(&adev->psp, &ucode);
}
int psp_ring_cmd_submit(struct psp_context *psp,
uint64_t cmd_buf_mc_addr,
uint64_t fence_mc_addr,
int index)
{
unsigned int psp_write_ptr_reg = 0;
struct psp_gfx_rb_frame *write_frame;
struct psp_ring *ring = &psp->km_ring;
struct psp_gfx_rb_frame *ring_buffer_start = ring->ring_mem;
struct psp_gfx_rb_frame *ring_buffer_end = ring_buffer_start +
ring->ring_size / sizeof(struct psp_gfx_rb_frame) - 1;
struct amdgpu_device *adev = psp->adev;
uint32_t ring_size_dw = ring->ring_size / 4;
uint32_t rb_frame_size_dw = sizeof(struct psp_gfx_rb_frame) / 4;
/* KM (GPCOM) prepare write pointer */
psp_write_ptr_reg = psp_ring_get_wptr(psp);
/* Update KM RB frame pointer to new frame */
/* write_frame ptr increments by size of rb_frame in bytes */
/* psp_write_ptr_reg increments by size of rb_frame in DWORDs */
if ((psp_write_ptr_reg % ring_size_dw) == 0)
write_frame = ring_buffer_start;
else
write_frame = ring_buffer_start + (psp_write_ptr_reg / rb_frame_size_dw);
/* Check invalid write_frame ptr address */
if ((write_frame < ring_buffer_start) || (ring_buffer_end < write_frame)) {
DRM_ERROR("ring_buffer_start = %p; ring_buffer_end = %p; write_frame = %p\n",
ring_buffer_start, ring_buffer_end, write_frame);
DRM_ERROR("write_frame is pointing to address out of bounds\n");
return -EINVAL;
}
/* Initialize KM RB frame */
memset(write_frame, 0, sizeof(struct psp_gfx_rb_frame));
/* Update KM RB frame */
write_frame->cmd_buf_addr_hi = upper_32_bits(cmd_buf_mc_addr);
write_frame->cmd_buf_addr_lo = lower_32_bits(cmd_buf_mc_addr);
write_frame->fence_addr_hi = upper_32_bits(fence_mc_addr);
write_frame->fence_addr_lo = lower_32_bits(fence_mc_addr);
write_frame->fence_value = index;
amdgpu_device_flush_hdp(adev, NULL);
/* Update the write Pointer in DWORDs */
psp_write_ptr_reg = (psp_write_ptr_reg + rb_frame_size_dw) % ring_size_dw;
psp_ring_set_wptr(psp, psp_write_ptr_reg);
return 0;
}
int psp_init_asd_microcode(struct psp_context *psp,
const char *chip_name)
{
struct amdgpu_device *adev = psp->adev;
char fw_name[PSP_FW_NAME_LEN];
const struct psp_firmware_header_v1_0 *asd_hdr;
int err = 0;
if (!chip_name) {
dev_err(adev->dev, "invalid chip name for asd microcode\n");
return -EINVAL;
}
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_asd.bin", chip_name);
err = request_firmware(&adev->psp.asd_fw, fw_name, adev->dev);
if (err)
goto out;
err = amdgpu_ucode_validate(adev->psp.asd_fw);
if (err)
goto out;
asd_hdr = (const struct psp_firmware_header_v1_0 *)adev->psp.asd_fw->data;
adev->psp.asd.fw_version = le32_to_cpu(asd_hdr->header.ucode_version);
adev->psp.asd.feature_version = le32_to_cpu(asd_hdr->sos.fw_version);
adev->psp.asd.size_bytes = le32_to_cpu(asd_hdr->header.ucode_size_bytes);
adev->psp.asd.start_addr = (uint8_t *)asd_hdr +
le32_to_cpu(asd_hdr->header.ucode_array_offset_bytes);
return 0;
out:
dev_err(adev->dev, "fail to initialize asd microcode\n");
release_firmware(adev->psp.asd_fw);
adev->psp.asd_fw = NULL;
return err;
}
int psp_init_toc_microcode(struct psp_context *psp,
const char *chip_name)
{
struct amdgpu_device *adev = psp->adev;
char fw_name[PSP_FW_NAME_LEN];
const struct psp_firmware_header_v1_0 *toc_hdr;
int err = 0;
if (!chip_name) {
dev_err(adev->dev, "invalid chip name for toc microcode\n");
return -EINVAL;
}
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_toc.bin", chip_name);
err = request_firmware(&adev->psp.toc_fw, fw_name, adev->dev);
if (err)
goto out;
err = amdgpu_ucode_validate(adev->psp.toc_fw);
if (err)
goto out;
toc_hdr = (const struct psp_firmware_header_v1_0 *)adev->psp.toc_fw->data;
adev->psp.toc.fw_version = le32_to_cpu(toc_hdr->header.ucode_version);
adev->psp.toc.feature_version = le32_to_cpu(toc_hdr->sos.fw_version);
adev->psp.toc.size_bytes = le32_to_cpu(toc_hdr->header.ucode_size_bytes);
adev->psp.toc.start_addr = (uint8_t *)toc_hdr +
le32_to_cpu(toc_hdr->header.ucode_array_offset_bytes);
return 0;
out:
dev_err(adev->dev, "fail to request/validate toc microcode\n");
release_firmware(adev->psp.toc_fw);
adev->psp.toc_fw = NULL;
return err;
}
static int parse_sos_bin_descriptor(struct psp_context *psp,
const struct psp_fw_bin_desc *desc,
const struct psp_firmware_header_v2_0 *sos_hdr)
{
uint8_t *ucode_start_addr = NULL;
if (!psp || !desc || !sos_hdr)
return -EINVAL;
ucode_start_addr = (uint8_t *)sos_hdr +
le32_to_cpu(desc->offset_bytes) +
le32_to_cpu(sos_hdr->header.ucode_array_offset_bytes);
switch (desc->fw_type) {
case PSP_FW_TYPE_PSP_SOS:
psp->sos.fw_version = le32_to_cpu(desc->fw_version);
psp->sos.feature_version = le32_to_cpu(desc->fw_version);
psp->sos.size_bytes = le32_to_cpu(desc->size_bytes);
psp->sos.start_addr = ucode_start_addr;
break;
case PSP_FW_TYPE_PSP_SYS_DRV:
psp->sys.fw_version = le32_to_cpu(desc->fw_version);
psp->sys.feature_version = le32_to_cpu(desc->fw_version);
psp->sys.size_bytes = le32_to_cpu(desc->size_bytes);
psp->sys.start_addr = ucode_start_addr;
break;
case PSP_FW_TYPE_PSP_KDB:
psp->kdb.fw_version = le32_to_cpu(desc->fw_version);
psp->kdb.feature_version = le32_to_cpu(desc->fw_version);
psp->kdb.size_bytes = le32_to_cpu(desc->size_bytes);
psp->kdb.start_addr = ucode_start_addr;
break;
case PSP_FW_TYPE_PSP_TOC:
psp->toc.fw_version = le32_to_cpu(desc->fw_version);
psp->toc.feature_version = le32_to_cpu(desc->fw_version);
psp->toc.size_bytes = le32_to_cpu(desc->size_bytes);
psp->toc.start_addr = ucode_start_addr;
break;
case PSP_FW_TYPE_PSP_SPL:
psp->spl.fw_version = le32_to_cpu(desc->fw_version);
psp->spl.feature_version = le32_to_cpu(desc->fw_version);
psp->spl.size_bytes = le32_to_cpu(desc->size_bytes);
psp->spl.start_addr = ucode_start_addr;
break;
case PSP_FW_TYPE_PSP_RL:
psp->rl.fw_version = le32_to_cpu(desc->fw_version);
psp->rl.feature_version = le32_to_cpu(desc->fw_version);
psp->rl.size_bytes = le32_to_cpu(desc->size_bytes);
psp->rl.start_addr = ucode_start_addr;
break;
case PSP_FW_TYPE_PSP_SOC_DRV:
psp->soc_drv.fw_version = le32_to_cpu(desc->fw_version);
psp->soc_drv.feature_version = le32_to_cpu(desc->fw_version);
psp->soc_drv.size_bytes = le32_to_cpu(desc->size_bytes);
psp->soc_drv.start_addr = ucode_start_addr;
break;
case PSP_FW_TYPE_PSP_INTF_DRV:
psp->intf_drv.fw_version = le32_to_cpu(desc->fw_version);
psp->intf_drv.feature_version = le32_to_cpu(desc->fw_version);
psp->intf_drv.size_bytes = le32_to_cpu(desc->size_bytes);
psp->intf_drv.start_addr = ucode_start_addr;
break;
case PSP_FW_TYPE_PSP_DBG_DRV:
psp->dbg_drv.fw_version = le32_to_cpu(desc->fw_version);
psp->dbg_drv.feature_version = le32_to_cpu(desc->fw_version);
psp->dbg_drv.size_bytes = le32_to_cpu(desc->size_bytes);
psp->dbg_drv.start_addr = ucode_start_addr;
break;
default:
dev_warn(psp->adev->dev, "Unsupported PSP FW type: %d\n", desc->fw_type);
break;
}
return 0;
}
static int psp_init_sos_base_fw(struct amdgpu_device *adev)
{
const struct psp_firmware_header_v1_0 *sos_hdr;
const struct psp_firmware_header_v1_3 *sos_hdr_v1_3;
uint8_t *ucode_array_start_addr;
sos_hdr = (const struct psp_firmware_header_v1_0 *)adev->psp.sos_fw->data;
ucode_array_start_addr = (uint8_t *)sos_hdr +
le32_to_cpu(sos_hdr->header.ucode_array_offset_bytes);
if (adev->gmc.xgmi.connected_to_cpu || (adev->asic_type != CHIP_ALDEBARAN)) {
adev->psp.sos.fw_version = le32_to_cpu(sos_hdr->header.ucode_version);
adev->psp.sos.feature_version = le32_to_cpu(sos_hdr->sos.fw_version);
adev->psp.sys.size_bytes = le32_to_cpu(sos_hdr->sos.offset_bytes);
adev->psp.sys.start_addr = ucode_array_start_addr;
adev->psp.sos.size_bytes = le32_to_cpu(sos_hdr->sos.size_bytes);
adev->psp.sos.start_addr = ucode_array_start_addr +
le32_to_cpu(sos_hdr->sos.offset_bytes);
adev->psp.xgmi_context.supports_extended_data = false;
} else {
/* Load alternate PSP SOS FW */
sos_hdr_v1_3 = (const struct psp_firmware_header_v1_3 *)adev->psp.sos_fw->data;
adev->psp.sos.fw_version = le32_to_cpu(sos_hdr_v1_3->sos_aux.fw_version);
adev->psp.sos.feature_version = le32_to_cpu(sos_hdr_v1_3->sos_aux.fw_version);
adev->psp.sys.size_bytes = le32_to_cpu(sos_hdr_v1_3->sys_drv_aux.size_bytes);
adev->psp.sys.start_addr = ucode_array_start_addr +
le32_to_cpu(sos_hdr_v1_3->sys_drv_aux.offset_bytes);
adev->psp.sos.size_bytes = le32_to_cpu(sos_hdr_v1_3->sos_aux.size_bytes);
adev->psp.sos.start_addr = ucode_array_start_addr +
le32_to_cpu(sos_hdr_v1_3->sos_aux.offset_bytes);
adev->psp.xgmi_context.supports_extended_data = true;
}
if ((adev->psp.sys.size_bytes == 0) || (adev->psp.sos.size_bytes == 0)) {
dev_warn(adev->dev, "PSP SOS FW not available");
return -EINVAL;
}
return 0;
}
int psp_init_sos_microcode(struct psp_context *psp,
const char *chip_name)
{
struct amdgpu_device *adev = psp->adev;
char fw_name[PSP_FW_NAME_LEN];
const struct psp_firmware_header_v1_0 *sos_hdr;
const struct psp_firmware_header_v1_1 *sos_hdr_v1_1;
const struct psp_firmware_header_v1_2 *sos_hdr_v1_2;
const struct psp_firmware_header_v1_3 *sos_hdr_v1_3;
const struct psp_firmware_header_v2_0 *sos_hdr_v2_0;
int err = 0;
uint8_t *ucode_array_start_addr;
int fw_index = 0;
if (!chip_name) {
dev_err(adev->dev, "invalid chip name for sos microcode\n");
return -EINVAL;
}
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sos.bin", chip_name);
err = request_firmware(&adev->psp.sos_fw, fw_name, adev->dev);
if (err)
goto out;
err = amdgpu_ucode_validate(adev->psp.sos_fw);
if (err)
goto out;
sos_hdr = (const struct psp_firmware_header_v1_0 *)adev->psp.sos_fw->data;
ucode_array_start_addr = (uint8_t *)sos_hdr +
le32_to_cpu(sos_hdr->header.ucode_array_offset_bytes);
amdgpu_ucode_print_psp_hdr(&sos_hdr->header);
switch (sos_hdr->header.header_version_major) {
case 1:
err = psp_init_sos_base_fw(adev);
if (err)
goto out;
if (sos_hdr->header.header_version_minor == 1) {
sos_hdr_v1_1 = (const struct psp_firmware_header_v1_1 *)adev->psp.sos_fw->data;
adev->psp.toc.size_bytes = le32_to_cpu(sos_hdr_v1_1->toc.size_bytes);
adev->psp.toc.start_addr = (uint8_t *)adev->psp.sys.start_addr +
le32_to_cpu(sos_hdr_v1_1->toc.offset_bytes);
adev->psp.kdb.size_bytes = le32_to_cpu(sos_hdr_v1_1->kdb.size_bytes);
adev->psp.kdb.start_addr = (uint8_t *)adev->psp.sys.start_addr +
le32_to_cpu(sos_hdr_v1_1->kdb.offset_bytes);
}
if (sos_hdr->header.header_version_minor == 2) {
sos_hdr_v1_2 = (const struct psp_firmware_header_v1_2 *)adev->psp.sos_fw->data;
adev->psp.kdb.size_bytes = le32_to_cpu(sos_hdr_v1_2->kdb.size_bytes);
adev->psp.kdb.start_addr = (uint8_t *)adev->psp.sys.start_addr +
le32_to_cpu(sos_hdr_v1_2->kdb.offset_bytes);
}
if (sos_hdr->header.header_version_minor == 3) {
sos_hdr_v1_3 = (const struct psp_firmware_header_v1_3 *)adev->psp.sos_fw->data;
adev->psp.toc.size_bytes = le32_to_cpu(sos_hdr_v1_3->v1_1.toc.size_bytes);
adev->psp.toc.start_addr = ucode_array_start_addr +
le32_to_cpu(sos_hdr_v1_3->v1_1.toc.offset_bytes);
adev->psp.kdb.size_bytes = le32_to_cpu(sos_hdr_v1_3->v1_1.kdb.size_bytes);
adev->psp.kdb.start_addr = ucode_array_start_addr +
le32_to_cpu(sos_hdr_v1_3->v1_1.kdb.offset_bytes);
adev->psp.spl.size_bytes = le32_to_cpu(sos_hdr_v1_3->spl.size_bytes);
adev->psp.spl.start_addr = ucode_array_start_addr +
le32_to_cpu(sos_hdr_v1_3->spl.offset_bytes);
adev->psp.rl.size_bytes = le32_to_cpu(sos_hdr_v1_3->rl.size_bytes);
adev->psp.rl.start_addr = ucode_array_start_addr +
le32_to_cpu(sos_hdr_v1_3->rl.offset_bytes);
}
break;
case 2:
sos_hdr_v2_0 = (const struct psp_firmware_header_v2_0 *)adev->psp.sos_fw->data;
if (le32_to_cpu(sos_hdr_v2_0->psp_fw_bin_count) >= UCODE_MAX_PSP_PACKAGING) {
dev_err(adev->dev, "packed SOS count exceeds maximum limit\n");
err = -EINVAL;
goto out;
}
for (fw_index = 0; fw_index < le32_to_cpu(sos_hdr_v2_0->psp_fw_bin_count); fw_index++) {
err = parse_sos_bin_descriptor(psp,
&sos_hdr_v2_0->psp_fw_bin[fw_index],
sos_hdr_v2_0);
if (err)
goto out;
}
break;
default:
dev_err(adev->dev,
"unsupported psp sos firmware\n");
err = -EINVAL;
goto out;
}
return 0;
out:
dev_err(adev->dev,
"failed to init sos firmware\n");
release_firmware(adev->psp.sos_fw);
adev->psp.sos_fw = NULL;
return err;
}
static int parse_ta_bin_descriptor(struct psp_context *psp,
const struct psp_fw_bin_desc *desc,
const struct ta_firmware_header_v2_0 *ta_hdr)
{
uint8_t *ucode_start_addr = NULL;
if (!psp || !desc || !ta_hdr)
return -EINVAL;
ucode_start_addr = (uint8_t *)ta_hdr +
le32_to_cpu(desc->offset_bytes) +
le32_to_cpu(ta_hdr->header.ucode_array_offset_bytes);
switch (desc->fw_type) {
case TA_FW_TYPE_PSP_ASD:
psp->asd.fw_version = le32_to_cpu(desc->fw_version);
psp->asd.feature_version = le32_to_cpu(desc->fw_version);
psp->asd.size_bytes = le32_to_cpu(desc->size_bytes);
psp->asd.start_addr = ucode_start_addr;
break;
case TA_FW_TYPE_PSP_XGMI:
psp->xgmi.feature_version = le32_to_cpu(desc->fw_version);
psp->xgmi.size_bytes = le32_to_cpu(desc->size_bytes);
psp->xgmi.start_addr = ucode_start_addr;
break;
case TA_FW_TYPE_PSP_RAS:
psp->ras.feature_version = le32_to_cpu(desc->fw_version);
psp->ras.size_bytes = le32_to_cpu(desc->size_bytes);
psp->ras.start_addr = ucode_start_addr;
break;
case TA_FW_TYPE_PSP_HDCP:
psp->hdcp.feature_version = le32_to_cpu(desc->fw_version);
psp->hdcp.size_bytes = le32_to_cpu(desc->size_bytes);
psp->hdcp.start_addr = ucode_start_addr;
break;
case TA_FW_TYPE_PSP_DTM:
psp->dtm.feature_version = le32_to_cpu(desc->fw_version);
psp->dtm.size_bytes = le32_to_cpu(desc->size_bytes);
psp->dtm.start_addr = ucode_start_addr;
break;
case TA_FW_TYPE_PSP_RAP:
psp->rap.feature_version = le32_to_cpu(desc->fw_version);
psp->rap.size_bytes = le32_to_cpu(desc->size_bytes);
psp->rap.start_addr = ucode_start_addr;
break;
case TA_FW_TYPE_PSP_SECUREDISPLAY:
psp->securedisplay.feature_version = le32_to_cpu(desc->fw_version);
psp->securedisplay.size_bytes = le32_to_cpu(desc->size_bytes);
psp->securedisplay.start_addr = ucode_start_addr;
break;
default:
dev_warn(psp->adev->dev, "Unsupported TA type: %d\n", desc->fw_type);
break;
}
return 0;
}
int psp_init_ta_microcode(struct psp_context *psp,
const char *chip_name)
{
struct amdgpu_device *adev = psp->adev;
char fw_name[PSP_FW_NAME_LEN];
const struct ta_firmware_header_v2_0 *ta_hdr;
int err = 0;
int ta_index = 0;
if (!chip_name) {
dev_err(adev->dev, "invalid chip name for ta microcode\n");
return -EINVAL;
}
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ta.bin", chip_name);
err = request_firmware(&adev->psp.ta_fw, fw_name, adev->dev);
if (err)
goto out;
err = amdgpu_ucode_validate(adev->psp.ta_fw);
if (err)
goto out;
ta_hdr = (const struct ta_firmware_header_v2_0 *)adev->psp.ta_fw->data;
if (le16_to_cpu(ta_hdr->header.header_version_major) != 2) {
dev_err(adev->dev, "unsupported TA header version\n");
err = -EINVAL;
goto out;
}
if (le32_to_cpu(ta_hdr->ta_fw_bin_count) >= UCODE_MAX_PSP_PACKAGING) {
dev_err(adev->dev, "packed TA count exceeds maximum limit\n");
err = -EINVAL;
goto out;
}
for (ta_index = 0; ta_index < le32_to_cpu(ta_hdr->ta_fw_bin_count); ta_index++) {
err = parse_ta_bin_descriptor(psp,
&ta_hdr->ta_fw_bin[ta_index],
ta_hdr);
if (err)
goto out;
}
return 0;
out:
dev_err(adev->dev, "fail to initialize ta microcode\n");
release_firmware(adev->psp.ta_fw);
adev->psp.ta_fw = NULL;
return err;
}
static int psp_set_clockgating_state(void *handle,
enum amd_clockgating_state state)
{
return 0;
}
static int psp_set_powergating_state(void *handle,
enum amd_powergating_state state)
{
return 0;
}
static ssize_t psp_usbc_pd_fw_sysfs_read(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct drm_device *ddev = dev_get_drvdata(dev);
struct amdgpu_device *adev = drm_to_adev(ddev);
uint32_t fw_ver;
int ret;
if (!adev->ip_blocks[AMD_IP_BLOCK_TYPE_PSP].status.late_initialized) {
DRM_INFO("PSP block is not ready yet.");
return -EBUSY;
}
mutex_lock(&adev->psp.mutex);
ret = psp_read_usbc_pd_fw(&adev->psp, &fw_ver);
mutex_unlock(&adev->psp.mutex);
if (ret) {
DRM_ERROR("Failed to read USBC PD FW, err = %d", ret);
return ret;
}
return sysfs_emit(buf, "%x\n", fw_ver);
}
static ssize_t psp_usbc_pd_fw_sysfs_write(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t count)
{
struct drm_device *ddev = dev_get_drvdata(dev);
struct amdgpu_device *adev = drm_to_adev(ddev);
int ret, idx;
char fw_name[100];
const struct firmware *usbc_pd_fw;
struct amdgpu_bo *fw_buf_bo = NULL;
uint64_t fw_pri_mc_addr;
void *fw_pri_cpu_addr;
if (!adev->ip_blocks[AMD_IP_BLOCK_TYPE_PSP].status.late_initialized) {
DRM_INFO("PSP block is not ready yet.");
return -EBUSY;
}
if (!drm_dev_enter(ddev, &idx))
return -ENODEV;
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s", buf);
ret = request_firmware(&usbc_pd_fw, fw_name, adev->dev);
if (ret)
goto fail;
/* LFB address which is aligned to 1MB boundary per PSP request */
ret = amdgpu_bo_create_kernel(adev, usbc_pd_fw->size, 0x100000,
AMDGPU_GEM_DOMAIN_VRAM,
&fw_buf_bo,
&fw_pri_mc_addr,
&fw_pri_cpu_addr);
if (ret)
goto rel_buf;
memcpy_toio(fw_pri_cpu_addr, usbc_pd_fw->data, usbc_pd_fw->size);
mutex_lock(&adev->psp.mutex);
ret = psp_load_usbc_pd_fw(&adev->psp, fw_pri_mc_addr);
mutex_unlock(&adev->psp.mutex);
amdgpu_bo_free_kernel(&fw_buf_bo, &fw_pri_mc_addr, &fw_pri_cpu_addr);
rel_buf:
release_firmware(usbc_pd_fw);
fail:
if (ret) {
DRM_ERROR("Failed to load USBC PD FW, err = %d", ret);
count = ret;
}
drm_dev_exit(idx);
return count;
}
void psp_copy_fw(struct psp_context *psp, uint8_t *start_addr, uint32_t bin_size)
{
int idx;
if (!drm_dev_enter(&psp->adev->ddev, &idx))
return;
memset(psp->fw_pri_buf, 0, PSP_1_MEG);
memcpy(psp->fw_pri_buf, start_addr, bin_size);
drm_dev_exit(idx);
}
static DEVICE_ATTR(usbc_pd_fw, S_IRUGO | S_IWUSR,
psp_usbc_pd_fw_sysfs_read,
psp_usbc_pd_fw_sysfs_write);
int is_psp_fw_valid(struct psp_bin_desc bin)
{
return bin.size_bytes;
}
const struct amd_ip_funcs psp_ip_funcs = {
.name = "psp",
.early_init = psp_early_init,
.late_init = NULL,
.sw_init = psp_sw_init,
.sw_fini = psp_sw_fini,
.hw_init = psp_hw_init,
.hw_fini = psp_hw_fini,
.suspend = psp_suspend,
.resume = psp_resume,
.is_idle = NULL,
.check_soft_reset = NULL,
.wait_for_idle = NULL,
.soft_reset = NULL,
.set_clockgating_state = psp_set_clockgating_state,
.set_powergating_state = psp_set_powergating_state,
};
static int psp_sysfs_init(struct amdgpu_device *adev)
{
int ret = device_create_file(adev->dev, &dev_attr_usbc_pd_fw);
if (ret)
DRM_ERROR("Failed to create USBC PD FW control file!");
return ret;
}
static void psp_sysfs_fini(struct amdgpu_device *adev)
{
device_remove_file(adev->dev, &dev_attr_usbc_pd_fw);
}
const struct amdgpu_ip_block_version psp_v3_1_ip_block =
{
.type = AMD_IP_BLOCK_TYPE_PSP,
.major = 3,
.minor = 1,
.rev = 0,
.funcs = &psp_ip_funcs,
};
const struct amdgpu_ip_block_version psp_v10_0_ip_block =
{
.type = AMD_IP_BLOCK_TYPE_PSP,
.major = 10,
.minor = 0,
.rev = 0,
.funcs = &psp_ip_funcs,
};
const struct amdgpu_ip_block_version psp_v11_0_ip_block =
{
.type = AMD_IP_BLOCK_TYPE_PSP,
.major = 11,
.minor = 0,
.rev = 0,
.funcs = &psp_ip_funcs,
};
const struct amdgpu_ip_block_version psp_v11_0_8_ip_block = {
.type = AMD_IP_BLOCK_TYPE_PSP,
.major = 11,
.minor = 0,
.rev = 8,
.funcs = &psp_ip_funcs,
};
const struct amdgpu_ip_block_version psp_v12_0_ip_block =
{
.type = AMD_IP_BLOCK_TYPE_PSP,
.major = 12,
.minor = 0,
.rev = 0,
.funcs = &psp_ip_funcs,
};
const struct amdgpu_ip_block_version psp_v13_0_ip_block = {
.type = AMD_IP_BLOCK_TYPE_PSP,
.major = 13,
.minor = 0,
.rev = 0,
.funcs = &psp_ip_funcs,
};