Commit ffb6c1c6 authored by Martin Tsai's avatar Martin Tsai Committed by Alex Deucher

drm/amd/display: Redefine DMCU_SCRATCH to identify DMCU state

[why]
To resume system before entering S0i3 completely will cause PSP not
reload DMCU FW since there is not HW power state change.
In this case, driver cannot get correct DMCU version from IRAM
since driver override it and DMCU didn't reload to update it.
It makes driver return false in dcn10_dmcu_init().

[how]
1.To redefine DMCU_SCRATCH to identify different DMCU state.
2.To reserve IRAM 0xF0~0xFF write by DMCU only.
3.To remove dcn10_get_dmcu_state
Signed-off-by: default avatarMartin Tsai <martin.tsai@amd.com>
Reviewed-by: default avatarAnthony Koo <Anthony.Koo@amd.com>
Acked-by: default avatarLeo Li <sunpeng.li@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 070fe724
......@@ -51,7 +51,6 @@
#define PSR_SET_WAITLOOP 0x31
#define MCP_INIT_DMCU 0x88
#define MCP_INIT_IRAM 0x89
#define MCP_DMCU_VERSION 0x90
#define MASTER_COMM_CNTL_REG__MASTER_COMM_INTERRUPT_MASK 0x00000001L
static bool dce_dmcu_init(struct dmcu *dmcu)
......@@ -317,38 +316,11 @@ static void dce_get_psr_wait_loop(
}
#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
static void dcn10_get_dmcu_state(struct dmcu *dmcu)
{
struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
uint32_t dmcu_state_offset = 0xf6;
/* Enable write access to IRAM */
REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL,
IRAM_HOST_ACCESS_EN, 1,
IRAM_RD_ADDR_AUTO_INC, 1);
REG_WAIT(DMU_MEM_PWR_CNTL, DMCU_IRAM_MEM_PWR_STATE, 0, 2, 10);
/* Write address to IRAM_RD_ADDR in DMCU_IRAM_RD_CTRL */
REG_WRITE(DMCU_IRAM_RD_CTRL, dmcu_state_offset);
/* Read data from IRAM_RD_DATA in DMCU_IRAM_RD_DATA*/
dmcu->dmcu_state = REG_READ(DMCU_IRAM_RD_DATA);
/* Disable write access to IRAM to allow dynamic sleep state */
REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL,
IRAM_HOST_ACCESS_EN, 0,
IRAM_RD_ADDR_AUTO_INC, 0);
}
static void dcn10_get_dmcu_version(struct dmcu *dmcu)
{
struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
uint32_t dmcu_version_offset = 0xf1;
/* Clear scratch */
REG_WRITE(DC_DMCU_SCRATCH, 0);
/* Enable write access to IRAM */
REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL,
IRAM_HOST_ACCESS_EN, 1,
......@@ -368,76 +340,65 @@ static void dcn10_get_dmcu_version(struct dmcu *dmcu)
REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL,
IRAM_HOST_ACCESS_EN, 0,
IRAM_RD_ADDR_AUTO_INC, 0);
/* Send MCP command message to DMCU to get version reply from FW.
* We expect this version should match the one in IRAM, otherwise
* something is wrong with DMCU and we should fail and disable UC.
*/
REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800);
/* Set command to get DMCU version from microcontroller */
REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0,
MCP_DMCU_VERSION);
/* Notify microcontroller of new command */
REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
/* Ensure command has been executed before continuing */
REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800);
/* Somehow version does not match, so fail and return version 0 */
if (dmcu->dmcu_version.interface_version != REG_READ(DC_DMCU_SCRATCH))
dmcu->dmcu_version.interface_version = 0;
}
static bool dcn10_dmcu_init(struct dmcu *dmcu)
{
struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
bool status = false;
/* DMCU FW should populate the scratch register if running */
if (REG_READ(DC_DMCU_SCRATCH) == 0)
return false;
/* Check state is uninitialized */
dcn10_get_dmcu_state(dmcu);
/* If microcontroller is already initialized, do nothing */
if (dmcu->dmcu_state == DMCU_RUNNING)
return true;
/* Retrieve and cache the DMCU firmware version. */
dcn10_get_dmcu_version(dmcu);
/* Check interface version to confirm firmware is loaded and running */
if (dmcu->dmcu_version.interface_version == 0)
return false;
/* Definition of DC_DMCU_SCRATCH
* 0 : firmare not loaded
* 1 : PSP load DMCU FW but not initialized
* 2 : Firmware already initialized
*/
dmcu->dmcu_state = REG_READ(DC_DMCU_SCRATCH);
/* Wait until microcontroller is ready to process interrupt */
REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800);
switch (dmcu->dmcu_state) {
case DMCU_UNLOADED:
status = false;
break;
case DMCU_LOADED_UNINITIALIZED:
/* Wait until microcontroller is ready to process interrupt */
REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800);
/* Set initialized ramping boundary value */
REG_WRITE(MASTER_COMM_DATA_REG1, 0xFFFF);
/* Set initialized ramping boundary value */
REG_WRITE(MASTER_COMM_DATA_REG1, 0xFFFF);
/* Set command to initialize microcontroller */
REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0,
/* Set command to initialize microcontroller */
REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0,
MCP_INIT_DMCU);
/* Notify microcontroller of new command */
REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
/* Notify microcontroller of new command */
REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
/* Ensure command has been executed before continuing */
REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800);
/* Ensure command has been executed before continuing */
REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800);
// Check state is initialized
dcn10_get_dmcu_state(dmcu);
// Check state is initialized
dmcu->dmcu_state = REG_READ(DC_DMCU_SCRATCH);
// If microcontroller is not in running state, fail
if (dmcu->dmcu_state != DMCU_RUNNING)
return false;
// If microcontroller is not in running state, fail
if (dmcu->dmcu_state == DMCU_RUNNING) {
/* Retrieve and cache the DMCU firmware version. */
dcn10_get_dmcu_version(dmcu);
status = true;
} else
status = false;
return true;
break;
case DMCU_RUNNING:
status = true;
break;
default:
status = false;
break;
}
return status;
}
static bool dcn10_dmcu_load_iram(struct dmcu *dmcu,
unsigned int start_offset,
const char *src,
......
......@@ -27,9 +27,15 @@
#include "dm_services_types.h"
/* If HW itself ever powered down it will be 0.
* fwDmcuInit will write to 1.
* Driver will only call MCP init if current state is 1,
* and the MCP command will transition this to 2.
*/
enum dmcu_state {
DMCU_NOT_INITIALIZED = 0,
DMCU_RUNNING = 1
DMCU_UNLOADED = 0,
DMCU_LOADED_UNINITIALIZED = 1,
DMCU_RUNNING = 2,
};
struct dmcu_version {
......
......@@ -56,6 +56,7 @@ static const unsigned char abm_config[abm_defines_max_config][abm_defines_max_le
#define NUM_AGGR_LEVEL 4
#define NUM_POWER_FN_SEGS 8
#define NUM_BL_CURVE_SEGS 16
#define IRAM_RESERVE_AREA_START 0xF0 // reserve 0xF0~0xFF are write by DMCU only
#pragma pack(push, 1)
/* NOTE: iRAM is 256B in size */
......@@ -324,5 +325,5 @@ bool dmcu_load_iram(struct dmcu *dmcu,
params, &ram_table);
return dmcu->funcs->load_iram(
dmcu, 0, (char *)(&ram_table), sizeof(ram_table));
dmcu, 0, (char *)(&ram_table), IRAM_RESERVE_AREA_START);
}
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