drm/msm: support backoff time update only in sde rsc

SDE RSC driver updates the complete RSC configuration when
client requests for only timer updates like static wrapper
or pdc/rsc backoff time. This may reset unintentional settings
on SDE rsc while client calls it during dynamic resolution
switch or inline rotation. This patch adds a new API to update
only timer configuration on sde rsc with new client settings.

Change-Id: I15c0e75cc4008431dc622dcf29085e9839dee15d
Signed-off-by: Dhaval Patel <pdhaval@codeaurora.org>
diff --git a/drivers/gpu/drm/msm/sde_rsc.c b/drivers/gpu/drm/msm/sde_rsc.c
index 0418644..7a52ece 100644
--- a/drivers/gpu/drm/msm/sde_rsc.c
+++ b/drivers/gpu/drm/msm/sde_rsc.c
@@ -404,7 +404,13 @@
 	/* mode 2 is infinite */
 	rsc->timer_config.rsc_time_slot_2_ns = 0xFFFFFFFF;
 
-	if (rsc->hw_ops.init) {
+	/* timer update should be called with client call */
+	if (cmd_config && rsc->hw_ops.timer_update) {
+		ret = rsc->hw_ops.timer_update(rsc);
+		if (ret)
+			pr_err("sde rsc: hw timer update failed ret:%d\n", ret);
+	/* rsc init should be called during rsc probe - one time only */
+	} else if (rsc->hw_ops.init) {
 		ret = rsc->hw_ops.init(rsc);
 		if (ret)
 			pr_err("sde rsc: hw init failed ret:%d\n", ret);
@@ -917,7 +923,7 @@
 
 end:
 	mutex_unlock(&rsc->client_lock);
-	if (blen < 0)
+	if (blen <= 0)
 		return 0;
 
 	if (copy_to_user(buf, buffer, blen))
@@ -1009,7 +1015,7 @@
 
 end:
 	mutex_unlock(&rsc->client_lock);
-	if (blen < 0)
+	if (blen <= 0)
 		return 0;
 
 	if (copy_to_user(buf, buffer, blen))
diff --git a/drivers/gpu/drm/msm/sde_rsc_hw.c b/drivers/gpu/drm/msm/sde_rsc_hw.c
index 4b61def..b474d21 100644
--- a/drivers/gpu/drm/msm/sde_rsc_hw.c
+++ b/drivers/gpu/drm/msm/sde_rsc_hw.c
@@ -296,6 +296,47 @@
 	return 0;
 }
 
+static int rsc_hw_timer_update(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, 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;
+}
+
 static int sde_rsc_mode2_exit(struct sde_rsc_priv *rsc,
 						enum sde_rsc_state state)
 {
@@ -755,6 +796,7 @@
 	pr_debug("rsc hardware register\n");
 
 	rsc->hw_ops.init = rsc_hw_init;
+	rsc->hw_ops.timer_update = rsc_hw_timer_update;
 
 	rsc->hw_ops.tcs_wait = rsc_hw_tcs_wait;
 	rsc->hw_ops.tcs_use_ok = rsc_hw_tcs_use_ok;
diff --git a/drivers/gpu/drm/msm/sde_rsc_priv.h b/drivers/gpu/drm/msm/sde_rsc_priv.h
index fe338d37..c96ce75 100644
--- a/drivers/gpu/drm/msm/sde_rsc_priv.h
+++ b/drivers/gpu/drm/msm/sde_rsc_priv.h
@@ -66,6 +66,8 @@
  * struct sde_rsc_hw_ops - sde resource state coordinator hardware ops
  * @init:			Initialize the sequencer, solver, qtimer,
 				etc. hardware blocks on RSC.
+ * @timer_update:		update the static wrapper time and pdc/rsc
+				backoff time.
  * @tcs_wait:			Waits for TCS block OK to allow sending a
  *				TCS command.
  * @hw_vsync:			Enables the vsync on RSC block.
@@ -79,6 +81,7 @@
 
 struct sde_rsc_hw_ops {
 	int (*init)(struct sde_rsc_priv *rsc);
+	int (*timer_update)(struct sde_rsc_priv *rsc);
 	int (*tcs_wait)(struct sde_rsc_priv *rsc);
 	int (*hw_vsync)(struct sde_rsc_priv *rsc, enum rsc_vsync_req request,
 		char *buffer, int buffer_size, u32 mode);