drm/amd/display: Handle SMU msg response
[Why] SMU may return error code to driver, but driver only check if response is OK. [How] Check SMU response instead of reg_wait, assert in case of reponse isn't OK. Signed-off-by: Yongqiang Sun <yongqiang.sun@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Eryk Brol <eryk.brol@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
ca37b02fba
commit
2705297c1a
|
@ -26,6 +26,7 @@
|
|||
#include "core_types.h"
|
||||
#include "clk_mgr_internal.h"
|
||||
#include "reg_helper.h"
|
||||
#include <linux/delay.h>
|
||||
|
||||
#define MAX_INSTANCE 5
|
||||
#define MAX_SEGMENT 5
|
||||
|
@ -68,10 +69,42 @@ static const struct IP_BASE MP1_BASE = { { { { 0x00016000, 0, 0, 0, 0 } },
|
|||
#define VBIOSSMC_MSG_SetDispclkFreq 0x4
|
||||
#define VBIOSSMC_MSG_SetDprefclkFreq 0x5
|
||||
|
||||
#define VBIOSSMC_Status_BUSY 0x0
|
||||
#define VBIOSSMC_Result_OK 0x1
|
||||
#define VBIOSSMC_Result_Failed 0xFF
|
||||
#define VBIOSSMC_Result_UnknownCmd 0xFE
|
||||
#define VBIOSSMC_Result_CmdRejectedPrereq 0xFD
|
||||
#define VBIOSSMC_Result_CmdRejectedBusy 0xFC
|
||||
|
||||
/*
|
||||
* Function to be used instead of REG_WAIT macro because the wait ends when
|
||||
* the register is NOT EQUAL to zero, and because the translation in msg_if.h
|
||||
* won't work with REG_WAIT.
|
||||
*/
|
||||
static uint32_t rv1_smu_wait_for_response(struct clk_mgr_internal *clk_mgr, unsigned int delay_us, unsigned int max_retries)
|
||||
{
|
||||
uint32_t res_val = VBIOSSMC_Status_BUSY;
|
||||
|
||||
do {
|
||||
res_val = REG_READ(MP1_SMN_C2PMSG_91);
|
||||
if (res_val != VBIOSSMC_Status_BUSY)
|
||||
break;
|
||||
|
||||
if (delay_us >= 1000)
|
||||
msleep(delay_us/1000);
|
||||
else if (delay_us > 0)
|
||||
udelay(delay_us);
|
||||
} while (max_retries--);
|
||||
|
||||
return res_val;
|
||||
}
|
||||
|
||||
int rv1_vbios_smu_send_msg_with_param(struct clk_mgr_internal *clk_mgr, unsigned int msg_id, unsigned int param)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
/* First clear response register */
|
||||
REG_WRITE(MP1_SMN_C2PMSG_91, 0);
|
||||
REG_WRITE(MP1_SMN_C2PMSG_91, VBIOSSMC_Status_BUSY);
|
||||
|
||||
/* Set the parameter register for the SMU message, unit is Mhz */
|
||||
REG_WRITE(MP1_SMN_C2PMSG_83, param);
|
||||
|
@ -79,7 +112,9 @@ int rv1_vbios_smu_send_msg_with_param(struct clk_mgr_internal *clk_mgr, unsigned
|
|||
/* Trigger the message transaction by writing the message ID */
|
||||
REG_WRITE(MP1_SMN_C2PMSG_67, msg_id);
|
||||
|
||||
REG_WAIT(MP1_SMN_C2PMSG_91, CONTENT, 1, 10, 200000);
|
||||
result = rv1_smu_wait_for_response(clk_mgr, 10, 1000);
|
||||
|
||||
ASSERT(result == VBIOSSMC_Result_OK);
|
||||
|
||||
/* Actual dispclk set is returned in the parameter register */
|
||||
return REG_READ(MP1_SMN_C2PMSG_83);
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "core_types.h"
|
||||
#include "clk_mgr_internal.h"
|
||||
#include "reg_helper.h"
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "renoir_ip_offset.h"
|
||||
|
||||
|
@ -53,10 +54,43 @@
|
|||
#define VBIOSSMC_MSG_EnableTmdp48MHzRefclkPwrDown 0xD
|
||||
#define VBIOSSMC_MSG_UpdatePmeRestore 0xE
|
||||
|
||||
#define VBIOSSMC_Status_BUSY 0x0
|
||||
#define VBIOSSMC_Result_OK 0x1
|
||||
#define VBIOSSMC_Result_Failed 0xFF
|
||||
#define VBIOSSMC_Result_UnknownCmd 0xFE
|
||||
#define VBIOSSMC_Result_CmdRejectedPrereq 0xFD
|
||||
#define VBIOSSMC_Result_CmdRejectedBusy 0xFC
|
||||
|
||||
/*
|
||||
* Function to be used instead of REG_WAIT macro because the wait ends when
|
||||
* the register is NOT EQUAL to zero, and because the translation in msg_if.h
|
||||
* won't work with REG_WAIT.
|
||||
*/
|
||||
static uint32_t rn_smu_wait_for_response(struct clk_mgr_internal *clk_mgr, unsigned int delay_us, unsigned int max_retries)
|
||||
{
|
||||
uint32_t res_val = VBIOSSMC_Status_BUSY;
|
||||
|
||||
do {
|
||||
res_val = REG_READ(MP1_SMN_C2PMSG_91);
|
||||
if (res_val != VBIOSSMC_Status_BUSY)
|
||||
break;
|
||||
|
||||
if (delay_us >= 1000)
|
||||
msleep(delay_us/1000);
|
||||
else if (delay_us > 0)
|
||||
udelay(delay_us);
|
||||
} while (max_retries--);
|
||||
|
||||
return res_val;
|
||||
}
|
||||
|
||||
|
||||
int rn_vbios_smu_send_msg_with_param(struct clk_mgr_internal *clk_mgr, unsigned int msg_id, unsigned int param)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
/* First clear response register */
|
||||
REG_WRITE(MP1_SMN_C2PMSG_91, 0);
|
||||
REG_WRITE(MP1_SMN_C2PMSG_91, VBIOSSMC_Status_BUSY);
|
||||
|
||||
/* Set the parameter register for the SMU message, unit is Mhz */
|
||||
REG_WRITE(MP1_SMN_C2PMSG_83, param);
|
||||
|
@ -64,7 +98,9 @@ int rn_vbios_smu_send_msg_with_param(struct clk_mgr_internal *clk_mgr, unsigned
|
|||
/* Trigger the message transaction by writing the message ID */
|
||||
REG_WRITE(MP1_SMN_C2PMSG_67, msg_id);
|
||||
|
||||
REG_WAIT(MP1_SMN_C2PMSG_91, CONTENT, 1, 10, 200000);
|
||||
result = rn_smu_wait_for_response(clk_mgr, 10, 1000);
|
||||
|
||||
ASSERT(result == VBIOSSMC_Result_OK);
|
||||
|
||||
/* Actual dispclk set is returned in the parameter register */
|
||||
return REG_READ(MP1_SMN_C2PMSG_83);
|
||||
|
|
Loading…
Reference in New Issue