Commit 25a3e8ac authored by Andrey Grodzovsky's avatar Andrey Grodzovsky Committed by Alex Deucher

drm/amdgpu: Switch to VRAM buffer for USBC PD FW.

System memory-based implementation for updating the
USBCPD is deprecated for so switching
to LFB based implementation for all the ASICs.
Signed-off-by: default avatarAndrey Grodzovsky <andrey.grodzovsky@amd.com>
Reviewed-by: default avatarAlexander Deucher <Alexander.Deucher@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 9075096b
...@@ -24,7 +24,6 @@ ...@@ -24,7 +24,6 @@
*/ */
#include <linux/firmware.h> #include <linux/firmware.h>
#include <linux/dma-mapping.h>
#include <drm/drm_drv.h> #include <drm/drm_drv.h>
#include "amdgpu.h" #include "amdgpu.h"
...@@ -3273,11 +3272,12 @@ static ssize_t psp_usbc_pd_fw_sysfs_write(struct device *dev, ...@@ -3273,11 +3272,12 @@ static ssize_t psp_usbc_pd_fw_sysfs_write(struct device *dev,
{ {
struct drm_device *ddev = dev_get_drvdata(dev); struct drm_device *ddev = dev_get_drvdata(dev);
struct amdgpu_device *adev = drm_to_adev(ddev); struct amdgpu_device *adev = drm_to_adev(ddev);
void *cpu_addr;
dma_addr_t dma_addr;
int ret, idx; int ret, idx;
char fw_name[100]; char fw_name[100];
const struct firmware *usbc_pd_fw; 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) { if (!adev->ip_blocks[AMD_IP_BLOCK_TYPE_PSP].status.late_initialized) {
DRM_INFO("PSP block is not ready yet."); DRM_INFO("PSP block is not ready yet.");
...@@ -3292,31 +3292,24 @@ static ssize_t psp_usbc_pd_fw_sysfs_write(struct device *dev, ...@@ -3292,31 +3292,24 @@ static ssize_t psp_usbc_pd_fw_sysfs_write(struct device *dev,
if (ret) if (ret)
goto fail; goto fail;
/* We need contiguous physical mem to place the FW for psp to access */ /* LFB address which is aligned to 1MB boundary per PSP request */
cpu_addr = dma_alloc_coherent(adev->dev, usbc_pd_fw->size, &dma_addr, GFP_KERNEL); ret = amdgpu_bo_create_kernel(adev, usbc_pd_fw->size, 0x100000,
AMDGPU_GEM_DOMAIN_VRAM,
ret = dma_mapping_error(adev->dev, dma_addr); &fw_buf_bo,
&fw_pri_mc_addr,
&fw_pri_cpu_addr);
if (ret) if (ret)
goto rel_buf; goto rel_buf;
memcpy_toio(cpu_addr, usbc_pd_fw->data, usbc_pd_fw->size); memcpy_toio(fw_pri_cpu_addr, usbc_pd_fw->data, usbc_pd_fw->size);
/*
* x86 specific workaround.
* Without it the buffer is invisible in PSP.
*
* TODO Remove once PSP starts snooping CPU cache
*/
#ifdef CONFIG_X86
clflush_cache_range(cpu_addr, (usbc_pd_fw->size & ~(L1_CACHE_BYTES - 1)));
#endif
mutex_lock(&adev->psp.mutex); mutex_lock(&adev->psp.mutex);
ret = psp_load_usbc_pd_fw(&adev->psp, dma_addr); ret = psp_load_usbc_pd_fw(&adev->psp, fw_pri_mc_addr);
mutex_unlock(&adev->psp.mutex); mutex_unlock(&adev->psp.mutex);
amdgpu_bo_free_kernel(&fw_buf_bo, &fw_pri_mc_addr, &fw_pri_cpu_addr);
rel_buf: rel_buf:
dma_free_coherent(adev->dev, usbc_pd_fw->size, cpu_addr, dma_addr);
release_firmware(usbc_pd_fw); release_firmware(usbc_pd_fw);
fail: fail:
if (ret) { if (ret) {
......
...@@ -106,7 +106,7 @@ struct psp_funcs ...@@ -106,7 +106,7 @@ struct psp_funcs
int (*mem_training)(struct psp_context *psp, uint32_t ops); int (*mem_training)(struct psp_context *psp, uint32_t ops);
uint32_t (*ring_get_wptr)(struct psp_context *psp); uint32_t (*ring_get_wptr)(struct psp_context *psp);
void (*ring_set_wptr)(struct psp_context *psp, uint32_t value); void (*ring_set_wptr)(struct psp_context *psp, uint32_t value);
int (*load_usbc_pd_fw)(struct psp_context *psp, dma_addr_t dma_addr); int (*load_usbc_pd_fw)(struct psp_context *psp, uint64_t fw_pri_mc_addr);
int (*read_usbc_pd_fw)(struct psp_context *psp, uint32_t *fw_ver); int (*read_usbc_pd_fw)(struct psp_context *psp, uint32_t *fw_ver);
}; };
...@@ -414,9 +414,9 @@ struct amdgpu_psp_funcs { ...@@ -414,9 +414,9 @@ struct amdgpu_psp_funcs {
#define psp_ring_get_wptr(psp) (psp)->funcs->ring_get_wptr((psp)) #define psp_ring_get_wptr(psp) (psp)->funcs->ring_get_wptr((psp))
#define psp_ring_set_wptr(psp, value) (psp)->funcs->ring_set_wptr((psp), (value)) #define psp_ring_set_wptr(psp, value) (psp)->funcs->ring_set_wptr((psp), (value))
#define psp_load_usbc_pd_fw(psp, dma_addr) \ #define psp_load_usbc_pd_fw(psp, fw_pri_mc_addr) \
((psp)->funcs->load_usbc_pd_fw ? \ ((psp)->funcs->load_usbc_pd_fw ? \
(psp)->funcs->load_usbc_pd_fw((psp), (dma_addr)) : -EINVAL) (psp)->funcs->load_usbc_pd_fw((psp), (fw_pri_mc_addr)) : -EINVAL)
#define psp_read_usbc_pd_fw(psp, fw_ver) \ #define psp_read_usbc_pd_fw(psp, fw_ver) \
((psp)->funcs->read_usbc_pd_fw ? \ ((psp)->funcs->read_usbc_pd_fw ? \
......
...@@ -80,6 +80,9 @@ MODULE_FIRMWARE("amdgpu/beige_goby_ta.bin"); ...@@ -80,6 +80,9 @@ MODULE_FIRMWARE("amdgpu/beige_goby_ta.bin");
/* For large FW files the time to complete can be very long */ /* For large FW files the time to complete can be very long */
#define USBC_PD_POLLING_LIMIT_S 240 #define USBC_PD_POLLING_LIMIT_S 240
/* Read USB-PD from LFB */
#define GFX_CMD_USB_PD_USE_LFB 0x480
static int psp_v11_0_init_microcode(struct psp_context *psp) static int psp_v11_0_init_microcode(struct psp_context *psp)
{ {
struct amdgpu_device *adev = psp->adev; struct amdgpu_device *adev = psp->adev;
...@@ -753,44 +756,26 @@ static void psp_v11_0_ring_set_wptr(struct psp_context *psp, uint32_t value) ...@@ -753,44 +756,26 @@ static void psp_v11_0_ring_set_wptr(struct psp_context *psp, uint32_t value)
WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_67, value); WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_67, value);
} }
static int psp_v11_0_load_usbc_pd_fw(struct psp_context *psp, dma_addr_t dma_addr) static int psp_v11_0_load_usbc_pd_fw(struct psp_context *psp, uint64_t fw_pri_mc_addr)
{ {
struct amdgpu_device *adev = psp->adev; struct amdgpu_device *adev = psp->adev;
uint32_t reg_status; uint32_t reg_status;
int ret, i = 0; int ret, i = 0;
/* Write lower 32-bit address of the PD Controller FW */ /*
WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36, lower_32_bits(dma_addr)); * LFB address which is aligned to 1MB address and has to be
ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35), * right-shifted by 20 so that LFB address can be passed on a 32-bit C2P
0x80000000, 0x80000000, false); * register
if (ret) */
return ret; WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36, (fw_pri_mc_addr >> 20));
/* Fireup interrupt so PSP can pick up the lower address */
WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, 0x800000);
ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35),
0x80000000, 0x80000000, false);
if (ret)
return ret;
reg_status = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35);
if ((reg_status & 0xFFFF) != 0) {
DRM_ERROR("Lower address load failed - MP0_SMN_C2PMSG_35.Bits [15:0] = %02x...\n",
reg_status & 0xFFFF);
return -EIO;
}
/* Write upper 32-bit address of the PD Controller FW */
WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36, upper_32_bits(dma_addr));
ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35), ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35),
0x80000000, 0x80000000, false); 0x80000000, 0x80000000, false);
if (ret) if (ret)
return ret; return ret;
/* Fireup interrupt so PSP can pick up the upper address */ /* Fireup interrupt so PSP can pick up the address */
WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, 0x4000000); WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, (GFX_CMD_USB_PD_USE_LFB << 16));
/* FW load takes very long time */ /* FW load takes very long time */
do { do {
...@@ -806,7 +791,7 @@ static int psp_v11_0_load_usbc_pd_fw(struct psp_context *psp, dma_addr_t dma_add ...@@ -806,7 +791,7 @@ static int psp_v11_0_load_usbc_pd_fw(struct psp_context *psp, dma_addr_t dma_add
done: done:
if ((reg_status & 0xFFFF) != 0) { if ((reg_status & 0xFFFF) != 0) {
DRM_ERROR("Upper address load failed - MP0_SMN_C2PMSG_35.Bits [15:0] = x%04x\n", DRM_ERROR("Address load failed - MP0_SMN_C2PMSG_35.Bits [15:0] = 0x%04x\n",
reg_status & 0xFFFF); reg_status & 0xFFFF);
return -EIO; return -EIO;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment