Refine VSP power management

BUG: 22602467

Replace the legacy ospm_apm_power_down_vsp with the new framework/power_island_put
Add recovery logic when VSP hang

Change-Id: I03bafc9d9db315aae7ad53638ebd643b1830f4d5
Signed-off-by: hding3 <haitao.ding@intel.com>
diff --git a/drivers/external_drivers/intel_media/display/tng/drv/ospm/pwr_mgmt.c b/drivers/external_drivers/intel_media/display/tng/drv/ospm/pwr_mgmt.c
index ad4c080..2b124cb 100755
--- a/drivers/external_drivers/intel_media/display/tng/drv/ospm/pwr_mgmt.c
+++ b/drivers/external_drivers/intel_media/display/tng/drv/ospm/pwr_mgmt.c
@@ -811,6 +811,7 @@
 	struct ospm_power_island *p_island;
 	struct drm_psb_private *dev_priv = dev->dev_private;
 	struct vsp_private *vsp_priv = dev_priv->vsp_private;
+	int island_ref;
 
 	PSB_DEBUG_PM("Power down VPP...\n");
 	p_island = get_island_ptr(OSPM_VIDEO_VPP_ISLAND);
@@ -825,9 +826,10 @@
 	if (!ospm_power_is_hw_on(OSPM_VIDEO_VPP_ISLAND))
 		goto out;
 
-	if (atomic_read(&p_island->ref_count))
+	island_ref = atomic_read(&p_island->ref_count);
+	if (island_ref)
 		PSB_DEBUG_PM("VPP ref_count has been set(%d), bypass\n",
-			     atomic_read(&p_island->ref_count));
+			     island_ref);
 
 	if (vsp_priv->vsp_cmd_num > 0) {
 		VSP_DEBUG("command in VSP, by pass\n");
@@ -847,11 +849,16 @@
 	/* handle the dependency */
 	if (p_island->p_dependency) {
 		/* Power down dependent island */
-		power_down_island(p_island->p_dependency);
+		do {
+			power_down_island(p_island->p_dependency);
+			island_ref--;
+		} while (island_ref);
 	}
 
 	if (!any_island_on()) {
 		PSB_DEBUG_PM("Suspending PCI\n");
+		pm_qos_add_request(&dev_priv->s0ix_qos,
+				   PM_QOS_CPU_DMA_LATENCY, CSTATE_EXIT_LATENCY_S0i1 - 1);
 		pm_runtime_put(&g_ospm_data->dev->pdev->dev);
 		wake_unlock(&dev_priv->ospm_wake_lock);
 	}
diff --git a/drivers/external_drivers/intel_media/video/common/psb_cmdbuf.c b/drivers/external_drivers/intel_media/video/common/psb_cmdbuf.c
index 65579de..3943c84 100644
--- a/drivers/external_drivers/intel_media/video/common/psb_cmdbuf.c
+++ b/drivers/external_drivers/intel_media/video/common/psb_cmdbuf.c
@@ -836,8 +836,10 @@
 			}
 
 			if (__copy_to_user(vbuf->user_val_arg,
-					   &arg, sizeof(arg)))
+					   &arg, sizeof(arg))) {
 				err = -EFAULT;
+				DRM_ERROR("call __copy_to_user() function error!\n");
+			}
 
 			if (arg.ret)
 				break;
diff --git a/drivers/external_drivers/intel_media/video/vsp/vsp.c b/drivers/external_drivers/intel_media/video/vsp/vsp.c
index 3a00fc9..15b5404 100755
--- a/drivers/external_drivers/intel_media/video/vsp/vsp.c
+++ b/drivers/external_drivers/intel_media/video/vsp/vsp.c
@@ -73,6 +73,43 @@
 	__asm__ __volatile__("wbinvd ");
 }
 
+
+static inline void force_power_down_vsp(void)
+{
+	int count = 0;
+	VSP_DEBUG("Force to power down VSP\n");
+	while (is_island_on(OSPM_VIDEO_VPP_ISLAND) && (count < 255)) {
+		count++;
+		VSP_DEBUG("The VSP is on, power down it, tries %d\n", count);
+		power_island_put(OSPM_VIDEO_VPP_ISLAND);
+	}
+	VSP_DEBUG("The VSP is off now (tried %d times)\n", count);
+}
+
+static inline void power_down_vsp(void)
+{
+	VSP_DEBUG("Try to power down VSP\n");
+
+	if (is_island_on(OSPM_VIDEO_VPP_ISLAND)) {
+		VSP_DEBUG("The VSP is on, power down it\n");
+		power_island_put(OSPM_VIDEO_VPP_ISLAND);
+	} else
+		VSP_DEBUG("The VSP is already off\n");
+}
+
+static inline void power_up_vsp(void)
+{
+	VSP_DEBUG("Try to power up VSP\n");
+
+	if (is_island_on(OSPM_VIDEO_VPP_ISLAND))
+		VSP_DEBUG("The VSP is alraedy on\n");
+	else {
+		VSP_DEBUG("The VSP is off, power up it\n");
+		power_island_get(OSPM_VIDEO_VPP_ISLAND);
+	}
+}
+
+
 int vsp_handle_response(struct drm_psb_private *dev_priv)
 {
 	struct vsp_private *vsp_priv = dev_priv->vsp_private;
@@ -311,8 +348,13 @@
 
 	/* If VSP timeout, don't send cmd to hardware anymore */
 	if (vsp_priv->vsp_state == VSP_STATE_HANG) {
-		DRM_ERROR("The VSP is hang abnormally!");
-		return -EFAULT;
+		DRM_ERROR("The VSP is hang abnormally, try to reset vsp hardware!\n");
+
+		VSP_DEBUG("Force state to DOWN to force power down\n");
+		vsp_priv->ctrl->entry_kind = vsp_exit;
+		vsp_priv->vsp_state = VSP_STATE_DOWN;
+		force_power_down_vsp();
+		//return -EFAULT;
 	}
 
 	memset(&cmd_kmap, 0, sizeof(cmd_kmap));
@@ -358,8 +400,9 @@
 	if (drm_vsp_vpp_batch_cmd == 0)
 		vsp_priv->force_flush_cmd = 1;
 
-	if (vsp_priv->vsp_state == VSP_STATE_IDLE)
-		ospm_apm_power_down_vsp(dev);
+        if ((drm_vsp_pmpolicy != PSB_PMPOLICY_NOPM) &&
+	    (vsp_priv->vsp_state == VSP_STATE_IDLE))
+		power_down_vsp();
 
 	if (vsp_priv->acc_num_cmd >= 1 || vsp_priv->force_flush_cmd != 0
 	    || vsp_priv->delayed_burst_cnt > 0) {
@@ -1108,7 +1151,7 @@
 	mutex_unlock(&vsp_priv->vsp_mutex);
 
 	VSP_DEBUG("context_vp8_num %d, context_vpp_num %d\n",
-			vsp_priv->context_vp8_num, vsp_priv->context_vpp_num);
+		  vsp_priv->context_vp8_num, vsp_priv->context_vpp_num);
 	return ret;
 }
 
@@ -1116,7 +1159,6 @@
 {
 	struct drm_psb_private *dev_priv = dev->dev_private;
 	struct vsp_private *vsp_priv = dev_priv->vsp_private;
-	bool ret = true;
 	int count = 0;
 	struct vss_command_t *cur_cmd;
 	bool tmp = true;
@@ -1153,11 +1195,10 @@
 
 	VSP_DEBUG("ctx_type=%d\n", ctx_type);
 
+	/* power on the VSP hardware to write registers */
+	power_up_vsp();
+
 	if (VAEntrypointEncSlice == ctx_type && filp != vsp_priv->vp8_filp[3]) {
-		/* power on again to send VssGenDestroyContext to firmware */
-		if (power_island_get(OSPM_VIDEO_VPP_ISLAND) == false) {
-			tmp = -EBUSY;
-		}
 		if (vsp_priv->vsp_state == VSP_STATE_SUSPEND) {
 			tmp = vsp_resume_function(dev_priv);
 			VSP_DEBUG("The VSP is on suspend, send resume!\n");
@@ -1217,26 +1258,26 @@
 	if (vsp_priv->context_vp8_num > 0 || vsp_priv->context_vpp_num > 0) {
 		VSP_DEBUG("context_vp8_num %d, context_vpp_num %d\n",
 			vsp_priv->context_vp8_num, vsp_priv->context_vpp_num);
+
+		power_down_vsp();
 		mutex_unlock(&vsp_priv->vsp_mutex);
 		return;
 	}
 
 	vsp_priv->ctrl->entry_kind = vsp_exit;
-	mutex_unlock(&vsp_priv->vsp_mutex);
-        VSP_DEBUG("After mutex_unlock, start to power off VSP!\n");
 
+	VSP_DEBUG("No context now, set state to DOWN to force power down\n");
+	PSB_UDELAY(800);
+	
 	/* in case of power mode 0, HW always active,
 	 * * in case got no response from FW, vsp_state=hang but could not be powered off,
 	 * * force state to down */
 	vsp_priv->vsp_state = VSP_STATE_DOWN;
-	ospm_apm_power_down_vsp(dev);
+	force_power_down_vsp();
 	vsp_priv->vsp_state = VSP_STATE_DOWN;
 
-	if (ret == false)
-		PSB_DEBUG_PM("Couldn't power down VSP!");
-	else
-		PSB_DEBUG_PM("VSP: OK. Power down the HW!\n");
-
+	mutex_unlock(&vsp_priv->vsp_mutex);
+	VSP_DEBUG("vsp_rm_context is successful\n");
 	/* FIXME: frequency should change */
 	VSP_PERF("the total time spend on VSP is %llu ms\n",
 		 div_u64(vsp_priv->vss_cc_acc, 200 * 1000));
@@ -1376,15 +1417,17 @@
 			  sequence, vsp_priv->current_sequence);
 	}
 
-	if (vsp_priv->vsp_state == VSP_STATE_IDLE) {
-		if (vsp_priv->ctrl->cmd_rd == vsp_priv->ctrl->cmd_wr)
-			ospm_apm_power_down_vsp(dev);
-		else {
-			while (ospm_power_is_hw_on(OSPM_VIDEO_VPP_ISLAND))
-				ospm_apm_power_down_vsp(dev);
-			VSP_DEBUG("successfully power down VSP\n");
-			power_island_get(OSPM_VIDEO_VPP_ISLAND);
-			vsp_resume_function(dev_priv);
+	if (drm_vsp_pmpolicy != PSB_PMPOLICY_NOPM){
+		if (vsp_priv->vsp_state == VSP_STATE_IDLE) {
+			if (vsp_priv->ctrl->cmd_rd == vsp_priv->ctrl->cmd_wr)
+				power_down_vsp();
+			else {
+				force_power_down_vsp();
+
+				VSP_DEBUG("Now power up VSP again to resume\n");
+				power_up_vsp();
+				vsp_resume_function(dev_priv);
+			}
 		}
 	}
 	mutex_unlock(&vsp_priv->vsp_mutex);
diff --git a/drivers/external_drivers/intel_media/video/vsp/vsp_fw.h b/drivers/external_drivers/intel_media/video/vsp/vsp_fw.h
index 064a053..89b8889 100644
--- a/drivers/external_drivers/intel_media/video/vsp/vsp_fw.h
+++ b/drivers/external_drivers/intel_media/video/vsp/vsp_fw.h
@@ -578,6 +578,8 @@
 	uint32_t cyclic_intra_refresh;
 	uint32_t concatenate_partitions;
 	uint32_t recon_buffer_mode;
+	uint32_t generate_skip_frames;
+	uint32_t max_num_dropped_frames;
 	uint32_t ts_number_layers;
 	uint32_t ts_target_bitrate[3];
 	uint32_t ts_rate_decimator[3];
@@ -596,8 +598,9 @@
 	uint32_t quantizer[4];
 	uint32_t frame_flags;
 	uint32_t partition_id;
-	uint32_t buffer_level;
+	uint32_t buffer_level[3];
 	uint32_t quality;
+	uint32_t overflow_bytes;
 	uint32_t surfaceId_of_ref_frame[4];
 	uint32_t reserved[15];
 	uint32_t coded_data[1];