android_kernel_xiaomi_sm8350/msm/sde_rsc_hw_v3.c
Dhaval Patel e05daba83d disp: msm: update clk and cmd state switch sequence
Disable double buffer vsync configuration while
enabling clk and cmd state switch sequence. Leaving
this configuration in enable state may cause different
issues for different state switch. Clock state switch
may see a vsync delay for solver disable. Command
state switch may not update the vsync source.

Change-Id: I910fc7e33a20a04b602435020173d85a4ee926d1
Signed-off-by: Dhaval Patel <pdhaval@codeaurora.org>
2019-06-12 10:39:39 -07:00

626 lines
19 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
*/
#define pr_fmt(fmt) "[sde_rsc_hw:%s:%d]: " fmt, __func__, __LINE__
#include <linux/kernel.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include "sde_rsc_priv.h"
#include "sde_rsc_hw.h"
#include "sde_dbg.h"
static int _rsc_hw_qtimer_init(struct sde_rsc_priv *rsc)
{
pr_debug("rsc hardware qtimer init\n");
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_QTMR_AC_HW_FRAME_SEL_1,
0xffffffff, rsc->debug_mode);
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_QTMR_AC_HW_FRAME_SEL_2,
0xffffffff, rsc->debug_mode);
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_QTMR_AC_CNTACR0_FG0,
0x1, rsc->debug_mode);
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_QTMR_AC_CNTACR1_FG0,
0x1, rsc->debug_mode);
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_LO,
0xffffffff, rsc->debug_mode);
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_HI,
0xffffffff, rsc->debug_mode);
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_LO,
0xffffffff, rsc->debug_mode);
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_HI,
0xffffffff, rsc->debug_mode);
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CTL,
0x1, rsc->debug_mode);
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CTL,
0x1, rsc->debug_mode);
return 0;
}
static int _rsc_hw_pdc_init(struct sde_rsc_priv *rsc)
{
pr_debug("rsc hardware pdc init\n");
dss_reg_w(&rsc->drv_io, SDE_RSCC_PDC_SEQ_START_ADDR_REG_OFFSET_DRV0,
0x4520, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSCC_PDC_MATCH_VALUE_LO_REG_OFFSET_DRV0,
0x4510, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSCC_PDC_MATCH_VALUE_HI_REG_OFFSET_DRV0,
0x4514, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSCC_PDC_SLAVE_ID_DRV0,
0x1, rsc->debug_mode);
return 0;
}
static int _rsc_hw_wrapper_init(struct sde_rsc_priv *rsc)
{
pr_debug("rsc hardware wrapper init\n");
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_STATIC_WAKEUP_0,
rsc->timer_config.static_wakeup_time_ns, rsc->debug_mode);
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_RSCC_MODE_THRESHOLD,
rsc->timer_config.rsc_mode_threshold_time_ns, rsc->debug_mode);
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL,
BIT(8), rsc->debug_mode);
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_MODE_MIN_THRESHOLD,
rsc->timer_config.min_threshold_time_ns, rsc->debug_mode);
return 0;
}
static int _rsc_hw_seq_memory_init_v3(struct sde_rsc_priv *rsc)
{
const u32 mode_0_start_addr = 0x0;
const u32 mode_1_start_addr = 0xc;
const u32 mode_2_start_addr = 0x18;
u32 br_offset = 0;
pr_debug("rsc sequencer memory init v2\n");
/* Mode - 0 sequence */
dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x0,
0xff399ebe, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x4,
0x20209ebe, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x8,
0x20202020, rsc->debug_mode);
/* Mode - 1 sequence */
dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0xc,
0xe0389ebe, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x10,
0x9ebeff39, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x14,
0x20202020, rsc->debug_mode);
/* Mode - 2 sequence */
dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x18,
0xfab9baa0, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x1c,
0x9afebdf9, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x20,
0xe1a13899, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x24,
0xa2e0ac81, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x28,
0x9d3982e2, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x2c,
0x20208cfd, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x30,
0x20202020, rsc->debug_mode);
/* tcs sleep & wake sequence */
dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x34,
0x01a6fcbc, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x38,
0x20209ce6, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x3c,
0x01a7fcbc, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x40,
0x00209ce7, rsc->debug_mode);
/* branch address */
if (rsc->hw_drv_ver >= SDE_RSC_HW_MAJOR_MINOR_STEP(2,0,5))
br_offset = 0xf0;
dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_CFG_BR_ADDR_0_DRV0 + br_offset,
0x34, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_CFG_BR_ADDR_1_DRV0 + br_offset,
0x3c, rsc->debug_mode);
/* start address */
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_OVERRIDE_CTRL_DRV0,
mode_0_start_addr,
rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM0_DRV0_MODE0,
mode_0_start_addr,
rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM0_DRV0_MODE1,
mode_1_start_addr,
rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM0_DRV0_MODE2,
mode_2_start_addr,
rsc->debug_mode);
return 0;
}
static int _rsc_hw_solver_init(struct sde_rsc_priv *rsc)
{
pr_debug("rsc solver init\n");
dss_reg_w(&rsc->drv_io, SDE_RSCC_SOFT_WAKEUP_TIME_LO_DRV0,
0xFFFFFFFF, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSCC_SOFT_WAKEUP_TIME_HI_DRV0,
0xFFFFFFFF, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSCC_MAX_IDLE_DURATION_DRV0,
0xEFFFFFFF, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_TIME_SLOT_TABLE_0_DRV0,
0x0, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_TIME_SLOT_TABLE_1_DRV0,
rsc->timer_config.bwi_threshold_time_ns, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_TIME_SLOT_TABLE_2_DRV0,
rsc->timer_config.rsc_time_slot_1_ns, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_TIME_SLOT_TABLE_3_DRV0,
rsc->timer_config.rsc_time_slot_2_ns, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_SOLVER_MODES_ENABLED_DRV0,
0x7, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PRI_TABLE_SLOT0_PRI0_DRV0,
0x0, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PRI_TABLE_SLOT1_PRI0_DRV0,
0x1, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PRI_TABLE_SLOT1_PRI3_DRV0,
0x1, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PRI_TABLE_SLOT2_PRI0_DRV0,
0x2, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PRI_TABLE_SLOT2_PRI3_DRV0,
0x2, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_OVERRIDE_MODE_DRV0,
0x0, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_TIMERS_CONSIDERED_DRV0,
0x1, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_OVERRIDE_IDLE_TIME_DRV0,
0x01000010, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM1_DRV0_MODE0,
0x80000000, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM2_DRV0_MODE0,
rsc->timer_config.rsc_backoff_time_ns, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE0,
rsc->timer_config.pdc_backoff_time_ns, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM1_DRV0_MODE1,
0x80000000, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM2_DRV0_MODE1,
rsc->timer_config.rsc_backoff_time_ns * 2,
rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE1,
rsc->timer_config.pdc_backoff_time_ns, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM1_DRV0_MODE2,
0x80000000, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM2_DRV0_MODE2,
0x0, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE2,
rsc->timer_config.pdc_backoff_time_ns, rsc->debug_mode);
return 0;
}
static int sde_rsc_mode2_entry_trigger(struct sde_rsc_priv *rsc)
{
int rc;
int count, wrapper_status, ctrl2_status;
unsigned long reg;
/* update qtimers to high during clk & video mode state */
if ((rsc->current_state == SDE_RSC_VID_STATE) ||
(rsc->current_state == SDE_RSC_CLK_STATE)) {
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_HI,
0xffffffff, rsc->debug_mode);
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_LO,
0xffffffff, rsc->debug_mode);
}
wrapper_status = dss_reg_r(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL,
rsc->debug_mode);
wrapper_status |= BIT(3);
wrapper_status |= BIT(0);
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL,
wrapper_status, rsc->debug_mode);
ctrl2_status = dss_reg_r(&rsc->wrapper_io,
SDE_RSCC_WRAPPER_OVERRIDE_CTRL2, rsc->debug_mode);
ctrl2_status &= ~BIT(3);
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL2,
ctrl2_status, rsc->debug_mode);
wmb(); /* make sure that vsync source is disabled */
/**
* force busy and idle during clk & video mode state because it
* is trying to entry in mode-2 without turning on the vysnc.
*/
if ((rsc->current_state == SDE_RSC_VID_STATE) ||
(rsc->current_state == SDE_RSC_CLK_STATE)) {
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL,
BIT(0) | BIT(1), rsc->debug_mode);
wmb(); /* force busy gurantee */
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL,
BIT(0) | BIT(9), rsc->debug_mode);
}
wmb(); /* make sure that mode-2 is triggered before wait*/
rc = -EBUSY;
/* this wait is required to turn off the rscc clocks */
for (count = MAX_CHECK_LOOPS; count > 0; count--) {
reg = dss_reg_r(&rsc->wrapper_io,
SDE_RSCC_PWR_CTRL, rsc->debug_mode);
if (test_bit(POWER_CTRL_BIT_12, &reg)) {
rc = 0;
break;
}
usleep_range(10, 100);
}
return rc;
}
static void sde_rsc_reset_mode_0_1(struct sde_rsc_priv *rsc)
{
u32 seq_busy, current_mode, curr_inst_addr;
seq_busy = dss_reg_r(&rsc->drv_io, SDE_RSCC_SEQ_BUSY_DRV0,
rsc->debug_mode);
current_mode = dss_reg_r(&rsc->drv_io, SDE_RSCC_SOLVER_STATUS2_DRV0,
rsc->debug_mode);
curr_inst_addr = dss_reg_r(&rsc->drv_io, SDE_RSCC_SEQ_PROGRAM_COUNTER,
rsc->debug_mode);
SDE_EVT32(seq_busy, current_mode, curr_inst_addr);
if (seq_busy && (current_mode == SDE_RSC_MODE_0_VAL ||
current_mode == SDE_RSC_MODE_1_VAL)) {
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_HI,
0xffffff, rsc->debug_mode);
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_LO,
0xffffffff, rsc->debug_mode);
wmb(); /* unstick f1 qtimer */
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_HI,
0x0, rsc->debug_mode);
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_LO,
0x0, rsc->debug_mode);
wmb(); /* manually trigger f1 qtimer interrupt */
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_HI,
0xffffff, rsc->debug_mode);
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_LO,
0xffffffff, rsc->debug_mode);
wmb(); /* unstick f0 qtimer */
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_HI,
0x0, rsc->debug_mode);
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_LO,
0x0, rsc->debug_mode);
wmb(); /* manually trigger f0 qtimer interrupt */
}
}
static int sde_rsc_mode2_entry_v3(struct sde_rsc_priv *rsc)
{
int rc = 0, i;
u32 reg;
if (rsc->power_collapse_block)
return -EINVAL;
if (rsc->sw_fs_enabled) {
rc = regulator_set_mode(rsc->fs, REGULATOR_MODE_FAST);
if (rc) {
pr_err("vdd reg fast mode set failed rc:%d\n", rc);
return rc;
}
}
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_SOLVER_MODES_ENABLED_DRV0,
0x7, rsc->debug_mode);
for (i = 0; i <= MAX_MODE2_ENTRY_TRY; i++) {
rc = sde_rsc_mode2_entry_trigger(rsc);
if (!rc)
break;
reg = dss_reg_r(&rsc->drv_io,
SDE_RSCC_SEQ_PROGRAM_COUNTER, rsc->debug_mode);
pr_err("mdss gdsc power down failed, instruction:0x%x, rc:%d\n",
reg, rc);
SDE_EVT32(rc, reg, SDE_EVTLOG_ERROR);
/* avoid touching f1 qtimer for last try */
if (i != MAX_MODE2_ENTRY_TRY)
sde_rsc_reset_mode_0_1(rsc);
}
if (rc)
goto end;
if ((rsc->current_state == SDE_RSC_VID_STATE) ||
(rsc->current_state == SDE_RSC_CLK_STATE)) {
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL,
BIT(0) | BIT(8), rsc->debug_mode);
wmb(); /* force busy on vsync */
}
if (rsc->sw_fs_enabled) {
regulator_disable(rsc->fs);
rsc->sw_fs_enabled = false;
}
return 0;
end:
sde_rsc_mode2_exit(rsc, rsc->current_state);
return rc;
}
static int sde_rsc_state_update_v3(struct sde_rsc_priv *rsc,
enum sde_rsc_state state)
{
int rc = 0;
int reg, ctrl2_config;
if (rsc->power_collapse) {
rc = sde_rsc_mode2_exit(rsc, state);
if (rc)
pr_err("power collapse: mode2 exit failed\n");
else
rsc->power_collapse = false;
}
switch (state) {
case SDE_RSC_CMD_STATE:
pr_debug("command mode handling\n");
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL,
0x0, rsc->debug_mode);
wmb(); /* disable double buffer config before vsync select */
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL2,
BIT(1) | BIT(2) | BIT(3), rsc->debug_mode);
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL,
0x1, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSCC_SOLVER_OVERRIDE_CTRL_DRV0,
0x0, rsc->debug_mode);
reg = dss_reg_r(&rsc->wrapper_io,
SDE_RSCC_WRAPPER_OVERRIDE_CTRL, rsc->debug_mode);
reg |= (BIT(0) | BIT(8));
reg &= ~(BIT(1) | BIT(2) | BIT(3) | BIT(6) | BIT(7) | BIT(9));
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL,
reg, rsc->debug_mode);
wmb(); /* make sure that solver is enabled */
break;
case SDE_RSC_VID_STATE:
pr_debug("video mode handling\n");
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL,
0x0, rsc->debug_mode);
wmb(); /* disable double buffer config before vsync select */
ctrl2_config = (rsc->vsync_source & 0x7) << 4;
ctrl2_config |= (BIT(0) | BIT(1) | BIT(3));
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL2,
ctrl2_config, rsc->debug_mode);
wmb(); /* select vsync before double buffer config enabled */
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL,
0x1, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSCC_SOLVER_OVERRIDE_CTRL_DRV0,
0x0, rsc->debug_mode);
reg = dss_reg_r(&rsc->wrapper_io,
SDE_RSCC_WRAPPER_OVERRIDE_CTRL, rsc->debug_mode);
reg |= (BIT(0) | BIT(8));
reg &= ~(BIT(1) | BIT(2) | BIT(3) | BIT(6) | BIT(7) | BIT(9));
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL,
reg, rsc->debug_mode);
wmb(); /* make sure that solver is enabled */
break;
case SDE_RSC_CLK_STATE:
pr_debug("clk state handling\n");
ctrl2_config = dss_reg_r(&rsc->wrapper_io,
SDE_RSCC_WRAPPER_OVERRIDE_CTRL2, rsc->debug_mode);
ctrl2_config &= ~(BIT(0) | BIT(1) | BIT(2));
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL2,
ctrl2_config, rsc->debug_mode);
reg = dss_reg_r(&rsc->wrapper_io,
SDE_RSCC_WRAPPER_OVERRIDE_CTRL, rsc->debug_mode);
reg &= ~(BIT(0) | BIT(8));
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL,
reg, rsc->debug_mode);
wmb(); /* make sure that solver mode is disabled */
reg = dss_reg_r(&rsc->wrapper_io,
SDE_RSCC_WRAPPER_OVERRIDE_CTRL, rsc->debug_mode);
reg |= BIT(8);
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL,
reg, rsc->debug_mode);
wmb(); /* enable double buffer vsync configuration */
break;
case SDE_RSC_IDLE_STATE:
rc = sde_rsc_mode2_entry_v3(rsc);
if (rc)
pr_err("power collapse - mode 2 entry failed\n");
else
rsc->power_collapse = true;
break;
default:
pr_err("state:%d handling is not supported\n", state);
break;
}
return rc;
}
int rsc_hw_init_v3(struct sde_rsc_priv *rsc)
{
int rc = 0;
rsc->hw_drv_ver = dss_reg_r(&rsc->drv_io,
SDE_RSCC_RSC_ID_DRV0, rsc->debug_mode);
rc = _rsc_hw_qtimer_init(rsc);
if (rc) {
pr_err("rsc hw qtimer init failed\n");
goto end;
}
rc = _rsc_hw_wrapper_init(rsc);
if (rc) {
pr_err("rsc hw wrapper init failed\n");
goto end;
}
rc = _rsc_hw_seq_memory_init_v3(rsc);
if (rc) {
pr_err("rsc sequencer memory init failed\n");
goto end;
}
rc = _rsc_hw_solver_init(rsc);
if (rc) {
pr_err("rsc solver init failed\n");
goto end;
}
rc = _rsc_hw_pdc_init(rsc);
if (rc) {
pr_err("rsc hw pdc init failed\n");
goto end;
}
wmb(); /* make sure that hw is initialized */
pr_info("sde rsc init successfully done\n");
end:
return rc;
}
int rsc_hw_bwi_status_v3(struct sde_rsc_priv *rsc, bool bw_indication)
{
int count, bw_ack;
int rc = 0;
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_BW_INDICATION,
bw_indication, rsc->debug_mode);
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL,
0x1, rsc->debug_mode);
bw_ack = dss_reg_r(&rsc->wrapper_io, SDE_RSCC_WRAPPER_DEBUG_CTRL2,
rsc->debug_mode) & BIT(14);
/* check for sequence running status before exiting */
for (count = MAX_CHECK_LOOPS; count > 0 && !bw_ack; count--) {
usleep_range(8, 10);
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_BW_INDICATION,
bw_indication, rsc->debug_mode);
bw_ack = dss_reg_r(&rsc->wrapper_io,
SDE_RSCC_WRAPPER_DEBUG_CTRL2, rsc->debug_mode) & BIT(14);
}
if (!bw_ack)
rc = -EINVAL;
return rc;
}
static int rsc_hw_timer_update_v3(struct sde_rsc_priv *rsc)
{
if (!rsc) {
pr_debug("invalid input param\n");
return -EINVAL;
}
pr_debug("rsc hw timer update\n");
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_TIME_SLOT_TABLE_1_DRV0,
rsc->timer_config.rsc_time_slot_0_ns, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_TIME_SLOT_TABLE_2_DRV0,
rsc->timer_config.rsc_time_slot_1_ns, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_TIME_SLOT_TABLE_3_DRV0,
rsc->timer_config.rsc_time_slot_2_ns, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM2_DRV0_MODE0,
rsc->timer_config.rsc_backoff_time_ns, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE0,
rsc->timer_config.pdc_backoff_time_ns, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM2_DRV0_MODE1,
rsc->timer_config.rsc_backoff_time_ns * 2,
rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE1,
rsc->timer_config.pdc_backoff_time_ns, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE2,
rsc->timer_config.pdc_backoff_time_ns, rsc->debug_mode);
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_STATIC_WAKEUP_0,
rsc->timer_config.static_wakeup_time_ns, rsc->debug_mode);
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_RSCC_MODE_THRESHOLD,
rsc->timer_config.rsc_mode_threshold_time_ns, rsc->debug_mode);
/* make sure that hw timers are updated */
wmb();
return 0;
}
int sde_rsc_hw_register_v3(struct sde_rsc_priv *rsc)
{
pr_debug("rsc hardware register v3\n");
rsc->hw_ops.init = rsc_hw_init_v3;
rsc->hw_ops.state_update = sde_rsc_state_update_v3;
rsc->hw_ops.bwi_status = rsc_hw_bwi_status_v3;
rsc->hw_ops.timer_update = rsc_hw_timer_update_v3;
rsc->hw_ops.tcs_wait = rsc_hw_tcs_wait;
rsc->hw_ops.tcs_use_ok = rsc_hw_tcs_use_ok;
rsc->hw_ops.is_amc_mode = rsc_hw_is_amc_mode;
rsc->hw_ops.hw_vsync = rsc_hw_vsync;
rsc->hw_ops.debug_show = sde_rsc_debug_show;
rsc->hw_ops.mode_ctrl = rsc_hw_mode_ctrl;
rsc->hw_ops.debug_dump = rsc_hw_debug_dump;
return 0;
}