Przeglądaj źródła

msm: camera: isp: Change TPGv3 acquire implementation

Fix the TPG version 3 reserve function to utilize all the 16
unique VC and DT combination support. Add functionality to be
 able to reserve TPG version 3 multiple times for future
multi camera usecase.

CRs-Fixed: 2823940
Change-Id: Ib5cadc5398c78f110a8a768932d65de3bd849309
Signed-off-by: Jigar Agrawal <[email protected]>
Jigar Agrawal 4 lat temu
rodzic
commit
af624ce693

+ 35 - 29
drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c

@@ -2945,38 +2945,42 @@ static int cam_ife_hw_mgr_acquire_tpg(
 	uint32_t                                 num_inport)
 {
 	int rc = -EINVAL;
-	uint32_t i;
+	uint32_t i = 0;
 	struct cam_ife_hw_mgr *ife_hw_mgr;
 	struct cam_hw_intf *hw_intf;
-	struct cam_top_tpg_ver2_reserve_args tpg_reserve;
+	struct cam_top_tpg_reserve_args tpg_reserve;
 
 	ife_hw_mgr = ife_ctx->hw_mgr;
 
-	for (i = 0; i < CAM_TOP_TPG_HW_NUM_MAX; i++) {
-		if (!ife_hw_mgr->tpg_devices[i])
-			continue;
+	tpg_reserve.num_inport = num_inport;
+	tpg_reserve.node_res = NULL;
+	if ((num_inport > 0) &&
+		(num_inport <= CAM_TOP_TPG_MAX_SUPPORTED_IN_PORTS)){
+		for (i = 0; i < num_inport; i++)
+			tpg_reserve.in_port[i] = (in_port + i);
 
-		hw_intf = ife_hw_mgr->tpg_devices[i];
-		tpg_reserve.num_inport = num_inport;
-		tpg_reserve.node_res = NULL;
-		tpg_reserve.in_port = in_port;
+		for (i = 0; i < CAM_TOP_TPG_HW_NUM_MAX; i++) {
+			if (!ife_hw_mgr->tpg_devices[i])
+				continue;
 
-		rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv,
-			&tpg_reserve, sizeof(tpg_reserve));
-		if (!rc)
-			break;
+			hw_intf = ife_hw_mgr->tpg_devices[i];
+			rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv,
+				&tpg_reserve, sizeof(tpg_reserve));
+			if (!rc)
+				break;
+		}
 	}
 
-	if (i == CAM_TOP_TPG_HW_NUM_MAX || !tpg_reserve.node_res) {
-		CAM_ERR(CAM_ISP, "Can not acquire IFE TPG");
+	if ((i == CAM_TOP_TPG_HW_NUM_MAX) || !tpg_reserve.node_res) {
+		CAM_ERR(CAM_ISP,
+			"Can not acquire IFE TPG. rc:%d, num_inports:%u",
+			rc, num_inport);
 		rc = -EINVAL;
 		goto end;
 	}
 
-	ife_ctx->res_list_tpg.res_type = in_port->res_type;
 	ife_ctx->res_list_tpg.hw_res[0] = tpg_reserve.node_res;
 	ife_ctx->is_tpg = true;
-
 end:
 	return rc;
 }
@@ -4501,8 +4505,18 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args)
 	}
 
 	/* Check if all output ports are of lite  */
-	if (total_lite_port == total_pix_port + total_rdi_port) {
+	if (total_lite_port == total_pix_port + total_rdi_port)
 		ife_ctx->is_lite_context = 1;
+
+	/* Acquire tpg HW */
+	if ((in_port->res_type == CAM_ISP_IFE_IN_RES_CPHY_TPG_0) ||
+		(in_port->res_type == CAM_ISP_IFE_IN_RES_CPHY_TPG_1) ||
+		(in_port->res_type == CAM_ISP_IFE_IN_RES_CPHY_TPG_2))
+		rc = cam_ife_hw_mgr_acquire_tpg(ife_ctx, &in_port[0],
+			acquire_hw_info->num_inputs);
+	if (rc) {
+		CAM_ERR(CAM_ISP, "can not acquire TPG resource");
+		goto free_res;
 	}
 
 	/* acquire HW resources */
@@ -4521,22 +4535,14 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args)
 			}
 		}
 
+		if (ife_ctx->is_tpg)
+			ife_ctx->res_list_tpg.res_type = in_port[i].res_type;
+
 		CAM_DBG(CAM_ISP,
 			"in_res_type: 0x%x sfe_in_path_type: 0x%x sfe_ife_enable: 0x%x",
 			in_port[i].res_type, in_port[i].sfe_in_path_type,
 			in_port[i].sfe_ife_enable);
 
-		if ((in_port[i].res_type == CAM_ISP_IFE_IN_RES_CPHY_TPG_0) ||
-			(in_port[i].res_type == CAM_ISP_IFE_IN_RES_CPHY_TPG_1) ||
-			(in_port[i].res_type == CAM_ISP_IFE_IN_RES_CPHY_TPG_2))
-			rc  = cam_ife_hw_mgr_acquire_tpg(ife_ctx, &in_port[i],
-				acquire_hw_info->num_inputs);
-
-		if (rc) {
-			CAM_ERR(CAM_ISP, "can not acquire TPG resource");
-			goto free_res;
-		}
-
 		if (ife_ctx->is_offline)
 			rc = cam_ife_mgr_acquire_hw_for_offline_ctx(
 				ife_ctx, &in_port[i],

+ 10 - 18
drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_top_tpg_hw_intf.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _CAM_TOP_TPG_HW_INTF_H_
@@ -12,8 +12,12 @@
 
 /* Max top tpg instance */
 #define CAM_TOP_TPG_HW_NUM_MAX                        3
+/* Max supported number of VC for TPG */
+#define CAM_TOP_TPG_MAX_SUPPORTED_VC                  4
 /* Max supported number of DT for TPG */
 #define CAM_TOP_TPG_MAX_SUPPORTED_DT                  4
+/* Max supported number of in_ports for TPG */
+#define CAM_TOP_TPG_MAX_SUPPORTED_IN_PORTS            16
 
 /**
  * enum cam_top_tpg_id - top tpg hw instance id
@@ -54,30 +58,18 @@ struct cam_top_tpg_ver1_reserve_args {
 };
 
 /**
- * struct cam_top_tpg_ver2_reserve_args
- * @num_inport:   number of inport
+ * struct cam_top_tpg_reserve_args
  *                TPG supports 1 VC/DT combo
- * @in_port :     Input port resource info structure pointer
- * @node_res :    Reserved resource structure pointer
- *
- */
-struct cam_top_tpg_ver2_reserve_args {
-	uint32_t                                  num_inport;
-	struct cam_isp_in_port_generic_info      *in_port;
-	struct cam_isp_resource_node             *node_res;
-};
-
-/**
- * struct cam_top_tpg_ver2_reserve_args
- * @num_inport:   number of inport
  *                TPG supports 4 VC's and 4 DT's per VC
+ * @num_inport:   number of inport
  * @in_port :     Input port resource info structure pointer
  * @node_res :    Reserved resource structure pointer
  *
  */
-struct cam_top_tpg_ver3_reserve_args {
+struct cam_top_tpg_reserve_args {
 	uint32_t                                  num_inport;
-	struct cam_isp_in_port_generic_info      *in_port;
+	struct cam_isp_in_port_generic_info      *in_port[
+					CAM_TOP_TPG_MAX_SUPPORTED_IN_PORTS];
 	struct cam_isp_resource_node             *node_res;
 };
 

+ 17 - 81
drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_core.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/iopoll.h>
@@ -50,48 +50,6 @@ int cam_top_tpg_get_format(
 	return rc;
 }
 
-static int cam_top_tpg_release(void *hw_priv,
-	void *release_args, uint32_t arg_size)
-{
-	int rc = 0;
-	struct cam_top_tpg_hw           *tpg_hw;
-	struct cam_hw_info              *tpg_hw_info;
-	struct cam_top_tpg_cfg          *tpg_data;
-	struct cam_isp_resource_node    *tpg_res;
-
-	if (!hw_priv || !release_args ||
-		(arg_size != sizeof(struct cam_isp_resource_node))) {
-		CAM_ERR(CAM_ISP, "TPG: Invalid args");
-		return -EINVAL;
-	}
-
-	tpg_hw_info = (struct cam_hw_info  *)hw_priv;
-	tpg_hw = (struct cam_top_tpg_hw   *)tpg_hw_info->core_info;
-	tpg_res = (struct cam_isp_resource_node *)release_args;
-
-	mutex_lock(&tpg_hw->hw_info->hw_mutex);
-	if ((tpg_res->res_type != CAM_ISP_RESOURCE_TPG) ||
-		(tpg_res->res_state <= CAM_ISP_RESOURCE_STATE_AVAILABLE)) {
-		CAM_ERR(CAM_ISP, "TPG:%d Invalid res type:%d res_state:%d",
-			tpg_hw->hw_intf->hw_idx, tpg_res->res_type,
-			tpg_res->res_state);
-		rc = -EINVAL;
-		goto end;
-	}
-
-	CAM_DBG(CAM_ISP, "TPG:%d res type :%d",
-		tpg_hw->hw_intf->hw_idx, tpg_res->res_type);
-
-	tpg_hw->reserve_cnt = 0;
-	tpg_res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE;
-	tpg_data = (struct cam_top_tpg_cfg *)tpg_res->res_priv;
-	memset(tpg_data, 0, sizeof(struct cam_top_tpg_cfg));
-
-end:
-	mutex_unlock(&tpg_hw->hw_info->hw_mutex);
-	return rc;
-}
-
 static int cam_top_tpg_init_hw(void *hw_priv,
 	void *init_args, uint32_t arg_size)
 {
@@ -230,7 +188,7 @@ static int cam_top_tpg_write(void *hw_priv,
 	return -EINVAL;
 }
 
-static int cam_top_tpg_set_phy_clock(
+int cam_top_tpg_set_phy_clock(
 	struct cam_top_tpg_hw *csid_hw, void *cmd_args)
 {
 	struct cam_top_tpg_clock_update_args *clk_update = NULL;
@@ -283,40 +241,10 @@ irqreturn_t cam_top_tpg_irq(int irq_num, void *data)
 	return IRQ_HANDLED;
 }
 
-static int cam_top_tpg_process_cmd(void *hw_priv,
-	uint32_t cmd_type, void *cmd_args, uint32_t arg_size)
-{
-	int rc = 0;
-	struct cam_top_tpg_hw               *tpg_hw;
-	struct cam_hw_info                  *tpg_hw_info;
-
-	if (!hw_priv || !cmd_args) {
-		CAM_ERR(CAM_ISP, "CSID: Invalid arguments");
-		return -EINVAL;
-	}
-
-	tpg_hw_info = (struct cam_hw_info  *)hw_priv;
-	tpg_hw = (struct cam_top_tpg_hw   *)tpg_hw_info->core_info;
-
-	switch (cmd_type) {
-	case CAM_ISP_HW_CMD_TPG_PHY_CLOCK_UPDATE:
-		rc = cam_top_tpg_set_phy_clock(tpg_hw, cmd_args);
-		break;
-	default:
-		CAM_ERR(CAM_ISP, "TPG:%d unsupported cmd:%d",
-			tpg_hw->hw_intf->hw_idx, cmd_type);
-		rc = -EINVAL;
-		break;
-	}
-
-	return 0;
-}
-
 int cam_top_tpg_probe_init(struct cam_hw_intf  *tpg_hw_intf,
 	uint32_t tpg_idx)
 {
 	int rc = -EINVAL;
-	struct cam_top_tpg_cfg             *tpg_data;
 	struct cam_hw_info                 *tpg_hw_info;
 	struct cam_top_tpg_hw              *tpg_hw = NULL;
 	uint32_t hw_version = 0;
@@ -352,10 +280,8 @@ int cam_top_tpg_probe_init(struct cam_hw_intf  *tpg_hw_intf,
 	tpg_hw->hw_intf->hw_ops.init        = cam_top_tpg_init_hw;
 	tpg_hw->hw_intf->hw_ops.deinit      = cam_top_tpg_deinit_hw;
 	tpg_hw->hw_intf->hw_ops.reset       = NULL;
-	tpg_hw->hw_intf->hw_ops.release     = cam_top_tpg_release;
 	tpg_hw->hw_intf->hw_ops.read        = cam_top_tpg_read;
 	tpg_hw->hw_intf->hw_ops.write       = cam_top_tpg_write;
-	tpg_hw->hw_intf->hw_ops.process_cmd = cam_top_tpg_process_cmd;
 
 	hw_version = tpg_hw->tpg_info->hw_dts_version;
 	if (hw_version == CAM_TOP_TPG_VERSION_1)
@@ -368,12 +294,22 @@ int cam_top_tpg_probe_init(struct cam_hw_intf  *tpg_hw_intf,
 	tpg_hw->tpg_res.res_type = CAM_ISP_RESOURCE_TPG;
 	tpg_hw->tpg_res.res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE;
 	tpg_hw->tpg_res.hw_intf = tpg_hw->hw_intf;
-	tpg_data = kzalloc(sizeof(*tpg_data), GFP_KERNEL);
-	if (!tpg_data) {
-		rc = -ENOMEM;
-		goto err;
+
+	if (hw_version < CAM_TOP_TPG_VERSION_3) {
+		tpg_hw->tpg_res.res_priv =
+			kzalloc(sizeof(struct cam_top_tpg_cfg), GFP_KERNEL);
+		if (!tpg_hw->tpg_res.res_priv) {
+			rc = -ENOMEM;
+			goto err;
+		}
+	} else {
+		tpg_hw->tpg_res.res_priv =
+			kzalloc(sizeof(struct cam_top_tpg_cfg_v2), GFP_KERNEL);
+		if (!tpg_hw->tpg_res.res_priv) {
+			rc = -ENOMEM;
+			goto err;
+		}
 	}
-	tpg_hw->tpg_res.res_priv = tpg_data;
 
 	cam_top_tpg_enable_soc_resources(&tpg_hw->hw_info->soc_info,
 		CAM_SVS_VOTE);

+ 46 - 5
drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_core.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _CAM_TOP_TPG_CORE_H_
@@ -14,6 +14,7 @@
 #define CAM_TOP_TPG_VERSION_2             0x10000002
 #define CAM_TOP_TPG_VERSION_3             0x20000000
 
+#define CAM_TPG_LFSR_SEED                 0x12345678
 
 enum cam_top_tpg_encode_format {
 	CAM_TOP_TPG_ENCODE_FORMAT_RAW6,
@@ -79,7 +80,6 @@ struct cam_top_tpg_dt_cfg {
  * @v_blank_count:    vertical blanking count value
  * @num_active_dts:   number of active dts need to configure
  * @num_frames:       number of output frames
- * @throttle_pattern: Define bubble pattern in throttler
  * @qcfa_en:          enable qcfa in color bar cfg
  * @dt_cfg:           dt configuration values
  *
@@ -94,11 +94,53 @@ struct cam_top_tpg_cfg {
 	uint32_t                        num_active_dts;
 	uint32_t                        num_frames;
 	uint32_t                        vc_dt_pattern_id;
-	uint32_t                        throttle_pattern;
 	uint32_t                        qcfa_en;
 	struct cam_top_tpg_dt_cfg       dt_cfg[4];
 };
 
+/**
+ * struct cam_top_tpg_vc_dt_info- VC DT information for tpg HW
+ *
+ * @vc_num:          Virtual channel number
+ * @num_active_dts:  number of active dts need to configure
+ * @dt_cfg:          dt configuration values
+ */
+struct cam_top_tpg_vc_dt_info {
+	uint32_t                        vc_num;
+	uint32_t                        num_active_dts;
+	struct cam_top_tpg_dt_cfg       dt_cfg[CAM_TOP_TPG_MAX_SUPPORTED_DT];
+};
+
+/**
+ * struct cam_top_tpg_cfg_v2- tpg congiguration
+ * @pix_pattern      : pixel pattern output of the tpg
+ * @phy_sel          : phy selection 0:dphy or 1:cphy
+ * @num_active_lanes : Number of active lines
+ * @h_blank_count    : horizontal blanking count value
+ * @h_blank_count    : vertical blanking count value
+ * @vbi_cnt          : vbi count
+ * @num_frames       : number of output frames
+ * @qcfa_en          : enable qcfa in color bar cfg
+ * @num_active_vcs   : number of currently configured vcs in tpg hw
+ * @throttle_pattern : Define bubble pattern in throttler
+ * @vc_dt            : VC DT information that the TPG HW holds
+ *
+ */
+struct cam_top_tpg_cfg_v2 {
+	uint32_t                       pix_pattern;
+	uint32_t                       phy_sel;
+	uint32_t                       num_active_lanes;
+	uint32_t                       v_blank_count;
+	uint32_t                       h_blank_count;
+	uint32_t                       vbi_cnt;
+	uint32_t                       num_frames;
+	uint32_t                       vc_dt_pattern_id;
+	uint32_t                       qcfa_en;
+	uint32_t                       num_active_vcs;
+	uint32_t                       throttle_pattern;
+	struct cam_top_tpg_vc_dt_info  vc_dt[CAM_TOP_TPG_MAX_SUPPORTED_VC];
+};
+
 /**
  * struct cam_top_tpg_hw- tpg hw device resources data
  *
@@ -108,7 +150,6 @@ struct cam_top_tpg_cfg {
  * @tpg_res:                  tpg resource
  * @tpg_cfg:                  tpg configuration
  * @clk_rate                  clock rate
- * @reserve_cnt:              reserve cnt
  * @lock_state                lock state
  * @tpg_complete              tpg completion
  *
@@ -119,7 +160,6 @@ struct cam_top_tpg_hw {
 	struct cam_top_tpg_hw_info      *tpg_info;
 	struct cam_isp_resource_node     tpg_res;
 	uint64_t                         clk_rate;
-	uint32_t                         reserve_cnt;
 	spinlock_t                       lock_state;
 	struct completion                tpg_complete;
 };
@@ -130,5 +170,6 @@ int cam_top_tpg_probe_init(struct cam_hw_intf *tpg_hw_intf,
 	uint32_t tpg_idx);
 
 int cam_top_tpg_deinit(struct cam_top_tpg_hw *top_tpg_hw);
+int cam_top_tpg_set_phy_clock(struct cam_top_tpg_hw *csid_hw, void *cmd_args);
 
 #endif /* _CAM_TOP_TPG_CORE_H_ */

+ 79 - 2
drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_ver1.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/iopoll.h>
@@ -54,6 +54,40 @@ static int cam_top_tpg_ver1_get_hw_caps(
 	return rc;
 }
 
+static int cam_top_tpg_ver1_process_cmd(void *hw_priv,
+	uint32_t cmd_type, void *cmd_args, uint32_t arg_size)
+{
+	int rc = 0;
+	struct cam_top_tpg_hw               *tpg_hw;
+	struct cam_hw_info                  *tpg_hw_info;
+
+	if (!hw_priv || !cmd_args) {
+		CAM_ERR(CAM_ISP, "CSID: Invalid arguments");
+		return -EINVAL;
+	}
+
+	tpg_hw_info = (struct cam_hw_info  *)hw_priv;
+	tpg_hw = (struct cam_top_tpg_hw   *)tpg_hw_info->core_info;
+
+	switch (cmd_type) {
+	case CAM_ISP_HW_CMD_TPG_PHY_CLOCK_UPDATE:
+		rc = cam_top_tpg_set_phy_clock(tpg_hw, cmd_args);
+		break;
+	case CAM_ISP_HW_CMD_TPG_CORE_CFG_CMD:
+		CAM_DBG(CAM_ISP,
+			"CORE_CFG_CMD is not supported by tpg version:%u",
+			tpg_hw->tpg_info->hw_dts_version);
+		break;
+	default:
+		CAM_ERR(CAM_ISP, "TPG:%d unsupported cmd:%d",
+			tpg_hw->hw_intf->hw_idx, cmd_type);
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
 static int cam_top_tpg_ver1_reserve(
 	void                                         *hw_priv,
 	void                                         *reserve_args,
@@ -191,6 +225,47 @@ error:
 	return rc;
 }
 
+static int cam_top_tpg_ver1_release(void *hw_priv,
+	void *release_args, uint32_t arg_size)
+{
+	int rc = 0;
+	struct cam_top_tpg_hw           *tpg_hw;
+	struct cam_hw_info              *tpg_hw_info;
+	struct cam_top_tpg_cfg          *tpg_data;
+	struct cam_isp_resource_node    *tpg_res;
+
+	if (!hw_priv || !release_args ||
+		(arg_size != sizeof(struct cam_isp_resource_node))) {
+		CAM_ERR(CAM_ISP, "TPG: Invalid args");
+		return -EINVAL;
+	}
+
+	tpg_hw_info = (struct cam_hw_info  *)hw_priv;
+	tpg_hw = (struct cam_top_tpg_hw   *)tpg_hw_info->core_info;
+	tpg_res = (struct cam_isp_resource_node *)release_args;
+
+	mutex_lock(&tpg_hw->hw_info->hw_mutex);
+	if ((tpg_res->res_type != CAM_ISP_RESOURCE_TPG) ||
+		(tpg_res->res_state <= CAM_ISP_RESOURCE_STATE_AVAILABLE)) {
+		CAM_ERR(CAM_ISP, "TPG:%d Invalid res type:%d res_state:%d",
+			tpg_hw->hw_intf->hw_idx, tpg_res->res_type,
+			tpg_res->res_state);
+		rc = -EINVAL;
+		goto end;
+	}
+
+	CAM_DBG(CAM_ISP, "TPG:%d res type :%d",
+		tpg_hw->hw_intf->hw_idx, tpg_res->res_type);
+
+	tpg_res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE;
+	tpg_data = (struct cam_top_tpg_cfg *)tpg_res->res_priv;
+	memset(tpg_data, 0, sizeof(struct cam_top_tpg_cfg));
+
+end:
+	mutex_unlock(&tpg_hw->hw_info->hw_mutex);
+	return rc;
+}
+
 static int cam_top_tpg_ver1_start(
 	void                                         *hw_priv,
 	void                                         *start_args,
@@ -226,7 +301,7 @@ static int cam_top_tpg_ver1_start(
 		rc = -EINVAL;
 		goto end;
 	}
-	cam_io_w_mb(0x12345678, soc_info->reg_map[0].mem_base +
+	cam_io_w_mb(CAM_TPG_LFSR_SEED, soc_info->reg_map[0].mem_base +
 		tpg_reg->tpg_lfsr_seed);
 
 	for (i = 0; i < tpg_data->num_active_dts; i++) {
@@ -361,7 +436,9 @@ int cam_top_tpg_ver1_init(
 	struct cam_top_tpg_hw                        *tpg_hw)
 {
 	tpg_hw->hw_intf->hw_ops.get_hw_caps = cam_top_tpg_ver1_get_hw_caps;
+	tpg_hw->hw_intf->hw_ops.process_cmd = cam_top_tpg_ver1_process_cmd;
 	tpg_hw->hw_intf->hw_ops.reserve     = cam_top_tpg_ver1_reserve;
+	tpg_hw->hw_intf->hw_ops.release     = cam_top_tpg_ver1_release;
 	tpg_hw->hw_intf->hw_ops.start       = cam_top_tpg_ver1_start;
 	tpg_hw->hw_intf->hw_ops.stop        = cam_top_tpg_ver1_stop;
 

+ 95 - 15
drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_ver2.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/iopoll.h>
@@ -48,6 +48,41 @@ static int cam_top_tpg_ver2_get_hw_caps(
 	return rc;
 }
 
+static int cam_top_tpg_ver2_process_cmd(void *hw_priv,
+	uint32_t cmd_type, void *cmd_args, uint32_t arg_size)
+{
+	int rc = 0;
+	struct cam_top_tpg_hw               *tpg_hw;
+	struct cam_hw_info                  *tpg_hw_info;
+
+	if (!hw_priv || !cmd_args) {
+		CAM_ERR(CAM_ISP, "CSID: Invalid arguments");
+		return -EINVAL;
+	}
+
+	tpg_hw_info = (struct cam_hw_info  *)hw_priv;
+	tpg_hw = (struct cam_top_tpg_hw   *)tpg_hw_info->core_info;
+
+	switch (cmd_type) {
+	case CAM_ISP_HW_CMD_TPG_PHY_CLOCK_UPDATE:
+		rc = cam_top_tpg_set_phy_clock(tpg_hw, cmd_args);
+		break;
+	case CAM_ISP_HW_CMD_TPG_CORE_CFG_CMD:
+		CAM_DBG(CAM_ISP,
+			"CORE_CFG_CMD is not supported by tpg version:%u",
+			tpg_hw->tpg_info->hw_dts_version);
+		break;
+	default:
+		CAM_ERR(CAM_ISP, "TPG:%d unsupported cmd:%d",
+			tpg_hw->hw_intf->hw_idx, cmd_type);
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+
 static int cam_top_tpg_ver2_reserve(
 	void                                         *hw_priv,
 	void                                         *reserve_args,
@@ -56,21 +91,20 @@ static int cam_top_tpg_ver2_reserve(
 	int                                           rc = 0;
 	struct cam_top_tpg_hw                        *tpg_hw;
 	struct cam_hw_info                           *tpg_hw_info;
-	struct cam_top_tpg_ver2_reserve_args         *reserv;
+	struct cam_top_tpg_reserve_args              *reserv;
 	struct cam_top_tpg_cfg                       *tpg_data;
 
 	if (!hw_priv || !reserve_args || (arg_size !=
-		sizeof(struct cam_top_tpg_ver2_reserve_args))) {
+		sizeof(struct cam_top_tpg_reserve_args))) {
 		CAM_ERR(CAM_ISP, "TPG: Invalid args");
 		return -EINVAL;
 	}
 
 	tpg_hw_info = (struct cam_hw_info *)hw_priv;
 	tpg_hw = (struct cam_top_tpg_hw *)tpg_hw_info->core_info;
-	reserv = (struct cam_top_tpg_ver2_reserve_args  *)reserve_args;
+	reserv = (struct cam_top_tpg_reserve_args *)reserve_args;
 
-	if (reserv->num_inport <= 0 ||
-		reserv->num_inport > CAM_TOP_TPG_VER2_MAX_SUPPORTED_DT) {
+	if (reserv->num_inport > CAM_TOP_TPG_VER2_MAX_SUPPORTED_DT) {
 		CAM_ERR_RATE_LIMIT(CAM_ISP, "TPG: %u invalid input num port:%d",
 			tpg_hw->hw_intf->hw_idx, reserv->num_inport);
 		return -EINVAL;
@@ -85,21 +119,24 @@ static int cam_top_tpg_ver2_reserve(
 	}
 
 	tpg_data = (struct cam_top_tpg_cfg *)tpg_hw->tpg_res.res_priv;
-	tpg_data->h_blank_count = reserv->in_port->hbi_cnt;
-	tpg_data->v_blank_count = 600;
-	tpg_data->dt_cfg[0].data_type = reserv->in_port->dt[0];
-	tpg_data->dt_cfg[0].frame_height = reserv->in_port->height;
-	if (reserv->in_port->usage_type)
+	tpg_data->h_blank_count = 55000;
+	tpg_data->v_blank_count = 50688;
+	tpg_data->dt_cfg[0].data_type = reserv->in_port[0]->dt[0];
+	tpg_data->vc_num[0] = reserv->in_port[0]->vc[0];
+
+	tpg_data->dt_cfg[0].frame_height = reserv->in_port[0]->height;
+	if (reserv->in_port[0]->usage_type)
 		tpg_data->dt_cfg[0].frame_width =
-			((reserv->in_port->right_stop -
-				reserv->in_port->left_start) + 1);
+			((reserv->in_port[0]->right_stop -
+				reserv->in_port[0]->left_start) + 1);
 	else
 		tpg_data->dt_cfg[0].frame_width =
-			reserv->in_port->left_width;
+			reserv->in_port[0]->left_width;
 	tpg_data->num_active_dts = 1;
 
-	CAM_DBG(CAM_ISP, "TPG:%u dt:0x%x h:%d w:%d hbi:%d vbi:%d reserved",
+	CAM_DBG(CAM_ISP, "TPG:%u vc:0x%x dt:0x%x h:%d w:%d hbi:%d vbi:%d reserved",
 		tpg_hw->hw_intf->hw_idx,
+		tpg_data->vc_num[0],
 		tpg_data->dt_cfg[0].data_type,
 		tpg_data->dt_cfg[0].frame_height,
 		tpg_data->dt_cfg[0].frame_width,
@@ -114,6 +151,47 @@ static int cam_top_tpg_ver2_reserve(
 	return rc;
 }
 
+static int cam_top_tpg_ver2_release(void *hw_priv,
+	void *release_args, uint32_t arg_size)
+{
+	int rc = 0;
+	struct cam_top_tpg_hw           *tpg_hw;
+	struct cam_hw_info              *tpg_hw_info;
+	struct cam_top_tpg_cfg          *tpg_data;
+	struct cam_isp_resource_node    *tpg_res;
+
+	if (!hw_priv || !release_args ||
+		(arg_size != sizeof(struct cam_isp_resource_node))) {
+		CAM_ERR(CAM_ISP, "TPG: Invalid args");
+		return -EINVAL;
+	}
+
+	tpg_hw_info = (struct cam_hw_info  *)hw_priv;
+	tpg_hw = (struct cam_top_tpg_hw   *)tpg_hw_info->core_info;
+	tpg_res = (struct cam_isp_resource_node *)release_args;
+
+	mutex_lock(&tpg_hw->hw_info->hw_mutex);
+	if ((tpg_res->res_type != CAM_ISP_RESOURCE_TPG) ||
+		(tpg_res->res_state <= CAM_ISP_RESOURCE_STATE_AVAILABLE)) {
+		CAM_ERR(CAM_ISP, "TPG:%d Invalid res type:%d res_state:%d",
+			tpg_hw->hw_intf->hw_idx, tpg_res->res_type,
+			tpg_res->res_state);
+		rc = -EINVAL;
+		goto end;
+	}
+
+	CAM_DBG(CAM_ISP, "TPG:%d res type :%d",
+		tpg_hw->hw_intf->hw_idx, tpg_res->res_type);
+
+	tpg_res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE;
+	tpg_data = (struct cam_top_tpg_cfg *)tpg_res->res_priv;
+	memset(tpg_data, 0, sizeof(struct cam_top_tpg_cfg));
+
+end:
+	mutex_unlock(&tpg_hw->hw_info->hw_mutex);
+	return rc;
+}
+
 static int cam_top_tpg_ver2_start(
 	void                                         *hw_priv,
 	void                                         *start_args,
@@ -237,7 +315,9 @@ int cam_top_tpg_ver2_init(
 	struct cam_top_tpg_hw                        *tpg_hw)
 {
 	tpg_hw->hw_intf->hw_ops.get_hw_caps = cam_top_tpg_ver2_get_hw_caps;
+	tpg_hw->hw_intf->hw_ops.process_cmd = cam_top_tpg_ver2_process_cmd;
 	tpg_hw->hw_intf->hw_ops.reserve     = cam_top_tpg_ver2_reserve;
+	tpg_hw->hw_intf->hw_ops.release     = cam_top_tpg_ver2_release;
 	tpg_hw->hw_intf->hw_ops.start       = cam_top_tpg_ver2_start;
 	tpg_hw->hw_intf->hw_ops.stop        = cam_top_tpg_ver2_stop;
 

+ 254 - 152
drivers/cam_isp/isp_hw_mgr/isp_hw/top_tpg/cam_top_tpg_ver3.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/iopoll.h>
@@ -54,7 +54,7 @@ static int cam_top_tpg_ver3_process_cmd(void *hw_priv,
 	struct cam_top_tpg_hw                  *tpg_hw;
 	struct cam_hw_info                     *tpg_hw_info;
 	struct cam_isp_tpg_core_config         *core_cfg;
-	struct cam_top_tpg_cfg                 *tpg_data;
+	struct cam_top_tpg_cfg_v2              *tpg_data;
 
 	if (!hw_priv || !cmd_args) {
 		CAM_ERR(CAM_ISP, "TPG: Invalid args");
@@ -63,7 +63,7 @@ static int cam_top_tpg_ver3_process_cmd(void *hw_priv,
 
 	tpg_hw_info = (struct cam_hw_info *)hw_priv;
 	tpg_hw = (struct cam_top_tpg_hw *)tpg_hw_info->core_info;
-	tpg_data = (struct cam_top_tpg_cfg *)tpg_hw->tpg_res.res_priv;
+	tpg_data = (struct cam_top_tpg_cfg_v2 *)tpg_hw->tpg_res.res_priv;
 
 	switch (cmd_type) {
 	case CAM_ISP_HW_CMD_TPG_CORE_CFG_CMD:
@@ -99,6 +99,104 @@ static int cam_top_tpg_ver3_process_cmd(void *hw_priv,
 	return rc;
 }
 
+static int cam_top_tpg_ver3_add_append_vc_dt_info(uint32_t *num_active_vcs,
+	struct cam_top_tpg_vc_dt_info *tpg_vcdt,
+	struct cam_isp_in_port_generic_info *in_port)
+{
+	bool                                    is_dt_saved = false;
+	int                                     i;
+	int                                     j;
+	uint32_t                               *num_dts;
+	uint32_t                                encode_format;
+	int                                     rc;
+
+	for (i = 0; i < in_port->num_valid_vc_dt; i++) {
+		if (in_port->dt[i] > 0x3f || in_port->vc[i] > 0x1f) {
+			CAM_ERR(CAM_ISP, "Invalid vc:%d dt %d",
+				in_port->vc[i],
+				in_port->dt[i]);
+			return -EINVAL;
+		}
+		rc = cam_top_tpg_get_format(in_port->format, &encode_format);
+		if (rc)
+			return rc;
+
+		for (j = 0; j < *num_active_vcs; j++) {
+			if (tpg_vcdt[j].vc_num == in_port->vc[i]) {
+				num_dts = &tpg_vcdt[j].num_active_dts;
+				if (*num_dts >=
+					CAM_TOP_TPG_MAX_SUPPORTED_DT) {
+					CAM_ERR(CAM_ISP,
+						"Cannot support more than 4 DTs per VC"
+						);
+					return -EINVAL;
+				}
+				tpg_vcdt[j].dt_cfg[*num_dts].data_type =
+					in_port->dt[i];
+				tpg_vcdt[j].dt_cfg[*num_dts].encode_format =
+					encode_format;
+				tpg_vcdt[j].dt_cfg[*num_dts].frame_height =
+					in_port->height;
+				if (in_port->usage_type)
+					tpg_vcdt[j].dt_cfg[*num_dts].frame_width
+					= ((in_port->right_stop -
+						in_port->left_start) + 1);
+				else
+					tpg_vcdt[j].dt_cfg[*num_dts].frame_width
+					= in_port->left_width;
+
+				CAM_DBG(CAM_ISP,
+					"vc:%d dt:%d format:%d height:%d width:%d",
+					in_port->vc[i], in_port->dt[i],
+					encode_format, in_port->height,
+					tpg_vcdt[j].dt_cfg[*num_dts].frame_width
+					);
+
+				*num_dts += 1;
+				is_dt_saved = true;
+				break;
+			}
+		}
+
+		if (is_dt_saved == false) {
+			if (*num_active_vcs >= CAM_TOP_TPG_MAX_SUPPORTED_VC) {
+				CAM_ERR(CAM_ISP,
+					"Cannot support more than 4 VCs");
+				return -EINVAL;
+			}
+
+			tpg_vcdt[*num_active_vcs].vc_num = in_port->vc[i];
+			tpg_vcdt[*num_active_vcs].dt_cfg[0].data_type =
+				in_port->dt[i];
+			tpg_vcdt[*num_active_vcs].dt_cfg[0].encode_format =
+				encode_format;
+			tpg_vcdt[*num_active_vcs].dt_cfg[0].frame_height =
+				in_port->height;
+
+			if (in_port->usage_type)
+				tpg_vcdt[*num_active_vcs].dt_cfg[0].frame_width
+				= ((in_port->right_stop - in_port->left_start)
+					+ 1);
+			else
+				tpg_vcdt[*num_active_vcs].dt_cfg[0].frame_width
+				= in_port->left_width;
+
+			CAM_DBG(CAM_ISP,
+				"vc:%d dt:%d format:%d height:%d width:%d",
+				in_port->vc[i], in_port->dt[i],
+				encode_format, in_port->height,
+				tpg_vcdt[*num_active_vcs].dt_cfg[0].frame_width
+				);
+
+			tpg_vcdt[*num_active_vcs].num_active_dts++;
+			*num_active_vcs += 1;
+		} else {
+			is_dt_saved = false;
+		}
+	}
+	return 0;
+}
+
 static int cam_top_tpg_ver3_reserve(
 	void                                         *hw_priv,
 	void                                         *reserve_args,
@@ -107,124 +205,91 @@ static int cam_top_tpg_ver3_reserve(
 	int                                           rc = 0;
 	struct cam_top_tpg_hw                        *tpg_hw;
 	struct cam_hw_info                           *tpg_hw_info;
-	struct cam_top_tpg_ver3_reserve_args         *reserv;
-	struct cam_top_tpg_cfg                       *tpg_data;
-	uint32_t                                      encode_format = 0;
-	uint32_t                                      i, num_vc_dt;
+	struct cam_top_tpg_reserve_args              *reserv;
+	struct cam_top_tpg_cfg_v2                    *tpg_data;
+	uint32_t                                      num_active_vcs = 0;
+	struct cam_top_tpg_vc_dt_info
+		in_port_vc_dt[CAM_TOP_TPG_MAX_SUPPORTED_VC];
+	int                                           i;
 
 	if (!hw_priv || !reserve_args || (arg_size !=
-		sizeof(struct cam_top_tpg_ver3_reserve_args))) {
+		sizeof(struct cam_top_tpg_reserve_args))) {
 		CAM_ERR(CAM_ISP, "TPG: Invalid args");
 		return -EINVAL;
 	}
 
 	tpg_hw_info = (struct cam_hw_info *)hw_priv;
 	tpg_hw = (struct cam_top_tpg_hw *)tpg_hw_info->core_info;
-	reserv = (struct cam_top_tpg_ver3_reserve_args  *)reserve_args;
-
-	if (reserv->num_inport <= 0 ||
-		reserv->num_inport > CAM_TOP_TPG_MAX_SUPPORTED_DT) {
-		CAM_ERR_RATE_LIMIT(CAM_ISP, "TPG: %u invalid input num port:%d",
-			tpg_hw->hw_intf->hw_idx, reserv->num_inport);
-		return -EINVAL;
-	}
+	reserv = (struct cam_top_tpg_reserve_args  *)reserve_args;
 
 	mutex_lock(&tpg_hw->hw_info->hw_mutex);
-	if ((reserv->in_port->lane_num <= 0 ||
-		reserv->in_port->lane_num > 4) ||
-		(reserv->in_port->lane_type >= 2)) {
+
+	if ((reserv->in_port[0]->lane_num <= 0 ||
+		reserv->in_port[0]->lane_num > 4) ||
+		(reserv->in_port[0]->lane_type >= 2)) {
 		CAM_ERR_RATE_LIMIT(CAM_ISP, "TPG:%u invalid input %d %d",
 			tpg_hw->hw_intf->hw_idx,
-			reserv->in_port->lane_num,
-			reserv->in_port->lane_type);
+			reserv->in_port[0]->lane_num,
+			reserv->in_port[0]->lane_type);
 		rc = -EINVAL;
 		goto error;
 	}
 
-	tpg_data = (struct cam_top_tpg_cfg *)tpg_hw->tpg_res.res_priv;
-	if (!tpg_hw->reserve_cnt)
-		memset(tpg_data, 0, sizeof(*tpg_data));
-
-	if (tpg_hw->reserve_cnt) {
-		if ((tpg_data->num_active_dts +
-			reserv->in_port->num_valid_vc_dt) >
-			CAM_TOP_TPG_MAX_SUPPORTED_DT) {
-			CAM_DBG(CAM_ISP, "TPG: %u at max vc-dt config",
-				tpg_hw->hw_intf->hw_idx);
-			rc = -EINVAL;
-			goto error;
-		}
-
-		if (tpg_data->phy_sel !=  reserv->in_port->lane_type ||
-			tpg_data->num_active_lanes != reserv->in_port->lane_num) {
-			CAM_DBG(CAM_ISP, "TPG: %u config mismatch",
-				tpg_hw->hw_intf->hw_idx);
-			rc = -EINVAL;
-			goto error;
+	tpg_data = (struct cam_top_tpg_cfg_v2 *)tpg_hw->tpg_res.res_priv;
+
+	memcpy((void *)&in_port_vc_dt[0], (void *)&tpg_data->vc_dt[0],
+		CAM_TOP_TPG_MAX_SUPPORTED_VC *
+		sizeof(struct cam_top_tpg_vc_dt_info));
+	num_active_vcs = tpg_data->num_active_vcs;
+
+	for (i = 0; i < reserv->num_inport; i++) {
+		if (tpg_data->num_active_vcs) {
+			if ((tpg_data->phy_sel !=
+				reserv->in_port[i]->lane_type) ||
+				(tpg_data->num_active_lanes !=
+					reserv->in_port[i]->lane_num)) {
+				CAM_ERR_RATE_LIMIT(CAM_ISP,
+					"TPG: %u invalid DT config for tpg",
+					tpg_hw->hw_intf->hw_idx);
+				rc = -EINVAL;
+				goto error;
+			}
+		} else {
+			tpg_data->phy_sel = reserv->in_port[0]->lane_type;
+			tpg_data->num_active_lanes =
+				reserv->in_port[0]->lane_num;
 		}
-	}
 
-	num_vc_dt = tpg_data->num_active_dts;
-	for (i = 0; i < reserv->in_port->num_valid_vc_dt; i++) {
-		if (reserv->in_port->dt[i] > 0x3f ||
-			reserv->in_port->vc[i] > 0x1f) {
-			CAM_ERR(CAM_ISP, "TPG:%u Invalid vc:%d dt %d",
-				tpg_hw->hw_intf->hw_idx,
-				reserv->in_port->vc[i],
-				reserv->in_port->dt[i]);
+		rc = cam_top_tpg_ver3_add_append_vc_dt_info(
+				&num_active_vcs,
+				&in_port_vc_dt[0],
+				reserv->in_port[i]);
+		if (rc) {
 			rc = -EINVAL;
+			CAM_ERR(CAM_ISP,
+				"Failed to reserve TPG:%u for in_port: %u",
+				tpg_hw->hw_intf->hw_idx, i);
 			goto error;
 		}
-		tpg_data->vc_num[num_vc_dt + i] = reserv->in_port->vc[i];
-		tpg_data->dt_cfg[num_vc_dt + i].data_type = reserv->in_port->dt[i];
 	}
 
-	rc = cam_top_tpg_get_format(reserv->in_port->format,
-			&encode_format);
-	if (rc)
-		goto error;
-
-
 	CAM_DBG(CAM_ISP, "TPG: %u enter", tpg_hw->hw_intf->hw_idx);
 
-	if (!tpg_hw->reserve_cnt) {
-		tpg_data->phy_sel = reserv->in_port->lane_type;
-		tpg_data->num_active_lanes = reserv->in_port->lane_num;
-	}
-
-	for (i = 0; i < reserv->in_port->num_valid_vc_dt; i++) {
-		tpg_data->dt_cfg[num_vc_dt + i].encode_format = encode_format;
-		tpg_data->dt_cfg[num_vc_dt + i].frame_height = reserv->in_port->height;
+	tpg_data->num_active_vcs = num_active_vcs;
+	memcpy((void *)&tpg_data->vc_dt[0], (void *)&in_port_vc_dt[0],
+		CAM_TOP_TPG_MAX_SUPPORTED_VC *
+		sizeof(struct cam_top_tpg_vc_dt_info));
 
-		if (reserv->in_port->usage_type)
-			tpg_data->dt_cfg[num_vc_dt + i].frame_width =
-				((reserv->in_port->right_stop -
-					reserv->in_port->left_start) + 1);
-		else
-			tpg_data->dt_cfg[num_vc_dt + i].frame_width =
-				reserv->in_port->left_width;
-	}
-	tpg_data->num_active_dts += reserv->in_port->num_valid_vc_dt;
 	CAM_DBG(CAM_ISP,
-		"TPG:%u phy:%d lines:%d pattern:%d format:%d",
+		"TPG:%u phy:%d lines:%d pattern:%d hbi: %d vbi: %d",
 		tpg_hw->hw_intf->hw_idx,
-		tpg_data->phy_sel, tpg_data->num_active_lanes,
+		tpg_data->phy_sel,
+		tpg_data->num_active_lanes,
 		tpg_data->pix_pattern,
-		tpg_data->dt_cfg[0].encode_format);
-
-	for (i = 0; i < tpg_data->num_active_dts; i++) {
-		CAM_DBG(CAM_ISP,
-			"TPG:%u idx: %d vc_num:%d dt:%d  height:%d width:%d h blank:%d v blank:%d",
-			tpg_hw->hw_intf->hw_idx, i,
-			tpg_data->vc_num[i], tpg_data->dt_cfg[i].data_type,
-			tpg_data->dt_cfg[i].frame_height,
-			tpg_data->dt_cfg[i].frame_width,
-			tpg_data->h_blank_count,
-			tpg_data->v_blank_count);
-	}
+		tpg_data->h_blank_count,
+		tpg_data->v_blank_count);
 
 	reserv->node_res = &tpg_hw->tpg_res;
-	tpg_hw->reserve_cnt++;
 	tpg_hw->tpg_res.res_state = CAM_ISP_RESOURCE_STATE_RESERVED;
 error:
 	mutex_unlock(&tpg_hw->hw_info->hw_mutex);
@@ -233,6 +298,47 @@ error:
 	return rc;
 }
 
+static int cam_top_tpg_ver3_release(void *hw_priv,
+	void *release_args, uint32_t arg_size)
+{
+	int rc = 0;
+	struct cam_top_tpg_hw           *tpg_hw;
+	struct cam_hw_info              *tpg_hw_info;
+	struct cam_top_tpg_cfg_v2       *tpg_data;
+	struct cam_isp_resource_node    *tpg_res;
+
+	if (!hw_priv || !release_args ||
+		(arg_size != sizeof(struct cam_isp_resource_node))) {
+		CAM_ERR(CAM_ISP, "TPG: Invalid args");
+		return -EINVAL;
+	}
+
+	tpg_hw_info = (struct cam_hw_info  *)hw_priv;
+	tpg_hw = (struct cam_top_tpg_hw   *)tpg_hw_info->core_info;
+	tpg_res = (struct cam_isp_resource_node *)release_args;
+
+	mutex_lock(&tpg_hw->hw_info->hw_mutex);
+	if ((tpg_res->res_type != CAM_ISP_RESOURCE_TPG) ||
+		(tpg_res->res_state <= CAM_ISP_RESOURCE_STATE_AVAILABLE)) {
+		CAM_ERR(CAM_ISP, "TPG:%d Invalid res type:%d res_state:%d",
+			tpg_hw->hw_intf->hw_idx, tpg_res->res_type,
+			tpg_res->res_state);
+		rc = -EINVAL;
+		goto end;
+	}
+
+	CAM_DBG(CAM_ISP, "TPG:%d res type :%d",
+		tpg_hw->hw_intf->hw_idx, tpg_res->res_type);
+
+	tpg_res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE;
+	tpg_data = (struct cam_top_tpg_cfg_v2 *)tpg_res->res_priv;
+	memset(tpg_data, 0, sizeof(struct cam_top_tpg_cfg_v2));
+
+end:
+	mutex_unlock(&tpg_hw->hw_info->hw_mutex);
+	return rc;
+}
+
 static int cam_top_tpg_ver3_start(
 	void                                         *hw_priv,
 	void                                         *start_args,
@@ -244,8 +350,9 @@ static int cam_top_tpg_ver3_start(
 	struct cam_hw_soc_info                       *soc_info;
 	struct cam_isp_resource_node                 *tpg_res;
 	struct cam_top_tpg_ver3_reg_offset           *tpg_reg;
-	struct cam_top_tpg_cfg                       *tpg_data;
-	uint32_t                                      i, val;
+	struct cam_top_tpg_cfg_v2                    *tpg_data;
+	struct cam_top_tpg_vc_dt_info                *vc_dt;
+	uint32_t                                      i, val, j;
 
 	if (!hw_priv || !start_args ||
 		(arg_size != sizeof(struct cam_isp_resource_node))) {
@@ -257,12 +364,9 @@ static int cam_top_tpg_ver3_start(
 	tpg_hw = (struct cam_top_tpg_hw   *)tpg_hw_info->core_info;
 	tpg_reg = tpg_hw->tpg_info->tpg_reg;
 	tpg_res = (struct cam_isp_resource_node *)start_args;
-	tpg_data = (struct cam_top_tpg_cfg  *)tpg_res->res_priv;
+	tpg_data = (struct cam_top_tpg_cfg_v2  *)tpg_res->res_priv;
 	soc_info = &tpg_hw->hw_info->soc_info;
 
-	if (tpg_res->res_state == CAM_ISP_RESOURCE_STATE_STREAMING)
-		goto end;
-
 	if ((tpg_res->res_type != CAM_ISP_RESOURCE_TPG) ||
 		(tpg_res->res_state != CAM_ISP_RESOURCE_STATE_RESERVED)) {
 		CAM_ERR(CAM_ISP, "TPG:%d Invalid Res type:%d res_state:%d",
@@ -274,82 +378,81 @@ static int cam_top_tpg_ver3_start(
 
 	cam_io_w_mb(1, soc_info->reg_map[0].mem_base + tpg_reg->tpg_top_clear);
 
-	for (i = 0; i < tpg_data->num_active_dts; i++) {
-		val = (((tpg_data->dt_cfg[i].frame_width & 0xFFFF) << 16) |
-			(tpg_data->dt_cfg[i].frame_height & 0xFFFF));
-		cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
-			tpg_reg->tpg_vc0_dt_0_cfg_0 + 0x60 * i);
-
-		CAM_DBG(CAM_ISP, "vc%d_dt_%d_cfg_0 0x%x",
-			i, i, val);
-		cam_io_w_mb(tpg_data->dt_cfg[i].data_type,
-			soc_info->reg_map[0].mem_base +
-			tpg_reg->tpg_vc0_dt_0_cfg_1 + 0x60 * i);
+	for (i = 0; i < tpg_data->num_active_vcs; i++) {
+		vc_dt = &tpg_data->vc_dt[i];
 
-		CAM_DBG(CAM_ISP, "vc%d_dt_%d_cfg_1 0x%x",
-			i, i, tpg_data->dt_cfg[i].data_type);
-		val = ((tpg_data->dt_cfg[i].encode_format & 0xF) <<
-			tpg_reg->tpg_dt_encode_format_shift) |
-			tpg_reg->tpg_payload_mode_color;
-
-		cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
-			tpg_reg->tpg_vc0_dt_0_cfg_2 + 0x60 * i);
-
-		CAM_DBG(CAM_ISP, "vc%d_dt_%d_cfg_2 0x%x",
-			i, i, val);
 		val = (1 << tpg_reg->tpg_split_en_shift);
 		val |= tpg_data->pix_pattern;
 		if (tpg_data->qcfa_en)
-			val |= (1 << tpg_reg->tpg_color_bar_qcfa_en_shift);
+			val |=
+			(1 << tpg_reg->tpg_color_bar_qcfa_en_shift);
 		cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
-			tpg_reg->tpg_vc0_color_bar_cfg + 0x60 * i);
-
-		CAM_DBG(CAM_ISP, "vc%d color_bar_cfg 0x%x",
-			i, val);
-		/*
-		 * if hblank is notset configureHBlank count 500 and
-		 * V blank count is 600
-		 */
+			tpg_reg->tpg_vc0_color_bar_cfg + (0x60 * i));
+		CAM_DBG(CAM_ISP, "vc%d_color_bar_cfg: 0x%x", i, val);
 
 		if (tpg_data->h_blank_count)
-			cam_io_w_mb(tpg_data->h_blank_count,
-				soc_info->reg_map[0].mem_base +
-				tpg_reg->tpg_vc0_hbi_cfg + 0x60 * i);
+			val = tpg_data->h_blank_count;
 		else
-			cam_io_w_mb(0x1F4,
-				soc_info->reg_map[0].mem_base +
-				tpg_reg->tpg_vc0_hbi_cfg + 0x60 * i);
+			val = 0x40;
+		cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
+			tpg_reg->tpg_vc0_hbi_cfg + (0x60 * i));
+		CAM_DBG(CAM_ISP, "vc%d_hbi_cfg: 0x%x", i, val);
 
 		if (tpg_data->v_blank_count)
-			cam_io_w_mb(tpg_data->v_blank_count,
-				soc_info->reg_map[0].mem_base +
-				tpg_reg->tpg_vc0_vbi_cfg + 0x60 * i);
+			val = tpg_data->v_blank_count;
 		else
-			cam_io_w_mb(0x258,
-				soc_info->reg_map[0].mem_base +
-				tpg_reg->tpg_vc0_vbi_cfg + 0x60 * i);
+			val = 0xC600;
+		cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
+			tpg_reg->tpg_vc0_vbi_cfg + (0x60 * i));
+		CAM_DBG(CAM_ISP, "vc%d_vbi_cgf: 0x%x", i, val);
 
-		cam_io_w_mb(0x12345678, soc_info->reg_map[0].mem_base +
-			tpg_reg->tpg_vc0_lfsr_seed + 0x60 * i);
+		cam_io_w_mb(CAM_TPG_LFSR_SEED,
+			soc_info->reg_map[0].mem_base +
+			tpg_reg->tpg_vc0_lfsr_seed + (0x60 * i));
 
-		val = tpg_data->vc_num[i];
+		val = (((vc_dt->num_active_dts-1) <<
+			tpg_reg->tpg_num_dts_shift_val) |
+			vc_dt->vc_num);
 		cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
-			tpg_reg->tpg_vc0_cfg0 + 0x60 * i);
-		CAM_DBG(CAM_ISP, "vc%d_cfg0 0x%x",
-			i, val);
+			tpg_reg->tpg_vc0_cfg0 + (0x60 * i));
+		CAM_DBG(CAM_ISP, "vc%d_cfg0: 0x%x", i, val);
+
+		for (j = 0; j < vc_dt->num_active_dts; j++) {
+			val = (((vc_dt->dt_cfg[j].frame_width & 0xFFFF) << 16) |
+				(vc_dt->dt_cfg[j].frame_height & 0xFFFF));
+			cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
+				tpg_reg->tpg_vc0_dt_0_cfg_0 +
+				(0x60 * i) + (j * 0x0c));
+			CAM_DBG(CAM_ISP, "vc%d_dt%d_cfg_0: 0x%x", i, j, val);
+
+			cam_io_w_mb(vc_dt->dt_cfg[j].data_type,
+				soc_info->reg_map[0].mem_base +
+				tpg_reg->tpg_vc0_dt_0_cfg_1 +
+				(0x60 * i) + (j * 0x0c));
+			CAM_DBG(CAM_ISP, "vc%d_dt%d_cfg_1: 0x%x",
+				i, j, vc_dt->dt_cfg[j].data_type);
+
+			val = ((vc_dt->dt_cfg[j].encode_format & 0xF) <<
+				tpg_reg->tpg_dt_encode_format_shift) |
+				tpg_reg->tpg_payload_mode_color;
+			cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
+				tpg_reg->tpg_vc0_dt_0_cfg_2 +
+				(0x60 * i) + (j * 0x0c));
+			CAM_DBG(CAM_ISP, "vc%d_dt%d_cfg_2: 0x%x", i, j, val);
+		}
 	}
 
 	if (tpg_data->throttle_pattern)
-		cam_io_w_mb(tpg_data->throttle_pattern,
-			soc_info->reg_map[0].mem_base + tpg_reg->tpg_throttle);
+		val = tpg_data->throttle_pattern;
 	else
-		cam_io_w_mb(0x1111,
-			soc_info->reg_map[0].mem_base + tpg_reg->tpg_throttle);
+		val = 0x1111;
+	cam_io_w_mb(val, soc_info->reg_map[0].mem_base + tpg_reg->tpg_throttle);
+	CAM_DBG(CAM_ISP, "tpg_throttle: 0x%x", val);
 
 	cam_io_w_mb(1, soc_info->reg_map[0].mem_base +
 		tpg_reg->tpg_top_irq_mask);
 
-	val = ((tpg_data->num_active_dts - 1) <<
+	val = ((tpg_data->num_active_vcs - 1) <<
 		(tpg_reg->tpg_num_active_vcs_shift) |
 		(tpg_data->num_active_lanes - 1) <<
 		tpg_reg->tpg_num_active_lanes_shift) |
@@ -382,7 +485,6 @@ static int cam_top_tpg_ver3_stop(
 	struct cam_hw_soc_info                       *soc_info;
 	struct cam_isp_resource_node                 *tpg_res;
 	const struct cam_top_tpg_ver3_reg_offset     *tpg_reg;
-	struct cam_top_tpg_cfg                       *tpg_data;
 
 	if (!hw_priv || !stop_args ||
 		(arg_size != sizeof(struct cam_isp_resource_node))) {
@@ -394,7 +496,6 @@ static int cam_top_tpg_ver3_stop(
 	tpg_hw = (struct cam_top_tpg_hw   *)tpg_hw_info->core_info;
 	tpg_reg = tpg_hw->tpg_info->tpg_reg;
 	tpg_res = (struct cam_isp_resource_node  *) stop_args;
-	tpg_data = (struct cam_top_tpg_cfg  *)tpg_res->res_state;
 	soc_info = &tpg_hw->hw_info->soc_info;
 
 	if ((tpg_res->res_type != CAM_ISP_RESOURCE_TPG) ||
@@ -431,6 +532,7 @@ int cam_top_tpg_ver3_init(
 {
 	tpg_hw->hw_intf->hw_ops.get_hw_caps = cam_top_tpg_ver3_get_hw_caps;
 	tpg_hw->hw_intf->hw_ops.reserve     = cam_top_tpg_ver3_reserve;
+	tpg_hw->hw_intf->hw_ops.release     = cam_top_tpg_ver3_release;
 	tpg_hw->hw_intf->hw_ops.start       = cam_top_tpg_ver3_start;
 	tpg_hw->hw_intf->hw_ops.stop        = cam_top_tpg_ver3_stop;
 	tpg_hw->hw_intf->hw_ops.process_cmd = cam_top_tpg_ver3_process_cmd;