aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c
diff options
context:
space:
mode:
authorAmy Zhang <Amy.Zhang@amd.com>2017-02-17 11:56:03 -0500
committerAlex Deucher <alexander.deucher@amd.com>2017-09-26 17:16:02 -0400
commit3548f0731a2fa823bcb31b5ea662603926b85c43 (patch)
tree16468a04c372b44edb703fcdd23e89825c2c9fa2 /drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c
parentdrm/amd/display: 420 clock divided by 2 twice (diff)
downloadlinux-dev-3548f0731a2fa823bcb31b5ea662603926b85c43.tar.xz
linux-dev-3548f0731a2fa823bcb31b5ea662603926b85c43.zip
drm/amd/display: DMCU PSR Refactor
- Move PSR programming from link encoder to dmcu Signed-off-by: Amy Zhang <Amy.Zhang@amd.com> Acked-by: Harry Wentland <Harry.Wentland@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c')
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c208
1 files changed, 208 insertions, 0 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c
index eb0e95f57aa9..44eeeeb888fe 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c
@@ -23,6 +23,8 @@
*
*/
+#include "core_types.h"
+#include "link_encoder.h"
#include "dce_dmcu.h"
#include "dm_services.h"
#include "reg_helper.h"
@@ -42,6 +44,12 @@
#define CTX \
dmcu_dce->base.ctx
+/* PSR related commands */
+#define PSR_ENABLE 0x20
+#define PSR_EXIT 0x21
+#define PSR_SET 0x23
+#define MASTER_COMM_CNTL_REG__MASTER_COMM_INTERRUPT_MASK 0x00000001L
+
bool dce_dmcu_load_iram(struct dmcu *dmcu,
unsigned int start_offset,
const char *src,
@@ -76,8 +84,208 @@ bool dce_dmcu_load_iram(struct dmcu *dmcu,
return true;
}
+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 count = 0;
+ uint32_t psrStateOffset = 0xf0;
+ uint32_t value = -1;
+
+ /* Enable write access to IRAM */
+ REG_UPDATE(DMCU_RAM_ACCESS_CTRL, IRAM_HOST_ACCESS_EN, 1);
+
+ while (REG(DCI_MEM_PWR_STATUS) && value != 0 && count++ < 10) {
+ dm_delay_in_microseconds(dmcu->ctx, 2);
+ REG_GET(DCI_MEM_PWR_STATUS, DMCU_IRAM_MEM_PWR_STATE, &value);
+ }
+ while (REG(DMU_MEM_PWR_CNTL) && value != 0 && count++ < 10) {
+ dm_delay_in_microseconds(dmcu->ctx, 2);
+ REG_GET(DMU_MEM_PWR_CNTL, DMCU_IRAM_MEM_PWR_STATE, &value);
+ }
+
+ /* Write address to IRAM_RD_ADDR in DMCU_IRAM_RD_CTRL */
+ REG_WRITE(DMCU_IRAM_RD_CTRL, psrStateOffset);
+
+ /* Read data from IRAM_RD_DATA in DMCU_IRAM_RD_DATA*/
+ *psr_state = REG_READ(DMCU_IRAM_RD_DATA);
+
+ /* Disable write access to IRAM after finished using IRAM
+ * in order to allow dynamic sleep state
+ */
+ REG_UPDATE(DMCU_RAM_ACCESS_CTRL, IRAM_HOST_ACCESS_EN, 0);
+}
+
+static void dce_dmcu_set_psr_enable(struct dmcu *dmcu, bool enable)
+{
+ struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
+ unsigned int dmcu_max_retry_on_wait_reg_ready = 801;
+ unsigned int dmcu_wait_reg_ready_interval = 100;
+
+ unsigned int regValue;
+
+ unsigned int retryCount;
+ uint32_t psr_state = 0;
+
+ /* waitDMCUReadyForCmd */
+ do {
+ dm_delay_in_microseconds(dmcu->ctx,
+ dmcu_wait_reg_ready_interval);
+ regValue = REG_READ(MASTER_COMM_CNTL_REG);
+ dmcu_max_retry_on_wait_reg_ready--;
+ } while
+ /* expected value is 0, loop while not 0*/
+ ((MASTER_COMM_CNTL_REG__MASTER_COMM_INTERRUPT_MASK & regValue) &&
+ dmcu_max_retry_on_wait_reg_ready > 0);
+
+ /* setDMCUParam_Cmd */
+ if (enable)
+ REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0,
+ PSR_ENABLE);
+ else
+ REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0,
+ PSR_EXIT);
+
+ /* notifyDMCUMsg */
+ REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
+
+ for (retryCount = 0; retryCount <= 100; retryCount++) {
+ dce_get_dmcu_psr_state(dmcu, &psr_state);
+ if (enable) {
+ if (psr_state != 0)
+ break;
+ } else {
+ if (psr_state == 0)
+ break;
+ }
+ dm_delay_in_microseconds(dmcu->ctx, 10);
+ }
+}
+
+static void dce_dmcu_setup_psr(struct dmcu *dmcu,
+ struct core_link *link,
+ struct psr_context *psr_context)
+{
+ struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
+
+ unsigned int dmcu_max_retry_on_wait_reg_ready = 801;
+ unsigned int dmcu_wait_reg_ready_interval = 100;
+ unsigned int regValue;
+
+ union dce_dmcu_psr_config_data_reg1 masterCmdData1;
+ union dce_dmcu_psr_config_data_reg2 masterCmdData2;
+ union dce_dmcu_psr_config_data_reg3 masterCmdData3;
+
+ link->link_enc->funcs->psr_program_dp_dphy_fast_training(link->link_enc,
+ psr_context->psrExitLinkTrainingRequired);
+
+ /* Enable static screen interrupts for PSR supported display */
+ /* Disable the interrupt coming from other displays. */
+ REG_UPDATE_4(DMCU_INTERRUPT_TO_UC_EN_MASK,
+ STATIC_SCREEN1_INT_TO_UC_EN, 0,
+ STATIC_SCREEN2_INT_TO_UC_EN, 0,
+ STATIC_SCREEN3_INT_TO_UC_EN, 0,
+ STATIC_SCREEN4_INT_TO_UC_EN, 0);
+
+ switch (psr_context->controllerId) {
+ /* Driver uses case 1 for unconfigured */
+ case 1:
+ REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK,
+ STATIC_SCREEN1_INT_TO_UC_EN, 1);
+ break;
+ case 2:
+ REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK,
+ STATIC_SCREEN2_INT_TO_UC_EN, 1);
+ break;
+ case 3:
+ REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK,
+ STATIC_SCREEN3_INT_TO_UC_EN, 1);
+ break;
+ case 4:
+ REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK,
+ STATIC_SCREEN4_INT_TO_UC_EN, 1);
+ break;
+ case 5:
+ /* CZ/NL only has 4 CRTC!!
+ * really valid.
+ * There is no interrupt enable mask for these instances.
+ */
+ break;
+ case 6:
+ /* CZ/NL only has 4 CRTC!!
+ * These are here because they are defined in HW regspec,
+ * but not really valid. There is no interrupt enable mask
+ * for these instances.
+ */
+ break;
+ default:
+ REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK,
+ STATIC_SCREEN1_INT_TO_UC_EN, 1);
+ break;
+ }
+
+ link->link_enc->funcs->psr_program_secondary_packet(link->link_enc,
+ psr_context->sdpTransmitLineNumDeadline);
+
+ if (psr_context->psr_level.bits.SKIP_SMU_NOTIFICATION)
+ REG_UPDATE(SMU_INTERRUPT_CONTROL, DC_SMU_INT_ENABLE, 1);
+
+ /* waitDMCUReadyForCmd */
+ do {
+ dm_delay_in_microseconds(dmcu->ctx,
+ dmcu_wait_reg_ready_interval);
+ regValue = REG_READ(MASTER_COMM_CNTL_REG);
+ dmcu_max_retry_on_wait_reg_ready--;
+ } while
+ /* expected value is 0, loop while not 0*/
+ ((MASTER_COMM_CNTL_REG__MASTER_COMM_INTERRUPT_MASK & regValue) &&
+ dmcu_max_retry_on_wait_reg_ready > 0);
+
+ /* setDMCUParam_PSRHostConfigData */
+ masterCmdData1.u32All = 0;
+ masterCmdData1.bits.timehyst_frames = psr_context->timehyst_frames;
+ masterCmdData1.bits.hyst_lines = psr_context->hyst_lines;
+ masterCmdData1.bits.rfb_update_auto_en =
+ psr_context->rfb_update_auto_en;
+ masterCmdData1.bits.dp_port_num = psr_context->transmitterId;
+ masterCmdData1.bits.dcp_sel = psr_context->controllerId;
+ masterCmdData1.bits.phy_type = psr_context->phyType;
+ masterCmdData1.bits.frame_cap_ind =
+ psr_context->psrFrameCaptureIndicationReq;
+ masterCmdData1.bits.aux_chan = psr_context->channel;
+ masterCmdData1.bits.aux_repeat = psr_context->aux_repeats;
+ dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG1),
+ masterCmdData1.u32All);
+
+ masterCmdData2.u32All = 0;
+ masterCmdData2.bits.dig_fe = psr_context->engineId;
+ masterCmdData2.bits.dig_be = psr_context->transmitterId;
+ masterCmdData2.bits.skip_wait_for_pll_lock =
+ psr_context->skipPsrWaitForPllLock;
+ masterCmdData2.bits.frame_delay = psr_context->frame_delay;
+ masterCmdData2.bits.smu_phy_id = psr_context->smuPhyId;
+ masterCmdData2.bits.num_of_controllers =
+ psr_context->numberOfControllers;
+ dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG2),
+ masterCmdData2.u32All);
+
+ masterCmdData3.u32All = 0;
+ masterCmdData3.bits.psr_level = psr_context->psr_level.u32all;
+ dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG3),
+ masterCmdData3.u32All);
+
+ /* setDMCUParam_Cmd */
+ REG_UPDATE(MASTER_COMM_CMD_REG,
+ MASTER_COMM_CMD_REG_BYTE0, PSR_SET);
+
+ /* notifyDMCUMsg */
+ REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
+}
+
static const struct dmcu_funcs dce_funcs = {
.load_iram = dce_dmcu_load_iram,
+ .set_psr_enable = dce_dmcu_set_psr_enable,
+ .setup_psr = dce_dmcu_setup_psr,
};
static void dce_dmcu_construct(