// SPDX-License-Identifier: MIT
/*
* Copyright 2025 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.
*/
#include <linux/delay.h>
#include "amdgpu.h"
#include "amdgpu_reset.h"
#include "amdgpu_trace.h"
#include "amdgpu_virt.h"
#include "amdgpu_reg_access.h"
#define AMDGPU_PCIE_INDEX_FALLBACK (0x38 >> 2)
#define AMDGPU_PCIE_INDEX_HI_FALLBACK (0x44 >> 2)
#define AMDGPU_PCIE_DATA_FALLBACK (0x3C >> 2)
void amdgpu_reg_access_init(struct amdgpu_device *adev)
{
spin_lock_init(&adev->reg.smc.lock);
adev->reg.smc.rreg = NULL;
adev->reg.smc.wreg = NULL;
spin_lock_init(&adev->reg.uvd_ctx.lock);
adev->reg.uvd_ctx.rreg = NULL;
adev->reg.uvd_ctx.wreg = NULL;
spin_lock_init(&adev->reg.didt.lock);
adev->reg.didt.rreg = NULL;
adev->reg.didt.wreg = NULL;
spin_lock_init(&adev->reg.gc_cac.lock);
adev->reg.gc_cac.rreg = NULL;
adev->reg.gc_cac.wreg = NULL;
spin_lock_init(&adev->reg.se_cac.lock);
adev->reg.se_cac.rreg = NULL;
adev->reg.se_cac.wreg = NULL;
spin_lock_init(&adev->reg.audio_endpt.lock);
adev->reg.audio_endpt.rreg = NULL;
adev->reg.audio_endpt.wreg = NULL;
spin_lock_init(&adev->reg.pcie.lock);
adev->reg.pcie.rreg = NULL;
adev->reg.pcie.wreg = NULL;
adev->reg.pcie.rreg_ext = NULL;
adev->reg.pcie.wreg_ext = NULL;
adev->reg.pcie.rreg64 = NULL;
adev->reg.pcie.wreg64 = NULL;
adev->reg.pcie.rreg64_ext = NULL;
adev->reg.pcie.wreg64_ext = NULL;
adev->reg.pcie.port_rreg = NULL;
adev->reg.pcie.port_wreg = NULL;
}
uint32_t amdgpu_reg_smc_rd32(struct amdgpu_device *adev, uint32_t reg)
{
if (!adev->reg.smc.rreg) {
dev_err_once(adev->dev, "SMC register read not supported\n");
return 0;
}
return adev->reg.smc.rreg(adev, reg);
}
void amdgpu_reg_smc_wr32(struct amdgpu_device *adev, uint32_t reg, uint32_t v)
{
if (!adev->reg.smc.wreg) {
dev_err_once(adev->dev, "SMC register write not supported\n");
return;
}
adev->reg.smc.wreg(adev, reg, v);
}
uint32_t amdgpu_reg_uvd_ctx_rd32(struct amdgpu_device *adev, uint32_t reg)
{
if (!adev->reg.uvd_ctx.rreg) {
dev_err_once(adev->dev,
"UVD_CTX register read not supported\n");
return 0;
}
return adev->reg.uvd_ctx.rreg(adev, reg);
}
void amdgpu_reg_uvd_ctx_wr32(struct amdgpu_device *adev, uint32_t reg,
uint32_t v)
{
if (!adev->reg.uvd_ctx.wreg) {
dev_err_once(adev->dev,
"UVD_CTX register write not supported\n");
return;
}
adev->reg.uvd_ctx.wreg(adev, reg, v);
}
uint32_t amdgpu_reg_didt_rd32(struct amdgpu_device *adev, uint32_t reg)
{
if (!adev->reg.didt.rreg) {
dev_err_once(adev->dev, "DIDT register read not supported\n");
return 0;
}
return adev->reg.didt.rreg(adev, reg);
}
void amdgpu_reg_didt_wr32(struct amdgpu_device *adev, uint32_t reg, uint32_t v)
{
if (!adev->reg.didt.wreg) {
dev_err_once(adev->dev, "DIDT register write not supported\n");
return;
}
adev->reg.didt.wreg(adev