drm/amd/display: Redefine DMCU_SCRATCH to identify DMCU state
authorMartin Tsai <martin.tsai@amd.com>
Thu, 13 Dec 2018 04:25:19 +0000 (12:25 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Mon, 14 Jan 2019 20:39:22 +0000 (15:39 -0500)
[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: Martin Tsai <martin.tsai@amd.com>
Reviewed-by: Anthony Koo <Anthony.Koo@amd.com>
Acked-by: Leo Li <sunpeng.li@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c
drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h
drivers/gpu/drm/amd/display/modules/power/power_helpers.c

index dea40b3221918279795828d701aa336174dc9073..e927c8934681f3ad72a63cc7e850bf2572a4e380 100644 (file)
@@ -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,
index cb85eaa9857f84e878115934dc00fb10f92b80ea..ed32a7503684fa64522b4f70f4e8decaae847de1 100644 (file)
 
 #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 {
index c11a443dcbc8927fc2e9920ce7a72b332c139cd4..89b082b5d1072fe66b807da7c45691e64835728b 100644 (file)
@@ -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);
 }