msm: camera: isp: Enable/Disable IFE SAFE to SMMU

Enable/Disable the IFE SAFE signal to SMMU Hardware through
SCM call to Hypervisor, Enable SAFE before starting the IFE
Hardware and Disable it after stopping the IFE Hardware. This
is to work around the Hardware bug, that is incorrectly
clamping the SAFE signal externally due to wrong
power on reset values of SAFE LUTs. The SCM call needs to be
invoked to enable SAFE before starting first IFE Hardware
instance, disable SAFE to be invoked only after stoping all
the IFE HW instances, hence it is ref counted with active
context count.

Change-Id: I0889c53d0e824592d67f0207c9163f2564a80259
Signed-off-by: Harsh Shah <harshs@codeaurora.org>
Signed-off-by: Rajesh Sastrula <vrajesh@codeaurora.org>
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/Makefile b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/Makefile
index 7e3c353..1f7dc76 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/Makefile
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/Makefile
@@ -8,6 +8,7 @@
 ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller
 ccflags-y += -Idrivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include
 ccflags-y += -Idrivers/media/platform/msm/camera/cam_smmu/
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cpas/include
 
 obj-$(CONFIG_SPECTRA_CAMERA) += hw_utils/ isp_hw/
 obj-$(CONFIG_SPECTRA_CAMERA) += cam_isp_hw_mgr.o cam_ife_hw_mgr.o
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
index 6e93b06..29a99b2 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
@@ -14,6 +14,7 @@
 #include <linux/string.h>
 #include <linux/uaccess.h>
 #include <linux/debugfs.h>
+#include <soc/qcom/scm.h>
 #include <uapi/media/cam_isp.h>
 #include "cam_smmu_api.h"
 #include "cam_req_mgr_workq.h"
@@ -26,11 +27,50 @@
 #include "cam_cdm_intf_api.h"
 #include "cam_packet_util.h"
 #include "cam_debug_util.h"
+#include "cam_cpas_api.h"
 
 #define CAM_IFE_HW_ENTRIES_MAX  20
 
+#define TZ_SVC_SMMU_PROGRAM 0x15
+#define TZ_SAFE_SYSCALL_ID  0x3
+#define CAM_IFE_SAFE_DISABLE 0
+#define CAM_IFE_SAFE_ENABLE 1
+#define SMMU_SE_IFE 0
+
 static struct cam_ife_hw_mgr g_ife_hw_mgr;
 
+static int cam_ife_notify_safe_lut_scm(bool safe_trigger)
+{
+	uint32_t camera_hw_version, rc = 0;
+	struct scm_desc desc = {0};
+
+	rc = cam_cpas_get_cpas_hw_version(&camera_hw_version);
+	if (!rc) {
+		switch (camera_hw_version) {
+		case CAM_CPAS_TITAN_170_V100:
+		case CAM_CPAS_TITAN_170_V110:
+		case CAM_CPAS_TITAN_175_V100:
+
+			desc.arginfo = SCM_ARGS(2, SCM_VAL, SCM_VAL);
+			desc.args[0] = SMMU_SE_IFE;
+			desc.args[1] = safe_trigger;
+
+			CAM_DBG(CAM_ISP, "Safe scm call %d", safe_trigger);
+			if (scm_call2(SCM_SIP_FNID(TZ_SVC_SMMU_PROGRAM,
+					TZ_SAFE_SYSCALL_ID), &desc)) {
+				CAM_ERR(CAM_ISP,
+					"scm call to Enable Safe failed");
+				rc = -EINVAL;
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+	return rc;
+}
+
 static int cam_ife_mgr_get_hw_caps(void *hw_mgr_priv,
 	void *hw_caps_args)
 {
@@ -1600,6 +1640,17 @@
 
 	CAM_DBG(CAM_ISP, "Exit...ctx id:%d rc :%d", ctx->ctx_index, rc);
 
+	mutex_lock(&g_ife_hw_mgr.ctx_mutex);
+	if (!atomic_dec_return(&g_ife_hw_mgr.active_ctx_cnt)) {
+		rc = cam_ife_notify_safe_lut_scm(CAM_IFE_SAFE_DISABLE);
+		if (rc) {
+			CAM_ERR(CAM_ISP,
+				"SAFE SCM call failed:Check TZ/HYP dependency");
+			rc = 0;
+		}
+	}
+	mutex_unlock(&g_ife_hw_mgr.ctx_mutex);
+
 	return rc;
 }
 
@@ -1808,6 +1859,17 @@
 		}
 	}
 
+	mutex_lock(&g_ife_hw_mgr.ctx_mutex);
+	if (!atomic_fetch_inc(&g_ife_hw_mgr.active_ctx_cnt)) {
+		rc = cam_ife_notify_safe_lut_scm(CAM_IFE_SAFE_ENABLE);
+		if (rc) {
+			CAM_ERR(CAM_ISP,
+				"SAFE SCM call failed:Check TZ/HYP dependency");
+			rc = -1;
+		}
+	}
+	mutex_unlock(&g_ife_hw_mgr.ctx_mutex);
+
 	CAM_DBG(CAM_ISP, "start cdm interface");
 	rc = cam_cdm_stream_on(ctx->cdm_handle);
 	if (rc) {
@@ -3414,6 +3476,7 @@
 		g_ife_hw_mgr.mgr_common.cmd_iommu_hdl_secure = -1;
 	}
 
+	atomic_set(&g_ife_hw_mgr.active_ctx_cnt, 0);
 	for (i = 0; i < CAM_CTX_MAX; i++) {
 		memset(&g_ife_hw_mgr.ctx_pool[i], 0,
 			sizeof(g_ife_hw_mgr.ctx_pool[i]));
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h
index 2e66210..4faa2f3 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h
@@ -179,6 +179,7 @@
 	struct cam_soc_reg_map        *cdm_reg_map[CAM_IFE_HW_NUM_MAX];
 
 	struct mutex                   ctx_mutex;
+	atomic_t                       active_ctx_cnt;
 	struct list_head               free_ctx_list;
 	struct list_head               used_ctx_list;
 	struct cam_ife_hw_mgr_ctx      ctx_pool[CAM_CTX_MAX];
@@ -186,8 +187,8 @@
 	struct cam_ife_csid_hw_caps    ife_csid_dev_caps[
 						CAM_IFE_CSID_HW_NUM_MAX];
 	struct cam_vfe_hw_get_hw_cap   ife_dev_caps[CAM_IFE_HW_NUM_MAX];
-	struct cam_req_mgr_core_workq  *workq;
-	struct cam_ife_hw_mgr_debug     debug_cfg;
+	struct cam_req_mgr_core_workq *workq;
+	struct cam_ife_hw_mgr_debug    debug_cfg;
 };
 
 /**