|
@@ -49,9 +49,18 @@
|
|
|
#define PSR_EXIT 0x21
|
|
|
#define PSR_SET 0x23
|
|
|
#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
|
|
|
unsigned int cached_wait_loop_number = 0;
|
|
|
|
|
|
+static bool dce_dmcu_init(struct dmcu *dmcu)
|
|
|
+{
|
|
|
+ // Do nothing
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
bool dce_dmcu_load_iram(struct dmcu *dmcu,
|
|
|
unsigned int start_offset,
|
|
|
const char *src,
|
|
@@ -84,7 +93,7 @@ static void dce_get_dmcu_psr_state(struct dmcu *dmcu, uint32_t *psr_state)
|
|
|
{
|
|
|
struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
|
|
|
|
|
|
- uint32_t psrStateOffset = 0xf0;
|
|
|
+ uint32_t psr_state_offset = 0xf0;
|
|
|
|
|
|
/* Enable write access to IRAM */
|
|
|
REG_UPDATE(DMCU_RAM_ACCESS_CTRL, IRAM_HOST_ACCESS_EN, 1);
|
|
@@ -92,7 +101,7 @@ static void dce_get_dmcu_psr_state(struct dmcu *dmcu, uint32_t *psr_state)
|
|
|
REG_WAIT(DCI_MEM_PWR_STATUS, 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, psrStateOffset);
|
|
|
+ REG_WRITE(DMCU_IRAM_RD_CTRL, psr_state_offset);
|
|
|
|
|
|
/* Read data from IRAM_RD_DATA in DMCU_IRAM_RD_DATA*/
|
|
|
*psr_state = REG_READ(DMCU_IRAM_RD_DATA);
|
|
@@ -286,7 +295,128 @@ static void dce_get_psr_wait_loop(unsigned int *psr_wait_loop_number)
|
|
|
}
|
|
|
|
|
|
#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
|
|
|
-bool dcn10_dmcu_load_iram(struct dmcu *dmcu,
|
|
|
+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,
|
|
|
+ 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 and read from DATA register */
|
|
|
+ REG_WRITE(DMCU_IRAM_RD_CTRL, dmcu_version_offset);
|
|
|
+ dmcu->dmcu_version.interface_version = REG_READ(DMCU_IRAM_RD_DATA);
|
|
|
+ dmcu->dmcu_version.year = ((REG_READ(DMCU_IRAM_RD_DATA) << 8) |
|
|
|
+ REG_READ(DMCU_IRAM_RD_DATA));
|
|
|
+ dmcu->dmcu_version.month = REG_READ(DMCU_IRAM_RD_DATA);
|
|
|
+ dmcu->dmcu_version.day = 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);
|
|
|
+
|
|
|
+ /* 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);
|
|
|
+
|
|
|
+ /* 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;
|
|
|
+
|
|
|
+ /* 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 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);
|
|
|
+
|
|
|
+ /* 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);
|
|
|
+
|
|
|
+ // If microcontroller is not in running state, fail
|
|
|
+ if (dmcu->dmcu_state != DMCU_RUNNING)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+static bool dcn10_dmcu_load_iram(struct dmcu *dmcu,
|
|
|
unsigned int start_offset,
|
|
|
const char *src,
|
|
|
unsigned int bytes)
|
|
@@ -294,7 +424,9 @@ bool dcn10_dmcu_load_iram(struct dmcu *dmcu,
|
|
|
struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
|
|
|
unsigned int count = 0;
|
|
|
|
|
|
- REG_UPDATE(DMCU_CTRL, DMCU_ENABLE, 1);
|
|
|
+ /* If microcontroller is not running, do nothing */
|
|
|
+ if (dmcu->dmcu_state != DMCU_RUNNING)
|
|
|
+ return false;
|
|
|
|
|
|
/* Enable write access to IRAM */
|
|
|
REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL,
|
|
@@ -313,6 +445,19 @@ bool dcn10_dmcu_load_iram(struct dmcu *dmcu,
|
|
|
IRAM_HOST_ACCESS_EN, 0,
|
|
|
IRAM_WR_ADDR_AUTO_INC, 0);
|
|
|
|
|
|
+ /* Wait until microcontroller is ready to process interrupt */
|
|
|
+ REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800);
|
|
|
+
|
|
|
+ /* Set command to signal IRAM is loaded and to initialize IRAM */
|
|
|
+ REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0,
|
|
|
+ MCP_INIT_IRAM);
|
|
|
+
|
|
|
+ /* 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);
|
|
|
+
|
|
|
return true;
|
|
|
}
|
|
|
|
|
@@ -320,7 +465,11 @@ static void dcn10_get_dmcu_psr_state(struct dmcu *dmcu, uint32_t *psr_state)
|
|
|
{
|
|
|
struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
|
|
|
|
|
|
- uint32_t psrStateOffset = 0xf0;
|
|
|
+ uint32_t psr_state_offset = 0xf0;
|
|
|
+
|
|
|
+ /* If microcontroller is not running, do nothing */
|
|
|
+ if (dmcu->dmcu_state != DMCU_RUNNING)
|
|
|
+ return;
|
|
|
|
|
|
/* Enable write access to IRAM */
|
|
|
REG_UPDATE(DMCU_RAM_ACCESS_CTRL, IRAM_HOST_ACCESS_EN, 1);
|
|
@@ -328,7 +477,7 @@ static void dcn10_get_dmcu_psr_state(struct dmcu *dmcu, uint32_t *psr_state)
|
|
|
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, psrStateOffset);
|
|
|
+ REG_WRITE(DMCU_IRAM_RD_CTRL, psr_state_offset);
|
|
|
|
|
|
/* Read data from IRAM_RD_DATA in DMCU_IRAM_RD_DATA*/
|
|
|
*psr_state = REG_READ(DMCU_IRAM_RD_DATA);
|
|
@@ -348,6 +497,10 @@ static void dcn10_dmcu_set_psr_enable(struct dmcu *dmcu, bool enable, bool wait)
|
|
|
unsigned int retryCount;
|
|
|
uint32_t psr_state = 0;
|
|
|
|
|
|
+ /* If microcontroller is not running, do nothing */
|
|
|
+ if (dmcu->dmcu_state != DMCU_RUNNING)
|
|
|
+ return;
|
|
|
+
|
|
|
/* waitDMCUReadyForCmd */
|
|
|
REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0,
|
|
|
dmcu_wait_reg_ready_interval,
|
|
@@ -399,6 +552,10 @@ static void dcn10_dmcu_setup_psr(struct dmcu *dmcu,
|
|
|
union dce_dmcu_psr_config_data_reg2 masterCmdData2;
|
|
|
union dce_dmcu_psr_config_data_reg3 masterCmdData3;
|
|
|
|
|
|
+ /* If microcontroller is not running, do nothing */
|
|
|
+ if (dmcu->dmcu_state != DMCU_RUNNING)
|
|
|
+ return;
|
|
|
+
|
|
|
link->link_enc->funcs->psr_program_dp_dphy_fast_training(link->link_enc,
|
|
|
psr_context->psrExitLinkTrainingRequired);
|
|
|
|
|
@@ -505,6 +662,11 @@ static void dcn10_psr_wait_loop(
|
|
|
{
|
|
|
struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
|
|
|
union dce_dmcu_psr_config_data_wait_loop_reg1 masterCmdData1;
|
|
|
+
|
|
|
+ /* If microcontroller is not running, do nothing */
|
|
|
+ if (dmcu->dmcu_state != DMCU_RUNNING)
|
|
|
+ return;
|
|
|
+
|
|
|
if (wait_loop_number != 0) {
|
|
|
/* waitDMCUReadyForCmd */
|
|
|
REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 1, 10000);
|
|
@@ -531,6 +693,7 @@ static void dcn10_get_psr_wait_loop(unsigned int *psr_wait_loop_number)
|
|
|
#endif
|
|
|
|
|
|
static const struct dmcu_funcs dce_funcs = {
|
|
|
+ .dmcu_init = dce_dmcu_init,
|
|
|
.load_iram = dce_dmcu_load_iram,
|
|
|
.set_psr_enable = dce_dmcu_set_psr_enable,
|
|
|
.setup_psr = dce_dmcu_setup_psr,
|
|
@@ -541,6 +704,7 @@ static const struct dmcu_funcs dce_funcs = {
|
|
|
|
|
|
#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
|
|
|
static const struct dmcu_funcs dcn10_funcs = {
|
|
|
+ .dmcu_init = dcn10_dmcu_init,
|
|
|
.load_iram = dcn10_dmcu_load_iram,
|
|
|
.set_psr_enable = dcn10_dmcu_set_psr_enable,
|
|
|
.setup_psr = dcn10_dmcu_setup_psr,
|