浏览代码

Merge "msm: camera: isp: Add support for clk bw update on config" into camera-kernel.lnx.5.0

Camera Software Integration 4 年之前
父节点
当前提交
fbc548b838

+ 10 - 1
drivers/cam_core/cam_hw_intf.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
 /*
- * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2019, 2021, The Linux Foundation. All rights reserved.
  */
  */
 
 
 #ifndef _CAM_HW_INTF_H_
 #ifndef _CAM_HW_INTF_H_
@@ -13,6 +13,15 @@
  * Interface between HW driver and HW Manager.
  * Interface between HW driver and HW Manager.
  */
  */
 
 
+#define CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ 6
+
+enum cam_clk_bw_state {
+	CAM_CLK_BW_STATE_INIT,
+	CAM_CLK_BW_STATE_UNCHANGED,
+	CAM_CLK_BW_STATE_INCREASE,
+	CAM_CLK_BW_STATE_DECREASE,
+};
+
 /**
 /**
  * struct cam_hw_ops - Hardware layer interface functions
  * struct cam_hw_ops - Hardware layer interface functions
  *
  *

+ 1 - 0
drivers/cam_isp/cam_isp_context.c

@@ -4978,6 +4978,7 @@ static int __cam_isp_ctx_config_dev_in_top_state(
 	cfg.pf_data = &(req->pf_data);
 	cfg.pf_data = &(req->pf_data);
 	cfg.num_out_map_entries = 0;
 	cfg.num_out_map_entries = 0;
 	cfg.num_in_map_entries = 0;
 	cfg.num_in_map_entries = 0;
+	memset(&req_isp->hw_update_data, 0, sizeof(req_isp->hw_update_data));
 	req_isp->hw_update_data.fps = -1;
 	req_isp->hw_update_data.fps = -1;
 	req_isp->hw_update_data.packet = packet;
 	req_isp->hw_update_data.packet = packet;
 
 

+ 186 - 106
drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c

@@ -58,11 +58,50 @@ static struct cam_ife_hw_mgr g_ife_hw_mgr;
 static uint32_t g_num_ife, g_num_ife_lite;
 static uint32_t g_num_ife, g_num_ife_lite;
 static uint32_t max_ife_out_res;
 static uint32_t max_ife_out_res;
 
 
+static int cam_isp_blob_ife_clock_update(
+	struct cam_isp_clock_config           *clock_config,
+	struct cam_ife_hw_mgr_ctx             *ctx);
+
+static int cam_isp_blob_sfe_clock_update(
+	struct cam_isp_clock_config           *clock_config,
+	struct cam_ife_hw_mgr_ctx             *ctx);
+
+
 static int cam_ife_hw_mgr_event_handler(
 static int cam_ife_hw_mgr_event_handler(
 	void                                *priv,
 	void                                *priv,
 	uint32_t                             evt_id,
 	uint32_t                             evt_id,
 	void                                *evt_info);
 	void                                *evt_info);
 
 
+static int cam_ife_mgr_finish_clk_bw_update(
+	struct cam_ife_hw_mgr_ctx             *ctx, uint64_t request_id)
+{
+	int i, rc = 0;
+	struct cam_isp_apply_clk_bw_args clk_bw_args;
+
+	clk_bw_args.request_id = request_id;
+	for (i = 0; i < ctx->num_base; i++) {
+		clk_bw_args.hw_intf = NULL;
+		if (ctx->base[i].hw_type == CAM_ISP_HW_TYPE_VFE)
+			clk_bw_args.hw_intf = g_ife_hw_mgr.ife_devices[ctx->base[i].idx]->hw_intf;
+		else if (ctx->base[i].hw_type == CAM_ISP_HW_TYPE_SFE)
+			clk_bw_args.hw_intf = g_ife_hw_mgr.sfe_devices[ctx->base[i].idx];
+		else
+			continue;
+
+		CAM_DBG(CAM_PERF, "Apply Clock/BW for req_id:%d i:%d hw_idx=%d hw_type:%d",
+			request_id, i, clk_bw_args.hw_intf->hw_idx, clk_bw_args.hw_intf->hw_type);
+		rc |= clk_bw_args.hw_intf->hw_ops.process_cmd(clk_bw_args.hw_intf->hw_priv,
+			CAM_ISP_HW_CMD_APPLY_CLK_BW_UPDATE, &clk_bw_args,
+			sizeof(struct cam_isp_apply_clk_bw_args));
+		if (rc)
+			CAM_ERR(CAM_PERF,
+				"Finish Clock/BW Update failed i:%d hw_idx=%d hw_type:%d rc:%d",
+				i, ctx->base[i].idx, ctx->base[i].hw_type, rc);
+	}
+
+	return rc;
+}
+
 static inline int __cam_ife_mgr_get_hw_soc_info(
 static inline int __cam_ife_mgr_get_hw_soc_info(
 	struct list_head          *res_list,
 	struct list_head          *res_list,
 	enum cam_isp_hw_split_id   split_id,
 	enum cam_isp_hw_split_id   split_id,
@@ -5370,6 +5409,10 @@ static int cam_isp_blob_bw_update_v2(
 				bw_upd_args.node_res =
 				bw_upd_args.node_res =
 					hw_mgr_res->hw_res[split_idx];
 					hw_mgr_res->hw_res[split_idx];
 
 
+				/*
+				 * Update BW values to top, actual apply to hw will happen when
+				 * CAM_ISP_HW_CMD_APPLY_CLK_BW_UPDATE is called
+				 */
 				rc = hw_intf->hw_ops.process_cmd(
 				rc = hw_intf->hw_ops.process_cmd(
 					hw_intf->hw_priv,
 					hw_intf->hw_priv,
 					CAM_ISP_HW_CMD_BW_UPDATE_V2,
 					CAM_ISP_HW_CMD_BW_UPDATE_V2,
@@ -5409,6 +5452,10 @@ static int cam_isp_blob_bw_update_v2(
 				sfe_bw_update_args.node_res =
 				sfe_bw_update_args.node_res =
 					hw_mgr_res->hw_res[split_idx];
 					hw_mgr_res->hw_res[split_idx];
 
 
+				/*
+				 * Update BW values to top, actual apply to hw will happen when
+				 * CAM_ISP_HW_CMD_APPLY_CLK_BW_UPDATE is called
+				 */
 				rc = hw_intf->hw_ops.process_cmd(
 				rc = hw_intf->hw_ops.process_cmd(
 					hw_intf->hw_priv,
 					hw_intf->hw_priv,
 					CAM_ISP_HW_CMD_BW_UPDATE_V2,
 					CAM_ISP_HW_CMD_BW_UPDATE_V2,
@@ -5595,38 +5642,64 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv,
 		ctx->last_cdm_done_req = 0;
 		ctx->last_cdm_done_req = 0;
 	}
 	}
 
 
-	for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) {
-		if (hw_update_data->bw_config_valid[i] == true) {
+	CAM_DBG(CAM_PERF,
+		"ctx_idx=%d, bw_config_version=%d config_valid[BW VFE_CLK SFE_CLK]:[%d %d %d]",
+		ctx->ctx_index, ctx->bw_config_version,
+		hw_update_data->bw_clk_config.bw_config_valid,
+		hw_update_data->bw_clk_config.ife_clock_config_valid,
+		hw_update_data->bw_clk_config.sfe_clock_config_valid);
 
 
-			CAM_DBG(CAM_PERF, "idx=%d, bw_config_version=%d",
-				ctx, ctx->ctx_index, i,
-				hw_update_data->bw_config_version);
+	/*
+	 * Update clock and bw values to top layer, the actual application of these
+	 * votes to hw will happen for all relevant hw indices at once, in a separate
+	 * finish update call
+	 */
+	if (hw_update_data->bw_clk_config.ife_clock_config_valid) {
+		rc = cam_isp_blob_ife_clock_update((struct cam_isp_clock_config *)
+			&hw_update_data->bw_clk_config.ife_clock_config, ctx);
+		if (rc) {
+			CAM_ERR(CAM_PERF, "Clock Update Failed, rc=%d", rc);
+			return rc;
+		}
+	}
 
 
-			if (hw_update_data->bw_config_version ==
-				CAM_ISP_BW_CONFIG_V1) {
-				rc = cam_isp_blob_bw_update(
-					(struct cam_isp_bw_config *)
-					&hw_update_data->bw_config[i], ctx);
-				if (rc)
-					CAM_ERR(CAM_PERF,
-					"Bandwidth Update Failed rc: %d", rc);
-			} else if (hw_update_data->bw_config_version ==
-				CAM_ISP_BW_CONFIG_V2) {
-				rc = cam_isp_blob_bw_update_v2(
-					(struct cam_isp_bw_config_v2 *)
-					&hw_update_data->bw_config_v2[i], ctx);
-				if (rc)
-					CAM_ERR(CAM_PERF,
-					"Bandwidth Update Failed rc: %d", rc);
+	if (hw_update_data->bw_clk_config.sfe_clock_config_valid) {
+		rc = cam_isp_blob_sfe_clock_update((struct cam_isp_clock_config *)
+			&hw_update_data->bw_clk_config.sfe_clock_config, ctx);
+		if (rc) {
+			CAM_ERR(CAM_PERF, "Clock Update Failed, rc=%d", rc);
+			return rc;
+		}
+	}
 
 
-			} else {
-				CAM_ERR(CAM_PERF,
-					"Invalid bw config version: %d",
-					hw_update_data->bw_config_version);
+	if (hw_update_data->bw_clk_config.bw_config_valid) {
+		if (ctx->bw_config_version == CAM_ISP_BW_CONFIG_V1) {
+			rc = cam_isp_blob_bw_update(
+				(struct cam_isp_bw_config *)
+				&hw_update_data->bw_clk_config.bw_config, ctx);
+			if (rc) {
+				CAM_ERR(CAM_PERF, "Bandwidth Update Failed rc: %d", rc);
+				return rc;
+			}
+		} else if (ctx->bw_config_version == CAM_ISP_BW_CONFIG_V2) {
+			rc = cam_isp_blob_bw_update_v2((struct cam_isp_bw_config_v2 *)
+				&hw_update_data->bw_clk_config.bw_config_v2, ctx);
+			if (rc) {
+				CAM_ERR(CAM_PERF, "Bandwidth Update Failed rc: %d", rc);
+				return rc;
 			}
 			}
+		} else {
+			CAM_ERR(CAM_PERF, "Invalid bw config version: %d", ctx->bw_config_version);
 		}
 		}
 	}
 	}
 
 
+	/* Apply the updated values in top layer to the HW*/
+	rc = cam_ife_mgr_finish_clk_bw_update(ctx, cfg->request_id);
+	if (rc) {
+		CAM_ERR(CAM_ISP, "Failed in finishing clk/bw update rc: %d", rc);
+		return rc;
+	}
+
 	CAM_DBG(CAM_ISP,
 	CAM_DBG(CAM_ISP,
 		"Enter ctx id:%d num_hw_upd_entries %d request id: %llu",
 		"Enter ctx id:%d num_hw_upd_entries %d request id: %llu",
 		ctx->ctx_index, cfg->num_hw_update_entries, cfg->request_id);
 		ctx->ctx_index, cfg->num_hw_update_entries, cfg->request_id);
@@ -5774,11 +5847,11 @@ static int cam_ife_mgr_stop_hw_in_overflow(void *stop_hw_args)
 }
 }
 
 
 static int cam_ife_mgr_bw_control(struct cam_ife_hw_mgr_ctx *ctx,
 static int cam_ife_mgr_bw_control(struct cam_ife_hw_mgr_ctx *ctx,
-	enum cam_vfe_bw_control_action action)
+	enum cam_isp_bw_control_action action)
 {
 {
 	struct cam_isp_hw_mgr_res             *hw_mgr_res;
 	struct cam_isp_hw_mgr_res             *hw_mgr_res;
 	struct cam_hw_intf                    *hw_intf;
 	struct cam_hw_intf                    *hw_intf;
-	struct cam_vfe_bw_control_args         bw_ctrl_args;
+	struct cam_isp_bw_control_args         bw_ctrl_args;
 	int                                    rc = -EINVAL;
 	int                                    rc = -EINVAL;
 	uint32_t                               i;
 	uint32_t                               i;
 
 
@@ -5799,7 +5872,30 @@ static int cam_ife_mgr_bw_control(struct cam_ife_hw_mgr_ctx *ctx,
 					hw_intf->hw_priv,
 					hw_intf->hw_priv,
 					CAM_ISP_HW_CMD_BW_CONTROL,
 					CAM_ISP_HW_CMD_BW_CONTROL,
 					&bw_ctrl_args,
 					&bw_ctrl_args,
-					sizeof(struct cam_vfe_bw_control_args));
+					sizeof(struct cam_isp_bw_control_args));
+				if (rc)
+					CAM_ERR(CAM_ISP, "BW Update failed");
+			} else
+				CAM_WARN(CAM_ISP, "NULL hw_intf!");
+		}
+	}
+
+	list_for_each_entry(hw_mgr_res, &ctx->res_list_sfe_src, list) {
+		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
+			if (!hw_mgr_res->hw_res[i])
+				continue;
+
+			hw_intf = hw_mgr_res->hw_res[i]->hw_intf;
+			if (hw_intf && hw_intf->hw_ops.process_cmd) {
+				bw_ctrl_args.node_res =
+					hw_mgr_res->hw_res[i];
+				bw_ctrl_args.action = action;
+
+				rc = hw_intf->hw_ops.process_cmd(
+					hw_intf->hw_priv,
+					CAM_ISP_HW_CMD_BW_CONTROL,
+					&bw_ctrl_args,
+					sizeof(struct cam_isp_bw_control_args));
 				if (rc)
 				if (rc)
 					CAM_ERR(CAM_ISP, "BW Update failed");
 					CAM_ERR(CAM_ISP, "BW Update failed");
 			} else
 			} else
@@ -5812,7 +5908,7 @@ static int cam_ife_mgr_bw_control(struct cam_ife_hw_mgr_ctx *ctx,
 
 
 static int cam_ife_mgr_pause_hw(struct cam_ife_hw_mgr_ctx *ctx)
 static int cam_ife_mgr_pause_hw(struct cam_ife_hw_mgr_ctx *ctx)
 {
 {
-	return cam_ife_mgr_bw_control(ctx, CAM_VFE_BW_CONTROL_EXCLUDE);
+	return cam_ife_mgr_bw_control(ctx, CAM_ISP_BW_CONTROL_EXCLUDE);
 }
 }
 
 
 /* entry function: stop_hw */
 /* entry function: stop_hw */
@@ -7640,30 +7736,21 @@ static int cam_isp_blob_sfe_core_cfg_update(
 	return rc;
 	return rc;
 }
 }
 
 
-static int cam_isp_blob_clock_update(
-	uint32_t                               blob_type,
-	struct cam_isp_generic_blob_info      *blob_info,
+static int cam_isp_blob_ife_clock_update(
 	struct cam_isp_clock_config           *clock_config,
 	struct cam_isp_clock_config           *clock_config,
-	struct cam_hw_prepare_update_args     *prepare)
+	struct cam_ife_hw_mgr_ctx             *ctx)
 {
 {
-	struct cam_ife_hw_mgr_ctx             *ctx = NULL;
 	struct cam_isp_hw_mgr_res             *hw_mgr_res;
 	struct cam_isp_hw_mgr_res             *hw_mgr_res;
 	struct cam_hw_intf                    *hw_intf;
 	struct cam_hw_intf                    *hw_intf;
 	struct cam_vfe_clock_update_args       clock_upd_args;
 	struct cam_vfe_clock_update_args       clock_upd_args;
 	uint64_t                               clk_rate = 0;
 	uint64_t                               clk_rate = 0;
 	int                                    rc = -EINVAL;
 	int                                    rc = -EINVAL;
-	uint32_t                               i;
-	uint32_t                               j;
+	uint32_t                               i, j;
 	bool                                   camif_l_clk_updated = false;
 	bool                                   camif_l_clk_updated = false;
 	bool                                   camif_r_clk_updated = false;
 	bool                                   camif_r_clk_updated = false;
 
 
-	ctx = prepare->ctxt_to_hw_map;
-
-	CAM_DBG(CAM_PERF,
-		"usage=%u left_clk= %lu right_clk=%lu",
-		clock_config->usage_type,
-		clock_config->left_pix_hz,
-		clock_config->right_pix_hz);
+	CAM_DBG(CAM_PERF, "IFE clk update usage=%u left_clk= %lu right_clk=%lu",
+		clock_config->usage_type, clock_config->left_pix_hz, clock_config->right_pix_hz);
 
 
 	list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
 	list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
 		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
 		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
@@ -7671,26 +7758,9 @@ static int cam_isp_blob_clock_update(
 			if (!hw_mgr_res->hw_res[i])
 			if (!hw_mgr_res->hw_res[i])
 				continue;
 				continue;
 
 
-			if (hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF) {
-				if (i == CAM_ISP_HW_SPLIT_LEFT) {
-					if (camif_l_clk_updated)
-						continue;
-
-					clk_rate =
-						clock_config->left_pix_hz;
-
-					camif_l_clk_updated = true;
-				} else {
-					if (camif_r_clk_updated)
-						continue;
-
-					clk_rate =
-						clock_config->right_pix_hz;
-
-					camif_r_clk_updated = true;
-				}
-			} else if (hw_mgr_res->res_id ==
-				CAM_ISP_HW_VFE_IN_PDLIB) {
+			if ((hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF) ||
+				(hw_mgr_res->res_id ==
+				CAM_ISP_HW_VFE_IN_PDLIB)) {
 				if (i == CAM_ISP_HW_SPLIT_LEFT) {
 				if (i == CAM_ISP_HW_SPLIT_LEFT) {
 					if (camif_l_clk_updated)
 					if (camif_l_clk_updated)
 						continue;
 						continue;
@@ -7725,38 +7795,43 @@ static int cam_isp_blob_clock_update(
 
 
 			hw_intf = hw_mgr_res->hw_res[i]->hw_intf;
 			hw_intf = hw_mgr_res->hw_res[i]->hw_intf;
 			if (hw_intf && hw_intf->hw_ops.process_cmd) {
 			if (hw_intf && hw_intf->hw_ops.process_cmd) {
-				clock_upd_args.node_res =
-					hw_mgr_res->hw_res[i];
+				clock_upd_args.node_res = hw_mgr_res->hw_res[i];
 				CAM_DBG(CAM_PERF,
 				CAM_DBG(CAM_PERF,
-				"res_id=%u i= %d clk=%llu\n",
-				hw_mgr_res->res_id, i, clk_rate);
+					"Update Clock value res_id=%u i= %d clk=%llu",
+					hw_mgr_res->res_id, i, clk_rate);
 
 
 				clock_upd_args.clk_rate = clk_rate;
 				clock_upd_args.clk_rate = clk_rate;
 
 
+				/*
+				 * Update clock values to top, actual apply to hw will happen when
+				 * CAM_ISP_HW_CMD_APPLY_CLK_BW_UPDATE is called
+				 */
 				rc = hw_intf->hw_ops.process_cmd(
 				rc = hw_intf->hw_ops.process_cmd(
 					hw_intf->hw_priv,
 					hw_intf->hw_priv,
 					CAM_ISP_HW_CMD_CLOCK_UPDATE,
 					CAM_ISP_HW_CMD_CLOCK_UPDATE,
 					&clock_upd_args,
 					&clock_upd_args,
 					sizeof(
 					sizeof(
 					struct cam_vfe_clock_update_args));
 					struct cam_vfe_clock_update_args));
-				if (rc)
+				if (rc) {
 					CAM_ERR(CAM_PERF,
 					CAM_ERR(CAM_PERF,
-						"Clock Update failed");
+						"IFE:%d Clock Update failed clk_rate:%llu rc:%d",
+						hw_intf->hw_idx, clk_rate, rc);
+					goto end;
+				}
 			} else
 			} else
 				CAM_WARN(CAM_ISP, "NULL hw_intf!");
 				CAM_WARN(CAM_ISP, "NULL hw_intf!");
 		}
 		}
 	}
 	}
 
 
+end:
 	return rc;
 	return rc;
 }
 }
 
 
+
 static int cam_isp_blob_sfe_clock_update(
 static int cam_isp_blob_sfe_clock_update(
-	uint32_t                               blob_type,
-	struct cam_isp_generic_blob_info      *blob_info,
 	struct cam_isp_clock_config           *clock_config,
 	struct cam_isp_clock_config           *clock_config,
-	struct cam_hw_prepare_update_args     *prepare)
+	struct cam_ife_hw_mgr_ctx             *ctx)
 {
 {
-	struct cam_ife_hw_mgr_ctx             *ctx = NULL;
 	struct cam_isp_hw_mgr_res             *hw_mgr_res;
 	struct cam_isp_hw_mgr_res             *hw_mgr_res;
 	struct cam_hw_intf                    *hw_intf;
 	struct cam_hw_intf                    *hw_intf;
 	struct cam_sfe_clock_update_args       clock_upd_args;
 	struct cam_sfe_clock_update_args       clock_upd_args;
@@ -7766,13 +7841,10 @@ static int cam_isp_blob_sfe_clock_update(
 	bool                                   l_clk_updated = false;
 	bool                                   l_clk_updated = false;
 	bool                                   r_clk_updated = false;
 	bool                                   r_clk_updated = false;
 
 
-	ctx = prepare->ctxt_to_hw_map;
 
 
 	CAM_DBG(CAM_PERF,
 	CAM_DBG(CAM_PERF,
 		"SFE clk update usage: %u left_clk: %lu right_clk: %lu",
 		"SFE clk update usage: %u left_clk: %lu right_clk: %lu",
-		clock_config->usage_type,
-		clock_config->left_pix_hz,
-		clock_config->right_pix_hz);
+		clock_config->usage_type, clock_config->left_pix_hz, clock_config->right_pix_hz);
 
 
 	list_for_each_entry(hw_mgr_res, &ctx->res_list_sfe_src, list) {
 	list_for_each_entry(hw_mgr_res, &ctx->res_list_sfe_src, list) {
 		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
 		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
@@ -7811,6 +7883,10 @@ static int cam_isp_blob_sfe_clock_update(
 				hw_mgr_res->res_id, i, clk_rate);
 				hw_mgr_res->res_id, i, clk_rate);
 
 
 				clock_upd_args.clk_rate = clk_rate;
 				clock_upd_args.clk_rate = clk_rate;
+				/*
+				 * Update clock values to top, actual apply to hw will happen when
+				 * CAM_ISP_HW_CMD_APPLY_CLK_BW_UPDATE is called
+				 */
 				rc = hw_intf->hw_ops.process_cmd(
 				rc = hw_intf->hw_ops.process_cmd(
 					hw_intf->hw_priv,
 					hw_intf->hw_priv,
 					CAM_ISP_HW_CMD_CLOCK_UPDATE,
 					CAM_ISP_HW_CMD_CLOCK_UPDATE,
@@ -8189,7 +8265,9 @@ static int cam_isp_packet_generic_blob_handler(void *user_data,
 	}
 	}
 		break;
 		break;
 	case CAM_ISP_GENERIC_BLOB_TYPE_CLOCK_CONFIG: {
 	case CAM_ISP_GENERIC_BLOB_TYPE_CLOCK_CONFIG: {
+		size_t clock_config_size = 0;
 		struct cam_isp_clock_config    *clock_config;
 		struct cam_isp_clock_config    *clock_config;
+		struct cam_isp_prepare_hw_update_data   *prepare_hw_data;
 
 
 		if (blob_size < sizeof(struct cam_isp_clock_config)) {
 		if (blob_size < sizeof(struct cam_isp_clock_config)) {
 			CAM_ERR(CAM_ISP, "Invalid blob size %u", blob_size);
 			CAM_ERR(CAM_ISP, "Invalid blob size %u", blob_size);
@@ -8227,10 +8305,14 @@ static int cam_isp_packet_generic_blob_handler(void *user_data,
 			return -EINVAL;
 			return -EINVAL;
 		}
 		}
 
 
-		rc = cam_isp_blob_clock_update(blob_type, blob_info,
-			clock_config, prepare);
-		if (rc)
-			CAM_ERR(CAM_PERF, "Clock Update Failed, rc=%d", rc);
+		prepare_hw_data = (struct cam_isp_prepare_hw_update_data  *)
+			prepare->priv;
+		clock_config_size = sizeof(struct cam_isp_clock_config) +
+			((clock_config->num_rdi - 1) *
+			sizeof(clock_config->rdi_hz));
+		memcpy(&prepare_hw_data->bw_clk_config.ife_clock_config, clock_config,
+			clock_config_size);
+		prepare_hw_data->bw_clk_config.ife_clock_config_valid = true;
 	}
 	}
 		break;
 		break;
 	case CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG: {
 	case CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG: {
@@ -8277,7 +8359,7 @@ static int cam_isp_packet_generic_blob_handler(void *user_data,
 		}
 		}
 
 
 		if (!prepare || !prepare->priv ||
 		if (!prepare || !prepare->priv ||
-			(bw_config->usage_type >= CAM_IFE_HW_NUM_MAX)) {
+			(bw_config->usage_type >= CAM_ISP_HW_USAGE_TYPE_MAX)) {
 			CAM_ERR(CAM_ISP, "Invalid inputs usage type %d",
 			CAM_ERR(CAM_ISP, "Invalid inputs usage type %d",
 				bw_config->usage_type);
 				bw_config->usage_type);
 			return -EINVAL;
 			return -EINVAL;
@@ -8286,10 +8368,10 @@ static int cam_isp_packet_generic_blob_handler(void *user_data,
 		prepare_hw_data = (struct cam_isp_prepare_hw_update_data  *)
 		prepare_hw_data = (struct cam_isp_prepare_hw_update_data  *)
 			prepare->priv;
 			prepare->priv;
 
 
-		memcpy(&prepare_hw_data->bw_config[bw_config->usage_type],
-			bw_config, sizeof(prepare_hw_data->bw_config[0]));
-		prepare_hw_data->bw_config_version = CAM_ISP_BW_CONFIG_V1;
-		prepare_hw_data->bw_config_valid[bw_config->usage_type] = true;
+		memcpy(&prepare_hw_data->bw_clk_config.bw_config, bw_config,
+			sizeof(prepare_hw_data->bw_clk_config.bw_config));
+		ife_mgr_ctx->bw_config_version = CAM_ISP_BW_CONFIG_V1;
+		prepare_hw_data->bw_clk_config.bw_config_valid = true;
 	}
 	}
 		break;
 		break;
 	case CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG_V2: {
 	case CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG_V2: {
@@ -8339,7 +8421,7 @@ static int cam_isp_packet_generic_blob_handler(void *user_data,
 		}
 		}
 
 
 		if (!prepare || !prepare->priv ||
 		if (!prepare || !prepare->priv ||
-			(bw_config->usage_type >= CAM_IFE_HW_NUM_MAX)) {
+			(bw_config->usage_type >= CAM_ISP_HW_USAGE_TYPE_MAX)) {
 			CAM_ERR(CAM_ISP, "Invalid inputs usage type %d",
 			CAM_ERR(CAM_ISP, "Invalid inputs usage type %d",
 				bw_config->usage_type);
 				bw_config->usage_type);
 			return -EINVAL;
 			return -EINVAL;
@@ -8348,17 +8430,16 @@ static int cam_isp_packet_generic_blob_handler(void *user_data,
 		prepare_hw_data = (struct cam_isp_prepare_hw_update_data  *)
 		prepare_hw_data = (struct cam_isp_prepare_hw_update_data  *)
 			prepare->priv;
 			prepare->priv;
 
 
-		memset(&prepare_hw_data->bw_config_v2[bw_config->usage_type],
-			0, sizeof(
-			prepare_hw_data->bw_config_v2[bw_config->usage_type]));
+		memset(&prepare_hw_data->bw_clk_config.bw_config_v2, 0,
+			sizeof(prepare_hw_data->bw_clk_config.bw_config_v2));
 		bw_config_size = sizeof(struct cam_isp_bw_config_v2) +
 		bw_config_size = sizeof(struct cam_isp_bw_config_v2) +
 			((bw_config->num_paths - 1) *
 			((bw_config->num_paths - 1) *
 			sizeof(struct cam_axi_per_path_bw_vote));
 			sizeof(struct cam_axi_per_path_bw_vote));
-		memcpy(&prepare_hw_data->bw_config_v2[bw_config->usage_type],
-			bw_config, bw_config_size);
+		memcpy(&prepare_hw_data->bw_clk_config.bw_config_v2, bw_config,
+			bw_config_size);
 
 
-		prepare_hw_data->bw_config_version = CAM_ISP_BW_CONFIG_V2;
-		prepare_hw_data->bw_config_valid[bw_config->usage_type] = true;
+		ife_mgr_ctx->bw_config_version = CAM_ISP_BW_CONFIG_V2;
+		prepare_hw_data->bw_clk_config.bw_config_valid = true;
 	}
 	}
 		break;
 		break;
 	case CAM_ISP_GENERIC_BLOB_TYPE_UBWC_CONFIG: {
 	case CAM_ISP_GENERIC_BLOB_TYPE_UBWC_CONFIG: {
@@ -8782,7 +8863,9 @@ static int cam_sfe_packet_generic_blob_handler(void *user_data,
 
 
 	switch (blob_type) {
 	switch (blob_type) {
 	case CAM_ISP_GENERIC_BLOB_TYPE_SFE_CLOCK_CONFIG: {
 	case CAM_ISP_GENERIC_BLOB_TYPE_SFE_CLOCK_CONFIG: {
+		size_t clock_config_size = 0;
 		struct cam_isp_clock_config    *clock_config;
 		struct cam_isp_clock_config    *clock_config;
+		struct cam_isp_prepare_hw_update_data *prepare_hw_data;
 
 
 		if (blob_size < sizeof(struct cam_isp_clock_config)) {
 		if (blob_size < sizeof(struct cam_isp_clock_config)) {
 			CAM_ERR(CAM_ISP, "Invalid blob size %u", blob_size);
 			CAM_ERR(CAM_ISP, "Invalid blob size %u", blob_size);
@@ -8820,10 +8903,14 @@ static int cam_sfe_packet_generic_blob_handler(void *user_data,
 			return -EINVAL;
 			return -EINVAL;
 		}
 		}
 
 
-		rc = cam_isp_blob_sfe_clock_update(blob_type, blob_info,
-			clock_config, prepare);
-		if (rc)
-			CAM_ERR(CAM_PERF, "Clock Update Failed, rc=%d", rc);
+		prepare_hw_data = (struct cam_isp_prepare_hw_update_data  *)
+			prepare->priv;
+		clock_config_size = sizeof(struct cam_isp_clock_config) +
+			((clock_config->num_rdi - 1) *
+			sizeof(clock_config->rdi_hz));
+		memcpy(&prepare_hw_data->bw_clk_config.sfe_clock_config, clock_config,
+			clock_config_size);
+		prepare_hw_data->bw_clk_config.sfe_clock_config_valid = true;
 	}
 	}
 		break;
 		break;
 	case CAM_ISP_GENERIC_BLOB_TYPE_SFE_OUT_CONFIG: {
 	case CAM_ISP_GENERIC_BLOB_TYPE_SFE_OUT_CONFIG: {
@@ -9647,13 +9734,6 @@ static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv,
 	prepare->num_out_map_entries = 0;
 	prepare->num_out_map_entries = 0;
 	prepare->num_reg_dump_buf = 0;
 	prepare->num_reg_dump_buf = 0;
 
 
-	memset(&prepare_hw_data->bw_config[0], 0x0,
-		sizeof(prepare_hw_data->bw_config[0]) *
-		CAM_IFE_HW_NUM_MAX);
-	memset(&prepare_hw_data->bw_config_valid[0], 0x0,
-		sizeof(prepare_hw_data->bw_config_valid[0]) *
-		CAM_IFE_HW_NUM_MAX);
-
 	/* Assign IFE RD for non SFE targets */
 	/* Assign IFE RD for non SFE targets */
 	if (ctx->ctx_type != CAM_IFE_CTX_TYPE_SFE)
 	if (ctx->ctx_type != CAM_IFE_CTX_TYPE_SFE)
 		res_list_ife_rd_tmp = &ctx->res_list_ife_in_rd;
 		res_list_ife_rd_tmp = &ctx->res_list_ife_in_rd;
@@ -9858,7 +9938,7 @@ end:
 
 
 static int cam_ife_mgr_resume_hw(struct cam_ife_hw_mgr_ctx *ctx)
 static int cam_ife_mgr_resume_hw(struct cam_ife_hw_mgr_ctx *ctx)
 {
 {
-	return cam_ife_mgr_bw_control(ctx, CAM_VFE_BW_CONTROL_INCLUDE);
+	return cam_ife_mgr_bw_control(ctx, CAM_ISP_BW_CONTROL_INCLUDE);
 }
 }
 
 
 static int cam_ife_mgr_sof_irq_debug(
 static int cam_ife_mgr_sof_irq_debug(

+ 2 - 0
drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h

@@ -207,6 +207,7 @@ struct cam_ife_hw_mgr_ctx_flags {
  * @buf_done_controller     Buf done controller.
  * @buf_done_controller     Buf done controller.
  * @sfe_info                SFE info pertaining to this stream
  * @sfe_info                SFE info pertaining to this stream
  * @flags                   Flags pertainting to this ctx
  * @flags                   Flags pertainting to this ctx
+ * @bw_config_version       BW Config version
  *
  *
  */
  */
 struct cam_ife_hw_mgr_ctx {
 struct cam_ife_hw_mgr_ctx {
@@ -256,6 +257,7 @@ struct cam_ife_hw_mgr_ctx {
 	void                           *buf_done_controller;
 	void                           *buf_done_controller;
 	struct cam_ife_hw_mgr_sfe_info  sfe_info;
 	struct cam_ife_hw_mgr_sfe_info  sfe_info;
 	struct cam_ife_hw_mgr_ctx_flags flags;
 	struct cam_ife_hw_mgr_ctx_flags flags;
+	uint32_t                        bw_config_version;
 };
 };
 
 
 /**
 /**

+ 20 - 32
drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c

@@ -2660,24 +2660,20 @@ static int cam_tfe_mgr_config_hw(void *hw_mgr_priv,
 		ctx->last_cdm_done_req = 0;
 		ctx->last_cdm_done_req = 0;
 	}
 	}
 
 
-	for (i = 0; i < CAM_TFE_HW_NUM_MAX; i++) {
-		if (hw_update_data->bw_config_valid[i] == true) {
-
-			CAM_DBG(CAM_ISP, "idx=%d, bw_config_version=%d",
-				ctx->ctx_index, i,
-				hw_update_data->bw_config_version);
-			if (hw_update_data->bw_config_version ==
-				CAM_ISP_BW_CONFIG_V2) {
-				rc = cam_isp_tfe_blob_bw_update(
-					&hw_update_data->bw_config_v2[i], ctx);
-				if (rc)
-					CAM_ERR(CAM_ISP,
-					"Bandwidth Update Failed rc: %d", rc);
-			} else {
+	if (hw_update_data->bw_clk_config.bw_config_valid) {
+		CAM_DBG(CAM_ISP, "idx=%d, bw_config_version=%d", ctx->ctx_index,
+			ctx->bw_config_version);
+		if (ctx->bw_config_version ==
+			CAM_ISP_BW_CONFIG_V2) {
+			rc = cam_isp_tfe_blob_bw_update(
+				&hw_update_data->bw_clk_config.bw_config_v2, ctx);
+			if (rc)
 				CAM_ERR(CAM_ISP,
 				CAM_ERR(CAM_ISP,
-					"Invalid bw config version: %d",
-					hw_update_data->bw_config_version);
-			}
+				"Bandwidth Update Failed rc: %d", rc);
+		} else {
+			CAM_ERR(CAM_ISP,
+				"Invalid bw config version: %d",
+				ctx->bw_config_version);
 		}
 		}
 	}
 	}
 
 
@@ -3869,6 +3865,7 @@ static int cam_isp_tfe_packet_generic_blob_handler(void *user_data,
 	int rc = 0;
 	int rc = 0;
 	struct cam_isp_generic_blob_info  *blob_info = user_data;
 	struct cam_isp_generic_blob_info  *blob_info = user_data;
 	struct cam_hw_prepare_update_args *prepare = NULL;
 	struct cam_hw_prepare_update_args *prepare = NULL;
+	struct cam_tfe_hw_mgr_ctx *tfe_mgr_ctx = NULL;
 
 
 	if (!blob_data || (blob_size == 0) || !blob_info) {
 	if (!blob_data || (blob_size == 0) || !blob_info) {
 		CAM_ERR(CAM_ISP, "Invalid args data %pK size %d info %pK",
 		CAM_ERR(CAM_ISP, "Invalid args data %pK size %d info %pK",
@@ -3883,6 +3880,7 @@ static int cam_isp_tfe_packet_generic_blob_handler(void *user_data,
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
+	tfe_mgr_ctx = prepare->ctxt_to_hw_map;
 	CAM_DBG(CAM_ISP, "BLOB Type: %d", blob_type);
 	CAM_DBG(CAM_ISP, "BLOB Type: %d", blob_type);
 	switch (blob_type) {
 	switch (blob_type) {
 	case CAM_ISP_TFE_GENERIC_BLOB_TYPE_HFR_CONFIG: {
 	case CAM_ISP_TFE_GENERIC_BLOB_TYPE_HFR_CONFIG: {
@@ -4031,19 +4029,16 @@ static int cam_isp_tfe_packet_generic_blob_handler(void *user_data,
 		prepare_hw_data = (struct cam_isp_prepare_hw_update_data  *)
 		prepare_hw_data = (struct cam_isp_prepare_hw_update_data  *)
 			prepare->priv;
 			prepare->priv;
 
 
-		memset(&prepare_hw_data->bw_config_v2[bw_config->usage_type],
-			0, sizeof(
-			prepare_hw_data->bw_config_v2[bw_config->usage_type]));
+		memset(&prepare_hw_data->bw_clk_config.bw_config_v2,
+			0, sizeof(prepare_hw_data->bw_clk_config.bw_config_v2));
 		bw_config_size = sizeof(struct cam_isp_tfe_bw_config_v2) +
 		bw_config_size = sizeof(struct cam_isp_tfe_bw_config_v2) +
 			((bw_config->num_paths - 1) *
 			((bw_config->num_paths - 1) *
 			sizeof(struct cam_axi_per_path_bw_vote));
 			sizeof(struct cam_axi_per_path_bw_vote));
-		memcpy(&prepare_hw_data->bw_config_v2[bw_config->usage_type],
-			bw_config, bw_config_size);
+		memcpy(&prepare_hw_data->bw_clk_config.bw_config_v2, bw_config, bw_config_size);
 
 
-		prepare_hw_data->bw_config_version = CAM_ISP_BW_CONFIG_V2;
-		prepare_hw_data->bw_config_valid[bw_config->usage_type] = true;
+		tfe_mgr_ctx->bw_config_version = CAM_ISP_BW_CONFIG_V2;
+		prepare_hw_data->bw_clk_config.bw_config_valid = true;
 	}
 	}
-
 		break;
 		break;
 	case CAM_ISP_TFE_GENERIC_BLOB_TYPE_CSID_CLOCK_CONFIG: {
 	case CAM_ISP_TFE_GENERIC_BLOB_TYPE_CSID_CLOCK_CONFIG: {
 		struct cam_isp_tfe_csid_clock_config    *clock_config =
 		struct cam_isp_tfe_csid_clock_config    *clock_config =
@@ -4394,13 +4389,6 @@ static int cam_tfe_mgr_prepare_hw_update(void *hw_mgr_priv,
 	prepare->num_out_map_entries = 0;
 	prepare->num_out_map_entries = 0;
 	prepare->num_reg_dump_buf = 0;
 	prepare->num_reg_dump_buf = 0;
 
 
-	memset(&prepare_hw_data->bw_config[0], 0x0,
-		sizeof(prepare_hw_data->bw_config[0]) *
-		CAM_TFE_HW_NUM_MAX);
-	memset(&prepare_hw_data->bw_config_valid[0], 0x0,
-		sizeof(prepare_hw_data->bw_config_valid[0]) *
-		CAM_TFE_HW_NUM_MAX);
-
 	for (i = 0; i < ctx->num_base; i++) {
 	for (i = 0; i < ctx->num_base; i++) {
 		CAM_DBG(CAM_ISP, "process cmd buffer for device %d", i);
 		CAM_DBG(CAM_ISP, "process cmd buffer for device %d", i);
 
 

+ 3 - 1
drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.h

@@ -82,7 +82,8 @@ struct cam_tfe_hw_mgr_debug {
  * @slave_hw_idx              slave hardware index in dual tfe case
  * @slave_hw_idx              slave hardware index in dual tfe case
  * @dual_tfe_irq_mismatch_cnt irq mismatch count value per core, used for
  * @dual_tfe_irq_mismatch_cnt irq mismatch count value per core, used for
  *                              dual TFE
  *                              dual TFE
- * packet                     CSL packet from user mode driver
+ * @packet                     CSL packet from user mode driver
+ * @bw_config_version          BW Config version
  */
  */
 struct cam_tfe_hw_mgr_ctx {
 struct cam_tfe_hw_mgr_ctx {
 	struct list_head                list;
 	struct list_head                list;
@@ -124,6 +125,7 @@ struct cam_tfe_hw_mgr_ctx {
 	uint32_t                        slave_hw_idx;
 	uint32_t                        slave_hw_idx;
 	uint32_t                        dual_tfe_irq_mismatch_cnt;
 	uint32_t                        dual_tfe_irq_mismatch_cnt;
 	struct cam_packet              *packet;
 	struct cam_packet              *packet;
+	uint32_t                        bw_config_version;
 };
 };
 
 
 /**
 /**

+ 45 - 10
drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h

@@ -104,7 +104,25 @@ struct cam_isp_stop_args {
 	bool                          stop_only;
 	bool                          stop_only;
 };
 };
 
 
-
+/**
+ * struct cam_isp_clock_config_internal - Clock configuration
+ *
+ * @usage_type:                 Usage type (Single/Dual)
+ * @num_rdi:                    Number of RDI votes
+ * @left_pix_hz:                Pixel Clock for Left ISP
+ * @right_pix_hz:               Pixel Clock for Right ISP, valid only if Dual
+ * @rdi_hz:                     RDI Clock. ISP clock will be max of RDI and
+ *                              PIX clocks. For a particular context which ISP
+ *                              HW the RDI is allocated to is not known to UMD.
+ *                              Hence pass the clock and let KMD decide.
+ */
+struct cam_isp_clock_config_internal {
+	uint64_t                       usage_type;
+	uint64_t                       num_rdi;
+	uint64_t                       left_pix_hz;
+	uint64_t                       right_pix_hz;
+	uint64_t                       rdi_hz[CAM_IFE_RDI_NUM_MAX];
+};
 
 
 /**
 /**
  * struct cam_isp_bw_config_internal_v2 - Bandwidth configuration
  * struct cam_isp_bw_config_internal_v2 - Bandwidth configuration
@@ -136,6 +154,30 @@ struct cam_isp_bw_config_internal {
 	struct cam_isp_bw_vote         rdi_vote[CAM_IFE_RDI_NUM_MAX];
 	struct cam_isp_bw_vote         rdi_vote[CAM_IFE_RDI_NUM_MAX];
 };
 };
 
 
+/**
+ * struct cam_isp_bw_clk_config_info - Bw/Clk config info
+ *
+ * @bw_config  :            BW vote info for current request V1
+ * @bw_config_v2:           BW vote info for current request V2
+ * @bw_config_valid:        Flag indicating if BW vote is valid for current request
+ * @ife_clock_config:       Clock config information for ife
+ * @ife_clock_config_valid: Flag indicating whether clock config is valid for
+ *                          current request for ife
+ * @sfe_clock_config:       Clock config information for sfe
+ * @sfe_clock_config_valid: Flag indicating whether clock config is valid for
+ *                          current request for sfe
+ */
+struct cam_isp_bw_clk_config_info {
+	struct cam_isp_bw_config_internal     bw_config;
+	struct cam_isp_bw_config_internal_v2  bw_config_v2;
+	bool                                  bw_config_valid;
+	struct cam_isp_clock_config_internal  ife_clock_config;
+	bool                                  ife_clock_config_valid;
+	struct cam_isp_clock_config_internal  sfe_clock_config;
+	bool                                  sfe_clock_config_valid;
+
+};
+
 /**
 /**
  * struct cam_isp_prepare_hw_update_data - hw prepare data
  * struct cam_isp_prepare_hw_update_data - hw prepare data
  *
  *
@@ -146,11 +188,7 @@ struct cam_isp_bw_config_internal {
  * @frame_header_cpu_addr:  Frame header cpu addr
  * @frame_header_cpu_addr:  Frame header cpu addr
  * @frame_header_iova:      Frame header iova
  * @frame_header_iova:      Frame header iova
  * @frame_header_res_id:    Out port res_id corresponding to frame header
  * @frame_header_res_id:    Out port res_id corresponding to frame header
- * @bw_config_version:      BW config version indicator
- * @bw_config:              BW config information
- * @bw_config_v2:           BW config info for AXI bw voting v2
- * @bw_config_valid:        Flag indicating whether the bw_config at the index
- *                          is valid or not
+ * @bw_clk_config:          BW and clock config info
  * @reg_dump_buf_desc:     cmd buffer descriptors for reg dump
  * @reg_dump_buf_desc:     cmd buffer descriptors for reg dump
  * @num_reg_dump_buf:      Count of descriptors in reg_dump_buf_desc
  * @num_reg_dump_buf:      Count of descriptors in reg_dump_buf_desc
  * @packet                 CSL packet from user mode driver
  * @packet                 CSL packet from user mode driver
@@ -164,10 +202,7 @@ struct cam_isp_prepare_hw_update_data {
 	uint32_t                             *frame_header_cpu_addr;
 	uint32_t                             *frame_header_cpu_addr;
 	uint64_t                              frame_header_iova;
 	uint64_t                              frame_header_iova;
 	uint32_t                              frame_header_res_id;
 	uint32_t                              frame_header_res_id;
-	uint32_t                              bw_config_version;
-	struct cam_isp_bw_config_internal     bw_config[CAM_IFE_HW_NUM_MAX];
-	struct cam_isp_bw_config_internal_v2  bw_config_v2[CAM_IFE_HW_NUM_MAX];
-	bool                               bw_config_valid[CAM_IFE_HW_NUM_MAX];
+	struct cam_isp_bw_clk_config_info     bw_clk_config;
 	struct cam_cmd_buf_desc               reg_dump_buf_desc[
 	struct cam_cmd_buf_desc               reg_dump_buf_desc[
 						CAM_REG_DUMP_MAX_BUF_ENTRIES];
 						CAM_REG_DUMP_MAX_BUF_ENTRIES];
 	uint32_t                              num_reg_dump_buf;
 	uint32_t                              num_reg_dump_buf;

+ 34 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h

@@ -27,6 +27,33 @@
  */
  */
 #define CAM_ISP_RES_NAME_LEN      16
 #define CAM_ISP_RES_NAME_LEN      16
 
 
+enum cam_isp_bw_control_action {
+	CAM_ISP_BW_CONTROL_EXCLUDE       = 0,
+	CAM_ISP_BW_CONTROL_INCLUDE       = 1
+};
+
+/*
+ * struct cam_isp_bw_control_args:
+ *
+ * @node_res:             Resource node info
+ * @action:               Bandwidth control action
+ */
+struct cam_isp_bw_control_args {
+	struct cam_isp_resource_node      *node_res;
+	enum cam_isp_bw_control_action     action;
+};
+
+/*
+ * struct cam_isp_apply_clk_bw_args:
+ *
+ * @hw_intf:             Isp hw intf pointer
+ * @request_id:          Request Id
+ */
+struct cam_isp_apply_clk_bw_args {
+	struct cam_hw_intf                *hw_intf;
+	uint64_t                           request_id;
+};
+
 /*
 /*
  * struct cam_isp_timestamp:
  * struct cam_isp_timestamp:
  *
  *
@@ -69,6 +96,12 @@ enum cam_isp_hw_split_id {
 	CAM_ISP_HW_SPLIT_MAX,
 	CAM_ISP_HW_SPLIT_MAX,
 };
 };
 
 
+enum cam_isp_hw_usage_type {
+	CAM_ISP_HW_USAGE_TYPE_SINGLE = 0,
+	CAM_ISP_HW_USAGE_TYPE_DUAL,
+	CAM_ISP_HW_USAGE_TYPE_MAX,
+};
+
 enum cam_isp_hw_sync_mode {
 enum cam_isp_hw_sync_mode {
 	CAM_ISP_HW_SYNC_NONE,
 	CAM_ISP_HW_SYNC_NONE,
 	CAM_ISP_HW_SYNC_MASTER,
 	CAM_ISP_HW_SYNC_MASTER,
@@ -163,6 +196,7 @@ enum cam_isp_hw_cmd_type {
 	CAM_ISP_HW_SFE_SYS_CACHE_RM_CONFIG,
 	CAM_ISP_HW_SFE_SYS_CACHE_RM_CONFIG,
 	CAM_ISP_HW_CMD_WM_BW_LIMIT_CONFIG,
 	CAM_ISP_HW_CMD_WM_BW_LIMIT_CONFIG,
 	CAM_ISP_HW_CMD_RM_ENABLE_DISABLE,
 	CAM_ISP_HW_CMD_RM_ENABLE_DISABLE,
+	CAM_ISP_HW_CMD_APPLY_CLK_BW_UPDATE,
 	CAM_ISP_HW_CMD_MAX,
 	CAM_ISP_HW_CMD_MAX,
 };
 };
 
 

+ 0 - 16
drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_sfe_hw_intf.h

@@ -41,11 +41,6 @@ enum cam_sfe_hw_irq_status {
 	CAM_SFE_IRQ_STATUS_MAX,
 	CAM_SFE_IRQ_STATUS_MAX,
 };
 };
 
 
-enum cam_sfe_bw_control_action {
-	CAM_SFE_BW_CONTROL_EXCLUDE,
-	CAM_SFE_BW_CONTROL_INCLUDE,
-};
-
 enum cam_sfe_hw_irq_regs {
 enum cam_sfe_hw_irq_regs {
 	CAM_SFE_IRQ_TOP_REG_STATUS0,
 	CAM_SFE_IRQ_TOP_REG_STATUS0,
 	CAM_SFE_IRQ_REGISTERS_MAX,
 	CAM_SFE_IRQ_REGISTERS_MAX,
@@ -96,17 +91,6 @@ struct cam_sfe_debug_cfg_params {
 	} u;
 	} u;
 };
 };
 
 
-/*
- * struct cam_sfe_bw_control_args:
- *
- * @node_res:             Resource node info
- * @action:               Bandwidth control action
- */
-struct cam_sfe_bw_control_args {
-	struct cam_isp_resource_node      *node_res;
-	enum cam_sfe_bw_control_action     action;
-};
-
 /*
 /*
  * struct cam_sfe_bw_update_args:
  * struct cam_sfe_bw_update_args:
  *
  *

+ 1 - 17
drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
 /*
- * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
  */
  */
 
 
 #ifndef _CAM_VFE_HW_INTF_H_
 #ifndef _CAM_VFE_HW_INTF_H_
@@ -269,22 +269,6 @@ struct cam_vfe_fe_update_args {
 	struct cam_fe_config               fe_config;
 	struct cam_fe_config               fe_config;
 };
 };
 
 
-enum cam_vfe_bw_control_action {
-	CAM_VFE_BW_CONTROL_EXCLUDE       = 0,
-	CAM_VFE_BW_CONTROL_INCLUDE       = 1
-};
-
-/*
- * struct cam_vfe_bw_control_args:
- *
- * @node_res:             Resource to get the time stamp
- * @action:               Bandwidth control action
- */
-struct cam_vfe_bw_control_args {
-	struct cam_isp_resource_node      *node_res;
-	enum cam_vfe_bw_control_action     action;
-};
-
 /*
 /*
  * struct cam_vfe_top_irq_evt_payload:
  * struct cam_vfe_top_irq_evt_payload:
  *
  *

+ 1 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.c

@@ -323,6 +323,7 @@ int cam_sfe_process_cmd(void *hw_priv, uint32_t cmd_type,
 	case CAM_ISP_HW_CMD_BW_CONTROL:
 	case CAM_ISP_HW_CMD_BW_CONTROL:
 	case CAM_ISP_HW_CMD_CORE_CONFIG:
 	case CAM_ISP_HW_CMD_CORE_CONFIG:
 	case CAM_ISP_HW_NOTIFY_OVERFLOW:
 	case CAM_ISP_HW_NOTIFY_OVERFLOW:
+	case CAM_ISP_HW_CMD_APPLY_CLK_BW_UPDATE:
 		rc = core_info->sfe_top->hw_ops.process_cmd(
 		rc = core_info->sfe_top->hw_ops.process_cmd(
 			core_info->sfe_top->top_priv, cmd_type,
 			core_info->sfe_top->top_priv, cmd_type,
 			cmd_args, arg_size);
 			cmd_args, arg_size);

+ 444 - 172
drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_top/cam_sfe_top.c

@@ -13,8 +13,6 @@
 #include "cam_sfe_soc.h"
 #include "cam_sfe_soc.h"
 #include "cam_sfe_core.h"
 #include "cam_sfe_core.h"
 
 
-#define CAM_SFE_DELAY_BW_REDUCTION_NUM_FRAMES 18
-
 struct cam_sfe_core_cfg {
 struct cam_sfe_core_cfg {
 	uint32_t   mode_sel;
 	uint32_t   mode_sel;
 	uint32_t   ops_mode_cfg;
 	uint32_t   ops_mode_cfg;
@@ -35,14 +33,18 @@ struct cam_sfe_top_priv {
 	struct cam_sfe_top_common_data  common_data;
 	struct cam_sfe_top_common_data  common_data;
 	struct cam_isp_resource_node    in_rsrc[CAM_SFE_TOP_IN_PORT_MAX];
 	struct cam_isp_resource_node    in_rsrc[CAM_SFE_TOP_IN_PORT_MAX];
 	uint32_t                        num_in_ports;
 	uint32_t                        num_in_ports;
-	unsigned long                   hw_clk_rate;
+	unsigned long                   applied_clk_rate;
 	unsigned long                   req_clk_rate[CAM_SFE_TOP_IN_PORT_MAX];
 	unsigned long                   req_clk_rate[CAM_SFE_TOP_IN_PORT_MAX];
-	uint32_t                        last_counter;
+	uint32_t                        last_bw_counter;
+	uint32_t                        last_clk_counter;
 	uint64_t                        total_bw_applied;
 	uint64_t                        total_bw_applied;
 	struct cam_axi_vote             req_axi_vote[CAM_SFE_TOP_IN_PORT_MAX];
 	struct cam_axi_vote             req_axi_vote[CAM_SFE_TOP_IN_PORT_MAX];
-	struct cam_axi_vote             last_vote[
-			CAM_SFE_DELAY_BW_REDUCTION_NUM_FRAMES];
-	enum cam_sfe_bw_control_action  axi_vote_control[
+	struct cam_axi_vote             last_bw_vote[CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ];
+	uint64_t                        last_total_bw_vote[CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ];
+	uint64_t                        last_clk_vote[CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ];
+	enum cam_clk_bw_state           clk_state;
+	enum cam_clk_bw_state           bw_state;
+	enum cam_isp_bw_control_action  axi_vote_control[
 		CAM_SFE_TOP_IN_PORT_MAX];
 		CAM_SFE_TOP_IN_PORT_MAX];
 	struct cam_axi_vote             applied_axi_vote;
 	struct cam_axi_vote             applied_axi_vote;
 	struct cam_sfe_core_cfg         core_cfg;
 	struct cam_sfe_core_cfg         core_cfg;
@@ -385,6 +387,97 @@ static const struct cam_sfe_top_debug_info sfe_dbg_list[][8] = {
 	},
 	},
 };
 };
 
 
+static int cam_sfe_top_apply_clock_start_stop(struct cam_sfe_top_priv *top_priv);
+
+static int cam_sfe_top_apply_bw_start_stop(struct cam_sfe_top_priv *top_priv);
+
+static const char *cam_sfe_top_clk_bw_state_to_string(uint32_t state)
+{
+	switch (state) {
+	case CAM_CLK_BW_STATE_UNCHANGED:
+		return "UNCHANGED";
+	case CAM_CLK_BW_STATE_INCREASE:
+		return "INCREASE";
+	case CAM_CLK_BW_STATE_DECREASE:
+		return "DECREASE";
+	default:
+		return "Invalid State";
+	}
+}
+
+static int cam_sfe_top_set_axi_bw_vote(
+	struct cam_sfe_top_priv *top_priv,
+	struct cam_axi_vote *final_bw_vote, uint64_t total_bw_new_vote, bool start_stop,
+	uint64_t request_id)
+{
+	int rc = 0;
+	struct cam_hw_soc_info        *soc_info = NULL;
+	struct cam_sfe_soc_private    *soc_private = NULL;
+
+	soc_info = top_priv->common_data.soc_info;
+	soc_private = (struct cam_sfe_soc_private *)soc_info->soc_private;
+
+	CAM_DBG(CAM_PERF, "SFE:%d Sending final BW to cpas bw_state:%s bw_vote:%llu req_id:%d",
+		top_priv->common_data.hw_intf->hw_idx,
+		cam_sfe_top_clk_bw_state_to_string(top_priv->bw_state),
+		total_bw_new_vote, (start_stop ? -1 : request_id));
+	rc = cam_cpas_update_axi_vote(soc_private->cpas_handle,
+		final_bw_vote);
+	if (!rc) {
+		memcpy(&top_priv->applied_axi_vote,
+			final_bw_vote,
+			sizeof(struct cam_axi_vote));
+		top_priv->total_bw_applied = total_bw_new_vote;
+	} else {
+		CAM_ERR(CAM_PERF, "BW request failed, rc=%d", rc);
+	}
+
+	return rc;
+
+}
+
+static int cam_sfe_top_set_hw_clk_rate(
+	struct cam_sfe_top_priv *top_priv, uint64_t final_clk_rate, bool start_stop,
+	uint64_t request_id)
+{
+	struct cam_hw_soc_info        *soc_info = NULL;
+	struct cam_sfe_soc_private    *soc_private = NULL;
+	struct cam_ahb_vote            ahb_vote;
+	int rc = 0, clk_lvl = -1;
+
+	soc_info = top_priv->common_data.soc_info;
+	soc_private = (struct cam_sfe_soc_private *)soc_info->soc_private;
+
+	CAM_DBG(CAM_PERF, "Applying SFE:%d Clock name=%s idx=%d clk=%llu req_id=%d",
+		top_priv->common_data.hw_intf->hw_idx, soc_info->clk_name[soc_info->src_clk_idx],
+		soc_info->src_clk_idx, final_clk_rate, (start_stop ? -1 : request_id));
+
+	rc = cam_soc_util_set_src_clk_rate(soc_info, final_clk_rate);
+	if (!rc) {
+		top_priv->applied_clk_rate = final_clk_rate;
+		rc = cam_soc_util_get_clk_level(soc_info, final_clk_rate,
+			soc_info->src_clk_idx, &clk_lvl);
+		if (rc) {
+			CAM_WARN(CAM_SFE,
+				"Failed to get clk level for %s with clk_rate %llu src_idx %d rc %d",
+				soc_info->dev_name, final_clk_rate,
+				soc_info->src_clk_idx, rc);
+			rc = 0;
+			goto end;
+		}
+
+		ahb_vote.type = CAM_VOTE_ABSOLUTE;
+		ahb_vote.vote.level = clk_lvl;
+		cam_cpas_update_ahb_vote(soc_private->cpas_handle, &ahb_vote);
+	} else {
+		CAM_ERR(CAM_PERF, "SFE:%d Set Clock rate failed, rc=%d",
+			top_priv->common_data.hw_intf->hw_idx, rc);
+	}
+
+end:
+	return rc;
+}
+
 static void cam_sfe_top_check_module_status(
 static void cam_sfe_top_check_module_status(
 	uint32_t num_reg, uint32_t *reg_val,
 	uint32_t num_reg, uint32_t *reg_val,
 	const struct cam_sfe_top_debug_info status_list[][8])
 	const struct cam_sfe_top_debug_info status_list[][8])
@@ -459,33 +552,14 @@ static struct cam_axi_vote *cam_sfe_top_delay_bw_reduction(
 	struct cam_sfe_top_priv *top_priv,
 	struct cam_sfe_top_priv *top_priv,
 	uint64_t *to_be_applied_bw)
 	uint64_t *to_be_applied_bw)
 {
 {
-	uint32_t i, j;
+	uint32_t i;
 	int vote_idx = -1;
 	int vote_idx = -1;
 	uint64_t max_bw = 0;
 	uint64_t max_bw = 0;
-	uint64_t total_bw;
-	struct cam_axi_vote *curr_l_vote;
-
-	for (i = 0; i < CAM_SFE_DELAY_BW_REDUCTION_NUM_FRAMES; i++) {
-		total_bw = 0;
-		curr_l_vote = &top_priv->last_vote[i];
-		for (j = 0; j < curr_l_vote->num_paths; j++) {
-			if (total_bw >
-				(U64_MAX -
-				curr_l_vote->axi_path[j].camnoc_bw)) {
-				CAM_ERR(CAM_PERF,
-					"sfe[%d] : Integer overflow at hist idx: %d, path: %d, total_bw = %llu, camnoc_bw = %llu",
-					top_priv->common_data.hw_intf->hw_idx,
-					i, j, total_bw,
-					curr_l_vote->axi_path[j].camnoc_bw);
-				return NULL;
-			}
-
-			total_bw += curr_l_vote->axi_path[j].camnoc_bw;
-		}
 
 
-		if (total_bw > max_bw) {
+	for (i = 0; i < CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ; i++) {
+		if (top_priv->last_total_bw_vote[i] > max_bw) {
 			vote_idx = i;
 			vote_idx = i;
-			max_bw = total_bw;
+			max_bw = top_priv->last_total_bw_vote[i];
 		}
 		}
 	}
 	}
 
 
@@ -494,24 +568,24 @@ static struct cam_axi_vote *cam_sfe_top_delay_bw_reduction(
 
 
 	*to_be_applied_bw = max_bw;
 	*to_be_applied_bw = max_bw;
 
 
-	return &top_priv->last_vote[vote_idx];
+	return &top_priv->last_bw_vote[vote_idx];
 }
 }
 
 
-int cam_sfe_top_set_axi_bw_vote(struct cam_sfe_soc_private *soc_private,
-	struct cam_sfe_top_priv *top_priv, bool start_stop)
+int cam_sfe_top_calc_axi_bw_vote(struct cam_sfe_top_priv *top_priv,
+	bool start_stop, struct cam_axi_vote **to_be_applied_axi_vote,
+	uint64_t *total_bw_new_vote, uint64_t request_id)
 {
 {
-	struct cam_axi_vote agg_vote = {0};
-	struct cam_axi_vote *to_be_applied_axi_vote = NULL;
+	static struct cam_axi_vote agg_vote = {0};
 	int rc = 0;
 	int rc = 0;
 	uint32_t i;
 	uint32_t i;
 	uint32_t num_paths = 0;
 	uint32_t num_paths = 0;
-	uint64_t total_bw_new_vote = 0;
 	bool bw_unchanged = true;
 	bool bw_unchanged = true;
-	bool apply_bw_update = false;
+	struct cam_axi_vote *final_bw_vote = NULL;
 
 
+	memset(&agg_vote, 0, sizeof(struct cam_axi_vote));
 	for (i = 0; i < top_priv->num_in_ports; i++) {
 	for (i = 0; i < top_priv->num_in_ports; i++) {
 		if (top_priv->axi_vote_control[i] ==
 		if (top_priv->axi_vote_control[i] ==
-			CAM_SFE_BW_CONTROL_INCLUDE) {
+			CAM_ISP_BW_CONTROL_INCLUDE) {
 			if (num_paths +
 			if (num_paths +
 				top_priv->req_axi_vote[i].num_paths >
 				top_priv->req_axi_vote[i].num_paths >
 				CAM_CPAS_MAX_PATHS_PER_CLIENT) {
 				CAM_CPAS_MAX_PATHS_PER_CLIENT) {
@@ -520,7 +594,8 @@ int cam_sfe_top_set_axi_bw_vote(struct cam_sfe_soc_private *soc_private,
 					num_paths +
 					num_paths +
 					top_priv->req_axi_vote[i].num_paths,
 					top_priv->req_axi_vote[i].num_paths,
 					CAM_CPAS_MAX_PATHS_PER_CLIENT);
 					CAM_CPAS_MAX_PATHS_PER_CLIENT);
-				return -EINVAL;
+				rc = -EINVAL;
+				goto end;
 			}
 			}
 
 
 			memcpy(&agg_vote.axi_path[num_paths],
 			memcpy(&agg_vote.axi_path[num_paths],
@@ -538,7 +613,7 @@ int cam_sfe_top_set_axi_bw_vote(struct cam_sfe_soc_private *soc_private,
 		CAM_DBG(CAM_PERF,
 		CAM_DBG(CAM_PERF,
 			"sfe[%d] : New BW Vote : counter[%d] [%s][%s] [%llu %llu %llu]",
 			"sfe[%d] : New BW Vote : counter[%d] [%s][%s] [%llu %llu %llu]",
 			top_priv->common_data.hw_intf->hw_idx,
 			top_priv->common_data.hw_intf->hw_idx,
-			top_priv->last_counter,
+			top_priv->last_bw_counter,
 			cam_cpas_axi_util_path_type_to_string(
 			cam_cpas_axi_util_path_type_to_string(
 			agg_vote.axi_path[i].path_data_type),
 			agg_vote.axi_path[i].path_data_type),
 			cam_cpas_axi_util_trans_type_to_string(
 			cam_cpas_axi_util_trans_type_to_string(
@@ -547,89 +622,93 @@ int cam_sfe_top_set_axi_bw_vote(struct cam_sfe_soc_private *soc_private,
 			agg_vote.axi_path[i].mnoc_ab_bw,
 			agg_vote.axi_path[i].mnoc_ab_bw,
 			agg_vote.axi_path[i].mnoc_ib_bw);
 			agg_vote.axi_path[i].mnoc_ib_bw);
 
 
-		total_bw_new_vote += agg_vote.axi_path[i].camnoc_bw;
+		*total_bw_new_vote += agg_vote.axi_path[i].camnoc_bw;
 	}
 	}
 
 
-	memcpy(&top_priv->last_vote[top_priv->last_counter], &agg_vote,
+	memcpy(&top_priv->last_bw_vote[top_priv->last_bw_counter], &agg_vote,
 		sizeof(struct cam_axi_vote));
 		sizeof(struct cam_axi_vote));
-	top_priv->last_counter = (top_priv->last_counter + 1) %
-		CAM_SFE_DELAY_BW_REDUCTION_NUM_FRAMES;
+	top_priv->last_total_bw_vote[top_priv->last_bw_counter] = *total_bw_new_vote;
+	top_priv->last_bw_counter = (top_priv->last_bw_counter + 1) %
+		CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ;
 
 
-	if ((agg_vote.num_paths != top_priv->applied_axi_vote.num_paths) ||
-		(total_bw_new_vote != top_priv->total_bw_applied))
+	if (*total_bw_new_vote != top_priv->total_bw_applied)
 		bw_unchanged = false;
 		bw_unchanged = false;
 
 
 	CAM_DBG(CAM_PERF,
 	CAM_DBG(CAM_PERF,
-		"applied_total=%lld, new_total=%lld unchanged=%d, start_stop=%d",
+		"applied_total=%lld, new_total=%lld unchanged=%d, start_stop=%d req_id=%d",
 		top_priv->total_bw_applied,
 		top_priv->total_bw_applied,
-		total_bw_new_vote, bw_unchanged, start_stop);
+		*total_bw_new_vote, bw_unchanged, start_stop, (start_stop ? -1 : request_id));
 
 
 	if (bw_unchanged) {
 	if (bw_unchanged) {
 		CAM_DBG(CAM_PERF, "BW config unchanged");
 		CAM_DBG(CAM_PERF, "BW config unchanged");
-		return 0;
+		*to_be_applied_axi_vote = NULL;
+		top_priv->bw_state = CAM_CLK_BW_STATE_UNCHANGED;
+		goto end;
 	}
 	}
 
 
 	if (start_stop) {
 	if (start_stop) {
 		/* need to vote current request immediately */
 		/* need to vote current request immediately */
-		to_be_applied_axi_vote = &agg_vote;
+		final_bw_vote = &agg_vote;
 		/* Reset everything, we can start afresh */
 		/* Reset everything, we can start afresh */
-		memset(top_priv->last_vote, 0x0, sizeof(struct cam_axi_vote) *
-			CAM_SFE_DELAY_BW_REDUCTION_NUM_FRAMES);
-		top_priv->last_counter = 0;
-		top_priv->last_vote[top_priv->last_counter] = agg_vote;
-		top_priv->last_counter = (top_priv->last_counter + 1) %
-			CAM_SFE_DELAY_BW_REDUCTION_NUM_FRAMES;
+		memset(top_priv->last_bw_vote, 0, sizeof(struct cam_axi_vote) *
+			CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ);
+		memset(top_priv->last_total_bw_vote, 0, sizeof(uint64_t) *
+			CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ);
+		top_priv->last_bw_counter = 0;
+		top_priv->last_bw_vote[top_priv->last_bw_counter] = agg_vote;
+		top_priv->last_total_bw_vote[top_priv->last_bw_counter] = *total_bw_new_vote;
+		top_priv->last_bw_counter = (top_priv->last_bw_counter + 1) %
+			CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ;
 	} else {
 	} else {
 		/*
 		/*
 		 * Find max bw request in last few frames. This will the bw
 		 * Find max bw request in last few frames. This will the bw
 		 * that we want to vote to CPAS now.
 		 * that we want to vote to CPAS now.
 		 */
 		 */
-		to_be_applied_axi_vote =
-			cam_sfe_top_delay_bw_reduction(top_priv,
-			&total_bw_new_vote);
-		if (!to_be_applied_axi_vote) {
-			CAM_ERR(CAM_PERF, "to_be_applied_axi_vote is NULL");
-			return -EINVAL;
+		final_bw_vote = cam_sfe_top_delay_bw_reduction(top_priv, total_bw_new_vote);
+		if (!final_bw_vote) {
+			CAM_ERR(CAM_PERF, "to_be_applied_axi_vote is NULL, req_id:%llu",
+				request_id);
+			top_priv->bw_state = CAM_CLK_BW_STATE_UNCHANGED;
+			return 0;
 		}
 		}
 	}
 	}
 
 
-	for (i = 0; i < to_be_applied_axi_vote->num_paths; i++) {
+	for (i = 0; i < final_bw_vote->num_paths; i++) {
 		CAM_DBG(CAM_PERF,
 		CAM_DBG(CAM_PERF,
 			"sfe[%d] : Apply BW Vote : [%s][%s] [%llu %llu %llu]",
 			"sfe[%d] : Apply BW Vote : [%s][%s] [%llu %llu %llu]",
 			top_priv->common_data.hw_intf->hw_idx,
 			top_priv->common_data.hw_intf->hw_idx,
 			cam_cpas_axi_util_path_type_to_string(
 			cam_cpas_axi_util_path_type_to_string(
-			to_be_applied_axi_vote->axi_path[i].path_data_type),
+			final_bw_vote->axi_path[i].path_data_type),
 			cam_cpas_axi_util_trans_type_to_string(
 			cam_cpas_axi_util_trans_type_to_string(
-			to_be_applied_axi_vote->axi_path[i].transac_type),
-			to_be_applied_axi_vote->axi_path[i].camnoc_bw,
-			to_be_applied_axi_vote->axi_path[i].mnoc_ab_bw,
-			to_be_applied_axi_vote->axi_path[i].mnoc_ib_bw);
+			final_bw_vote->axi_path[i].transac_type),
+			final_bw_vote->axi_path[i].camnoc_bw,
+			final_bw_vote->axi_path[i].mnoc_ab_bw,
+			final_bw_vote->axi_path[i].mnoc_ib_bw);
+	}
+
+	if (*total_bw_new_vote == top_priv->total_bw_applied) {
+		CAM_DBG(CAM_PERF, "SFE:%d Final BW Unchanged after delay",
+			top_priv->common_data.hw_intf->hw_idx);
+		top_priv->bw_state = CAM_CLK_BW_STATE_UNCHANGED;
+		*to_be_applied_axi_vote = NULL;
+		goto end;
+	} else if (*total_bw_new_vote > top_priv->total_bw_applied) {
+		top_priv->bw_state = CAM_CLK_BW_STATE_INCREASE;
+	} else {
+		top_priv->bw_state = CAM_CLK_BW_STATE_DECREASE;
 	}
 	}
 
 
-	if ((to_be_applied_axi_vote->num_paths !=
-		top_priv->applied_axi_vote.num_paths) ||
-		(total_bw_new_vote != top_priv->total_bw_applied))
-		apply_bw_update = true;
 
 
 	CAM_DBG(CAM_PERF,
 	CAM_DBG(CAM_PERF,
-		"sfe[%d] : Delayed update: applied_total=%lld, new_total=%lld apply_bw_update=%d, start_stop=%d",
-		top_priv->common_data.hw_intf->hw_idx,
-		top_priv->total_bw_applied, total_bw_new_vote, apply_bw_update,
-		start_stop);
-
-	if (apply_bw_update) {
-		rc = cam_cpas_update_axi_vote(soc_private->cpas_handle,
-			to_be_applied_axi_vote);
-		if (!rc) {
-			memcpy(&top_priv->applied_axi_vote,
-				to_be_applied_axi_vote,
-				sizeof(struct cam_axi_vote));
-			top_priv->total_bw_applied = total_bw_new_vote;
-		} else {
-			CAM_ERR(CAM_PERF, "BW request failed, rc=%d", rc);
-		}
-	}
+		"sfe[%d] : Delayed update: applied_total=%lld new_total=%lld, start_stop=%d bw_state=%s req_id=%d",
+		top_priv->common_data.hw_intf->hw_idx, top_priv->total_bw_applied,
+		total_bw_new_vote, start_stop,
+		cam_sfe_top_clk_bw_state_to_string(top_priv->bw_state),
+		(start_stop ? -1 : request_id));
 
 
+	*to_be_applied_axi_vote = final_bw_vote;
+
+end:
 	return rc;
 	return rc;
 }
 }
 
 
@@ -665,21 +744,11 @@ int cam_sfe_top_bw_update(struct cam_sfe_soc_private *soc_private,
 				&bw_update->sfe_vote,
 				&bw_update->sfe_vote,
 				sizeof(struct cam_axi_vote));
 				sizeof(struct cam_axi_vote));
 			top_priv->axi_vote_control[i] =
 			top_priv->axi_vote_control[i] =
-				CAM_SFE_BW_CONTROL_INCLUDE;
+				CAM_ISP_BW_CONTROL_INCLUDE;
 			break;
 			break;
 		}
 		}
 	}
 	}
 
 
-	if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) {
-		CAM_ERR_RATE_LIMIT(CAM_SFE,
-			"SFE:%d Not ready to set BW yet :%d",
-			res->hw_intf->hw_idx,
-			hw_info->hw_state);
-	} else {
-		rc = cam_sfe_top_set_axi_bw_vote(soc_private, top_priv,
-			false);
-	}
-
 	return rc;
 	return rc;
 }
 }
 
 
@@ -687,13 +756,13 @@ int cam_sfe_top_bw_control(struct cam_sfe_soc_private *soc_private,
 	struct cam_sfe_top_priv *top_priv, void *cmd_args,
 	struct cam_sfe_top_priv *top_priv, void *cmd_args,
 	uint32_t arg_size)
 	uint32_t arg_size)
 {
 {
-	struct cam_sfe_bw_control_args       *bw_ctrl = NULL;
+	struct cam_isp_bw_control_args       *bw_ctrl = NULL;
 	struct cam_isp_resource_node         *res = NULL;
 	struct cam_isp_resource_node         *res = NULL;
 	struct cam_hw_info                   *hw_info = NULL;
 	struct cam_hw_info                   *hw_info = NULL;
 	int                                   rc = 0;
 	int                                   rc = 0;
 	int                                   i;
 	int                                   i;
 
 
-	bw_ctrl = (struct cam_sfe_bw_control_args *)cmd_args;
+	bw_ctrl = (struct cam_isp_bw_control_args *)cmd_args;
 	res = bw_ctrl->node_res;
 	res = bw_ctrl->node_res;
 
 
 	if (!res || !res->hw_intf->hw_priv)
 	if (!res || !res->hw_intf->hw_priv)
@@ -722,7 +791,7 @@ int cam_sfe_top_bw_control(struct cam_sfe_soc_private *soc_private,
 			res->hw_intf->hw_idx,
 			res->hw_intf->hw_idx,
 			hw_info->hw_state);
 			hw_info->hw_state);
 	} else {
 	} else {
-		rc = cam_sfe_top_set_axi_bw_vote(soc_private, top_priv, true);
+		rc = cam_sfe_top_apply_bw_start_stop(top_priv);
 	}
 	}
 
 
 	return rc;
 	return rc;
@@ -751,66 +820,71 @@ static int cam_sfe_top_core_cfg(
 	return 0;
 	return 0;
 }
 }
 
 
-static int cam_sfe_top_set_hw_clk_rate(
-	struct cam_sfe_top_priv *top_priv)
+static inline void cam_sfe_top_delay_clk_reduction(
+	struct cam_sfe_top_priv *top_priv,
+	uint64_t *max_clk)
 {
 {
-	struct cam_hw_soc_info        *soc_info = NULL;
-	struct cam_sfe_soc_private    *soc_private = NULL;
-	struct cam_ahb_vote            ahb_vote;
-	int                            rc, clk_lvl = -1, i;
-	unsigned long                  max_clk_rate = 0;
-
-	soc_info = top_priv->common_data.soc_info;
-	for (i = 0; i < top_priv->num_in_ports; i++) {
-		if (top_priv->req_clk_rate[i] > max_clk_rate)
-			max_clk_rate = top_priv->req_clk_rate[i];
-	}
+	int i;
 
 
-	if (max_clk_rate == top_priv->hw_clk_rate) {
-		CAM_DBG(CAM_SFE,
-			"Requested rate: %u same as current rate: %u",
-			max_clk_rate, top_priv->hw_clk_rate);
-		return 0;
+	for (i = 0; i < CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ; i++) {
+		if (top_priv->last_clk_vote[i] > (*max_clk))
+			*max_clk = top_priv->last_clk_vote[i];
 	}
 	}
+}
 
 
-	soc_private = (struct cam_sfe_soc_private *)
-		soc_info->soc_private;
-	CAM_DBG(CAM_PERF, "SFE [%u]: clk: %s idx: %d rate: %llu",
-		soc_info->index,
-		soc_info->clk_name[soc_info->src_clk_idx],
-		soc_info->src_clk_idx, max_clk_rate);
+int cam_sfe_top_calc_hw_clk_rate(
+	struct cam_sfe_top_priv *top_priv, bool start_stop,
+	uint64_t                       *final_clk_rate, uint64_t request_id)
+{
+	int                            i, rc = 0;
+	uint64_t                       max_req_clk_rate = 0;
 
 
-	rc = cam_soc_util_set_src_clk_rate(soc_info,
-		max_clk_rate);
+	for (i = 0; i < top_priv->num_in_ports; i++) {
+		if (top_priv->req_clk_rate[i] > max_req_clk_rate)
+			max_req_clk_rate = top_priv->req_clk_rate[i];
+	}
 
 
-	if (!rc) {
-		top_priv->hw_clk_rate = max_clk_rate;
-		rc = cam_soc_util_get_clk_level(soc_info,
-			max_clk_rate,
-			soc_info->src_clk_idx, &clk_lvl);
-		if (rc) {
-			CAM_WARN(CAM_SFE,
-				"Failed to get clk level for %s with clk_rate %llu src_idx %d rc: %d",
-				soc_info->dev_name, max_clk_rate,
-				soc_info->src_clk_idx, rc);
-			rc = 0;
-			goto end;
-		}
-		ahb_vote.type = CAM_VOTE_ABSOLUTE;
-		ahb_vote.vote.level = clk_lvl;
-		cam_cpas_update_ahb_vote(soc_private->cpas_handle, &ahb_vote);
+	if (start_stop) {
+		/* need to vote current clk immediately */
+		*final_clk_rate = max_req_clk_rate;
+		/* Reset everything, we can start afresh */
+		memset(top_priv->last_clk_vote, 0, sizeof(uint64_t) *
+			CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ);
+		top_priv->last_clk_counter = 0;
+		top_priv->last_clk_vote[top_priv->last_clk_counter] =
+			max_req_clk_rate;
+		top_priv->last_clk_counter = (top_priv->last_clk_counter + 1) %
+			CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ;
 	} else {
 	} else {
-		CAM_ERR(CAM_PERF,
-			"Set clk rate failed for SFE [%u] clk: %s rate: %llu rc: %d",
-			soc_info->index,
-			soc_info->clk_name[soc_info->src_clk_idx],
-			max_clk_rate, rc);
+		top_priv->last_clk_vote[top_priv->last_clk_counter] =
+			max_req_clk_rate;
+		top_priv->last_clk_counter = (top_priv->last_clk_counter + 1) %
+			CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ;
+
+		/* Find max clk request in last few requests */
+		cam_sfe_top_delay_clk_reduction(top_priv, final_clk_rate);
+		if (!(*final_clk_rate)) {
+			CAM_ERR(CAM_PERF, "Final clock rate is zero");
+			return -EINVAL;
+		}
 	}
 	}
 
 
-end:
+	if (*final_clk_rate == top_priv->applied_clk_rate)
+		top_priv->clk_state = CAM_CLK_BW_STATE_UNCHANGED;
+	else if (*final_clk_rate > top_priv->applied_clk_rate)
+		top_priv->clk_state = CAM_CLK_BW_STATE_INCREASE;
+	else
+		top_priv->clk_state = CAM_CLK_BW_STATE_DECREASE;
+
+	CAM_DBG(CAM_PERF, "SFE:%d Clock state:%s hw_clk_rate:%llu req_id:%d",
+		top_priv->common_data.hw_intf->hw_idx,
+		cam_sfe_top_clk_bw_state_to_string(top_priv->clk_state),
+		top_priv->applied_clk_rate, (start_stop ? -1 : request_id));
+
 	return rc;
 	return rc;
 }
 }
 
 
+
 static int cam_sfe_top_get_base(
 static int cam_sfe_top_get_base(
 	struct cam_sfe_top_priv *top_priv,
 	struct cam_sfe_top_priv *top_priv,
 	void *cmd_args, uint32_t arg_size)
 	void *cmd_args, uint32_t arg_size)
@@ -873,7 +947,7 @@ static int cam_sfe_top_clock_update(
 	struct cam_sfe_clock_update_args     *clk_update = NULL;
 	struct cam_sfe_clock_update_args     *clk_update = NULL;
 	struct cam_isp_resource_node         *res = NULL;
 	struct cam_isp_resource_node         *res = NULL;
 	struct cam_hw_info                   *hw_info = NULL;
 	struct cam_hw_info                   *hw_info = NULL;
-	int                                   rc = 0, i;
+	int i;
 
 
 	if (arg_size != sizeof(struct cam_sfe_clock_update_args)) {
 	if (arg_size != sizeof(struct cam_sfe_clock_update_args)) {
 		CAM_ERR(CAM_SFE, "Invalid cmd size");
 		CAM_ERR(CAM_SFE, "Invalid cmd size");
@@ -913,15 +987,7 @@ static int cam_sfe_top_clock_update(
 		}
 		}
 	}
 	}
 
 
-	if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) {
-		CAM_DBG(CAM_PERF,
-			"SFE: %d not ready to set clocks yet :%d",
-			res->hw_intf->hw_idx,
-			hw_info->hw_state);
-	} else
-		rc = cam_sfe_top_set_hw_clk_rate(top_priv);
-
-	return rc;
+	return 0;
 }
 }
 
 
 static int cam_sfe_set_top_debug(
 static int cam_sfe_set_top_debug(
@@ -971,6 +1037,208 @@ static int cam_sfe_top_handle_overflow(
 	return 0;
 	return 0;
 }
 }
 
 
+static int cam_sfe_top_apply_clk_bw_update(struct cam_sfe_top_priv *top_priv,
+	void *cmd_args, uint32_t arg_size)
+{
+	struct cam_hw_info                   *hw_info = NULL;
+	struct cam_hw_intf                   *hw_intf = NULL;
+	struct cam_axi_vote *to_be_applied_axi_vote = NULL;
+	struct cam_isp_apply_clk_bw_args *clk_bw_args = NULL;
+	uint64_t                              final_clk_rate = 0;
+	uint64_t                              total_bw_new_vote = 0;
+	uint64_t                              request_id;
+	int rc = 0;
+
+	if (arg_size != sizeof(struct cam_isp_apply_clk_bw_args)) {
+		CAM_ERR(CAM_SFE, "Invalid arg size: %u", arg_size);
+		return -EINVAL;
+	}
+
+	clk_bw_args = (struct cam_isp_apply_clk_bw_args *)cmd_args;
+	request_id = clk_bw_args->request_id;
+	hw_intf = clk_bw_args->hw_intf;
+	if (!hw_intf) {
+		CAM_ERR(CAM_SFE, "Invalid hw_intf");
+		return -EINVAL;
+	}
+
+	hw_info = hw_intf->hw_priv;
+	if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) {
+		CAM_DBG(CAM_PERF,
+			"SFE:%d Not ready to set clocks yet :%d",
+			hw_intf->hw_idx, hw_info->hw_state);
+		goto end;
+	}
+
+	rc = cam_sfe_top_calc_hw_clk_rate(top_priv, false, &final_clk_rate, request_id);
+	if (rc) {
+		CAM_ERR(CAM_SFE,
+			"SFE:%d Failed in calculating clock rate rc=%d",
+			hw_intf->hw_idx, rc);
+		goto end;
+	}
+
+	rc = cam_sfe_top_calc_axi_bw_vote(top_priv, false,
+		&to_be_applied_axi_vote, &total_bw_new_vote, request_id);
+	if (rc) {
+		CAM_ERR(CAM_SFE, "SFE:%d Failed in calculating bw vote rc=%d",
+			hw_intf->hw_idx, rc);
+		goto end;
+	}
+
+	if ((!to_be_applied_axi_vote) && (top_priv->bw_state != CAM_CLK_BW_STATE_UNCHANGED)) {
+		CAM_ERR(CAM_PERF, "SFE:%d Invalid BW vote for state:%s", hw_intf->hw_idx,
+			cam_sfe_top_clk_bw_state_to_string(top_priv->bw_state));
+	}
+
+	CAM_DBG(CAM_PERF, "SFE:%d APPLY CLK/BW req_id:%d clk_state:%s bw_state:%s ",
+		hw_intf->hw_idx, request_id,
+		cam_sfe_top_clk_bw_state_to_string(top_priv->clk_state),
+		cam_sfe_top_clk_bw_state_to_string(top_priv->bw_state));
+
+	/* Determine BW and clock voting sequence according to state */
+	if ((top_priv->clk_state == CAM_CLK_BW_STATE_UNCHANGED) &&
+		(top_priv->bw_state == CAM_CLK_BW_STATE_UNCHANGED)) {
+		goto end;
+	} else if (top_priv->clk_state == CAM_CLK_BW_STATE_UNCHANGED) {
+		rc = cam_sfe_top_set_axi_bw_vote(top_priv, to_be_applied_axi_vote,
+			total_bw_new_vote, false, request_id);
+		if (rc) {
+			CAM_ERR(CAM_SFE,
+				"SFE:%d Failed in voting final bw:%llu clk_state:%s bw_state:%s",
+				hw_intf->hw_idx, total_bw_new_vote,
+				cam_sfe_top_clk_bw_state_to_string(top_priv->clk_state),
+				cam_sfe_top_clk_bw_state_to_string(top_priv->bw_state));
+			goto end;
+		}
+	} else if (top_priv->bw_state == CAM_CLK_BW_STATE_UNCHANGED) {
+		rc = cam_sfe_top_set_hw_clk_rate(top_priv, final_clk_rate, false, request_id);
+		if (rc) {
+			CAM_ERR(CAM_SFE,
+				"SFE:%d Failed in voting final clk:%llu clk_state:%s bw_state:%s",
+				hw_intf->hw_idx, final_clk_rate,
+				cam_sfe_top_clk_bw_state_to_string(top_priv->clk_state),
+				cam_sfe_top_clk_bw_state_to_string(top_priv->bw_state));
+			goto end;
+		}
+	} else if (top_priv->clk_state == CAM_CLK_BW_STATE_INCREASE) {
+		/* Set BW first, followed by Clock */
+		rc = cam_sfe_top_set_axi_bw_vote(top_priv, to_be_applied_axi_vote,
+			total_bw_new_vote, false, request_id);
+		if (rc) {
+			CAM_ERR(CAM_SFE,
+				"SFE:%d Failed in voting final bw:%llu clk_state:%s bw_state:%s",
+				hw_intf->hw_idx, total_bw_new_vote,
+				cam_sfe_top_clk_bw_state_to_string(top_priv->clk_state),
+				cam_sfe_top_clk_bw_state_to_string(top_priv->bw_state));
+			goto end;
+		}
+
+		rc = cam_sfe_top_set_hw_clk_rate(top_priv, final_clk_rate, false, request_id);
+		if (rc) {
+			CAM_ERR(CAM_SFE,
+				"SFE:%d Failed in voting final clk:%llu clk_state:%s bw_state:%s",
+				hw_intf->hw_idx, final_clk_rate,
+				cam_sfe_top_clk_bw_state_to_string(top_priv->clk_state),
+				cam_sfe_top_clk_bw_state_to_string(top_priv->bw_state));
+			goto end;
+		}
+	} else if (top_priv->clk_state == CAM_CLK_BW_STATE_DECREASE) {
+		/* Set Clock first, followed by BW */
+		rc = cam_sfe_top_set_hw_clk_rate(top_priv, final_clk_rate, false, request_id);
+		if (rc) {
+			CAM_ERR(CAM_SFE,
+				"SFE:%d Failed in voting final clk:%llu clk_state:%s bw_state:%s",
+				hw_intf->hw_idx, final_clk_rate,
+				cam_sfe_top_clk_bw_state_to_string(top_priv->clk_state),
+				cam_sfe_top_clk_bw_state_to_string(top_priv->bw_state));
+			goto end;
+		}
+
+		rc = cam_sfe_top_set_axi_bw_vote(top_priv, to_be_applied_axi_vote,
+			total_bw_new_vote, false, request_id);
+		if (rc) {
+			CAM_ERR(CAM_SFE,
+				"SFE:%d Failed in voting final bw:%llu clk_state:%s bw_state:%s",
+				hw_intf->hw_idx, total_bw_new_vote,
+				cam_sfe_top_clk_bw_state_to_string(top_priv->clk_state),
+				cam_sfe_top_clk_bw_state_to_string(top_priv->bw_state));
+			goto end;
+		}
+	} else {
+		CAM_ERR(CAM_SFE, "Invalid state to apply CLK/BW clk_state:%s bw_state:%s",
+			cam_sfe_top_clk_bw_state_to_string(top_priv->clk_state),
+			cam_sfe_top_clk_bw_state_to_string(top_priv->bw_state));
+		rc = -EINVAL;
+		goto end;
+	}
+
+end:
+	top_priv->clk_state = CAM_CLK_BW_STATE_INIT;
+	top_priv->bw_state = CAM_CLK_BW_STATE_INIT;
+	return rc;
+}
+
+static int cam_sfe_top_apply_clock_start_stop(struct cam_sfe_top_priv *top_priv)
+{
+	int rc = 0;
+	uint64_t final_clk_rate = 0;
+
+	rc = cam_sfe_top_calc_hw_clk_rate(top_priv, true, &final_clk_rate, 0);
+	if (rc) {
+		CAM_ERR(CAM_SFE,
+			"SFE:%d Failed in calculating clock rate rc=%d",
+			top_priv->common_data.hw_intf->hw_idx, rc);
+		goto end;
+	}
+
+	if (top_priv->clk_state == CAM_CLK_BW_STATE_UNCHANGED)
+		goto end;
+
+	rc = cam_sfe_top_set_hw_clk_rate(top_priv, final_clk_rate, true, 0);
+	if (rc) {
+		CAM_ERR(CAM_SFE, "SFE:%d Failed in voting final clk:%llu clk_state:%s",
+			top_priv->common_data.hw_intf->hw_idx, final_clk_rate,
+			cam_sfe_top_clk_bw_state_to_string(top_priv->clk_state));
+		goto end;
+	}
+
+end:
+	top_priv->clk_state = CAM_CLK_BW_STATE_INIT;
+	return rc;
+}
+
+static int cam_sfe_top_apply_bw_start_stop(struct cam_sfe_top_priv *top_priv)
+{
+	int rc = 0;
+	uint64_t total_bw_new_vote = 0;
+	struct cam_axi_vote *to_be_applied_axi_vote = NULL;
+
+	rc = cam_sfe_top_calc_axi_bw_vote(top_priv, true,
+		&to_be_applied_axi_vote, &total_bw_new_vote, 0);
+	if (rc) {
+		CAM_ERR(CAM_SFE, "SFE:%d Failed in calculating bw vote rc=%d",
+			top_priv->common_data.hw_intf->hw_idx, rc);
+		goto end;
+	}
+
+	if (top_priv->bw_state == CAM_CLK_BW_STATE_UNCHANGED)
+		goto end;
+
+	rc = cam_sfe_top_set_axi_bw_vote(top_priv, to_be_applied_axi_vote, total_bw_new_vote,
+		true, 0);
+	if (rc) {
+		CAM_ERR(CAM_SFE, "SFE:%d Failed in voting final bw:%llu bw_state:%s",
+			top_priv->common_data.hw_intf->hw_idx, total_bw_new_vote,
+			cam_sfe_top_clk_bw_state_to_string(top_priv->bw_state));
+		goto end;
+	}
+
+end:
+	top_priv->bw_state = CAM_CLK_BW_STATE_INIT;
+	return rc;
+}
+
 int cam_sfe_top_process_cmd(void *priv, uint32_t cmd_type,
 int cam_sfe_top_process_cmd(void *priv, uint32_t cmd_type,
 	void *cmd_args, uint32_t arg_size)
 	void *cmd_args, uint32_t arg_size)
 {
 {
@@ -1007,6 +1275,7 @@ int cam_sfe_top_process_cmd(void *priv, uint32_t cmd_type,
 			cmd_args, arg_size);
 			cmd_args, arg_size);
 		break;
 		break;
 	case CAM_ISP_HW_CMD_BW_CONTROL:
 	case CAM_ISP_HW_CMD_BW_CONTROL:
+		rc = cam_sfe_top_bw_control(soc_private, top_priv, cmd_args, arg_size);
 		break;
 		break;
 	case CAM_ISP_HW_CMD_CORE_CONFIG:
 	case CAM_ISP_HW_CMD_CORE_CONFIG:
 		rc = cam_sfe_top_core_cfg(top_priv, cmd_args,
 		rc = cam_sfe_top_core_cfg(top_priv, cmd_args,
@@ -1018,6 +1287,9 @@ int cam_sfe_top_process_cmd(void *priv, uint32_t cmd_type,
 	case CAM_ISP_HW_NOTIFY_OVERFLOW:
 	case CAM_ISP_HW_NOTIFY_OVERFLOW:
 		rc = cam_sfe_top_handle_overflow(top_priv, cmd_type);
 		rc = cam_sfe_top_handle_overflow(top_priv, cmd_type);
 		break;
 		break;
+	case CAM_ISP_HW_CMD_APPLY_CLK_BW_UPDATE:
+		rc = cam_sfe_top_apply_clk_bw_update(top_priv, cmd_args, arg_size);
+		break;
 	default:
 	default:
 		CAM_ERR(CAM_SFE, "Invalid cmd type: %d", cmd_type);
 		CAM_ERR(CAM_SFE, "Invalid cmd type: %d", cmd_type);
 		rc = -EINVAL;
 		rc = -EINVAL;
@@ -1450,15 +1722,17 @@ int cam_sfe_top_start(
 	}
 	}
 
 
 	path_data = (struct cam_sfe_path_data *)sfe_res->res_priv;
 	path_data = (struct cam_sfe_path_data *)sfe_res->res_priv;
-	rc = cam_sfe_top_set_hw_clk_rate(top_priv);
-	if (rc)
+	rc = cam_sfe_top_apply_clock_start_stop(top_priv);
+	if (rc) {
+		CAM_ERR(CAM_SFE, "SFE:%d Failed in applying start clock rc:%d",
+			hw_info->soc_info.index, rc);
 		return rc;
 		return rc;
+	}
 
 
-	rc = cam_sfe_top_set_axi_bw_vote(soc_private,
-		top_priv, true);
+	rc = cam_sfe_top_apply_bw_start_stop(top_priv);
 	if (rc) {
 	if (rc) {
-		CAM_ERR(CAM_SFE,
-			"set_axi_bw_vote failed, rc=%d", rc);
+		CAM_ERR(CAM_SFE, "SFE:%d Failed in applying start bw rc:%d",
+			hw_info->soc_info.index, rc);
 		return rc;
 		return rc;
 	}
 	}
 
 
@@ -1585,7 +1859,7 @@ int cam_sfe_top_stop(
 			memset(&top_priv->req_axi_vote[i], 0,
 			memset(&top_priv->req_axi_vote[i], 0,
 				sizeof(struct cam_axi_vote));
 				sizeof(struct cam_axi_vote));
 			top_priv->axi_vote_control[i] =
 			top_priv->axi_vote_control[i] =
-				CAM_SFE_BW_CONTROL_EXCLUDE;
+				CAM_ISP_BW_CONTROL_EXCLUDE;
 			break;
 			break;
 		}
 		}
 	}
 	}
@@ -1629,7 +1903,7 @@ int cam_sfe_top_stop(
 	 * when all resources are streamed off
 	 * when all resources are streamed off
 	 */
 	 */
 	if (!start_stop_cnt) {
 	if (!start_stop_cnt) {
-		top_priv->hw_clk_rate = 0;
+		top_priv->applied_clk_rate = 0;
 		if (top_priv->error_irq_handle > 0) {
 		if (top_priv->error_irq_handle > 0) {
 			cam_irq_controller_unsubscribe_irq(
 			cam_irq_controller_unsubscribe_irq(
 				top_priv->common_data.sfe_irq_controller,
 				top_priv->common_data.sfe_irq_controller,
@@ -1681,10 +1955,8 @@ int cam_sfe_top_init(
 		goto free_top_priv;
 		goto free_top_priv;
 	}
 	}
 
 
-	top_priv->hw_clk_rate = 0;
+	top_priv->applied_clk_rate = 0;
 	top_priv->num_in_ports = sfe_top_hw_info->num_inputs;
 	top_priv->num_in_ports = sfe_top_hw_info->num_inputs;
-	memset(top_priv->last_vote, 0x0, sizeof(struct cam_axi_vote) *
-		CAM_SFE_DELAY_BW_REDUCTION_NUM_FRAMES);
 	memset(&top_priv->core_cfg, 0x0,
 	memset(&top_priv->core_cfg, 0x0,
 		sizeof(struct cam_sfe_core_cfg));
 		sizeof(struct cam_sfe_core_cfg));
 
 

+ 0 - 1
drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_top/cam_sfe_top.h

@@ -12,7 +12,6 @@
 #define CAM_SFE_RDI_VER_1_0    0x1000
 #define CAM_SFE_RDI_VER_1_0    0x1000
 #define CAM_SFE_TOP_VER_1_0    0x10000
 #define CAM_SFE_TOP_VER_1_0    0x10000
 
 
-#define CAM_SFE_DELAY_BW_REDUCTION_NUM_FRAMES  18
 #define CAM_SFE_TOP_IN_PORT_MAX                6
 #define CAM_SFE_TOP_IN_PORT_MAX                6
 #define CAM_SFE_RDI_MAX                        5
 #define CAM_SFE_RDI_MAX                        5
 
 

+ 1 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c

@@ -515,6 +515,7 @@ int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type,
 	case CAM_ISP_HW_CMD_BLANKING_UPDATE:
 	case CAM_ISP_HW_CMD_BLANKING_UPDATE:
 	case CAM_ISP_HW_CMD_FE_UPDATE_IN_RD:
 	case CAM_ISP_HW_CMD_FE_UPDATE_IN_RD:
 	case CAM_ISP_HW_CMD_GET_PATH_PORT_MAP:
 	case CAM_ISP_HW_CMD_GET_PATH_PORT_MAP:
+	case CAM_ISP_HW_CMD_APPLY_CLK_BW_UPDATE:
 		rc = core_info->vfe_top->hw_ops.process_cmd(
 		rc = core_info->vfe_top->hw_ops.process_cmd(
 			core_info->vfe_top->top_priv, cmd_type, cmd_args,
 			core_info->vfe_top->top_priv, cmd_type, cmd_args,
 			arg_size);
 			arg_size);

+ 392 - 140
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_common.c

@@ -1,51 +1,79 @@
 // SPDX-License-Identifier: GPL-2.0-only
 // SPDX-License-Identifier: GPL-2.0-only
 /*
 /*
- * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved.
  */
  */
 
 
 #include "cam_vfe_top_common.h"
 #include "cam_vfe_top_common.h"
 #include "cam_debug_util.h"
 #include "cam_debug_util.h"
 
 
-int cam_vfe_top_set_hw_clk_rate(
-	struct cam_vfe_top_priv_common *top_common)
+static const char *cam_vfe_top_clk_bw_state_to_string(uint32_t state)
 {
 {
+	switch (state) {
+	case CAM_CLK_BW_STATE_UNCHANGED:
+		return "UNCHANGED";
+	case CAM_CLK_BW_STATE_INCREASE:
+		return "INCREASE";
+	case CAM_CLK_BW_STATE_DECREASE:
+		return "DECREASE";
+	default:
+		return "Invalid State";
+	}
+}
+static int cam_vfe_top_set_axi_bw_vote(struct cam_vfe_top_priv_common *top_common,
+	struct cam_axi_vote *final_bw_vote, uint64_t total_bw_new_vote, bool start_stop,
+	uint64_t request_id)
+{
+	int rc = 0;
 	struct cam_hw_soc_info        *soc_info = NULL;
 	struct cam_hw_soc_info        *soc_info = NULL;
 	struct cam_vfe_soc_private    *soc_private = NULL;
 	struct cam_vfe_soc_private    *soc_private = NULL;
-	struct cam_ahb_vote            ahb_vote;
-	int                            i, rc = 0, clk_lvl = -1;
-	unsigned long                  max_clk_rate = 0;
 
 
 	soc_info = top_common->soc_info;
 	soc_info = top_common->soc_info;
 	soc_private = (struct cam_vfe_soc_private *)soc_info->soc_private;
 	soc_private = (struct cam_vfe_soc_private *)soc_info->soc_private;
 
 
-	for (i = 0; i < top_common->num_mux; i++) {
-		if (top_common->req_clk_rate[i] > max_clk_rate)
-			max_clk_rate = top_common->req_clk_rate[i];
+	CAM_DBG(CAM_PERF, "VFE:%d Sending final BW to cpas bw_state:%s bw_vote:%llu req_id:%d",
+		top_common->hw_idx, cam_vfe_top_clk_bw_state_to_string(top_common->bw_state),
+		total_bw_new_vote, (start_stop ? -1 : request_id));
+	rc = cam_cpas_update_axi_vote(soc_private->cpas_handle,
+		final_bw_vote);
+	if (!rc) {
+		memcpy(&top_common->applied_axi_vote,
+			final_bw_vote,
+			sizeof(struct cam_axi_vote));
+		top_common->total_bw_applied = total_bw_new_vote;
+	} else {
+		CAM_ERR(CAM_PERF, "BW request failed, rc=%d", rc);
 	}
 	}
 
 
-	if (max_clk_rate == top_common->hw_clk_rate) {
-		CAM_DBG(CAM_ISP, "VFE:%d Clock Unchanged %llu",
-			top_common->hw_idx, top_common->hw_clk_rate);
-		return 0;
-	}
+	return rc;
 
 
-	CAM_DBG(CAM_PERF, "VFE:%d Clock name=%s idx=%d clk=%llu",
-		top_common->hw_idx,
-		soc_info->clk_name[soc_info->src_clk_idx],
-		soc_info->src_clk_idx, max_clk_rate);
+}
 
 
-	rc = cam_soc_util_set_src_clk_rate(soc_info, max_clk_rate);
+static int cam_vfe_top_set_hw_clk_rate(struct cam_vfe_top_priv_common *top_common,
+	uint64_t final_clk_rate, bool start_stop, uint64_t request_id)
+{
+	struct cam_hw_soc_info        *soc_info = NULL;
+	struct cam_vfe_soc_private    *soc_private = NULL;
+	struct cam_ahb_vote            ahb_vote;
+	int rc = 0, clk_lvl = -1;
+
+	soc_info = top_common->soc_info;
+	soc_private = (struct cam_vfe_soc_private *)soc_info->soc_private;
+
+	CAM_DBG(CAM_PERF, "Applying VFE:%d Clock name=%s idx=%d clk=%llu req_id=%d",
+		top_common->hw_idx, soc_info->clk_name[soc_info->src_clk_idx],
+		soc_info->src_clk_idx, final_clk_rate, (start_stop ? -1 : request_id));
 
 
+	rc = cam_soc_util_set_src_clk_rate(soc_info, final_clk_rate);
 	if (!rc) {
 	if (!rc) {
-		soc_private->ife_clk_src = max_clk_rate;
+		soc_private->ife_clk_src = final_clk_rate;
 
 
-		top_common->hw_clk_rate = max_clk_rate;
-		rc = cam_soc_util_get_clk_level(soc_info, max_clk_rate,
+		top_common->applied_clk_rate = final_clk_rate;
+		rc = cam_soc_util_get_clk_level(soc_info, final_clk_rate,
 			soc_info->src_clk_idx, &clk_lvl);
 			soc_info->src_clk_idx, &clk_lvl);
 		if (rc) {
 		if (rc) {
 			CAM_WARN(CAM_ISP,
 			CAM_WARN(CAM_ISP,
 				"Failed to get clk level for %s with clk_rate %llu src_idx %d rc %d",
 				"Failed to get clk level for %s with clk_rate %llu src_idx %d rc %d",
-				soc_info->dev_name, max_clk_rate,
+				soc_info->dev_name, final_clk_rate,
 				soc_info->src_clk_idx, rc);
 				soc_info->src_clk_idx, rc);
 			rc = 0;
 			rc = 0;
 			goto end;
 			goto end;
@@ -63,13 +91,77 @@ end:
 	return rc;
 	return rc;
 }
 }
 
 
+static inline void cam_vfe_top_delay_clk_reduction(
+	struct cam_vfe_top_priv_common *top_common,
+	uint64_t *max_clk)
+{
+	int i;
+
+	for (i = 0; i < CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ; i++) {
+		if (top_common->last_clk_vote[i] > *max_clk)
+			*max_clk = top_common->last_clk_vote[i];
+	}
+}
+
+static int cam_vfe_top_calc_hw_clk_rate(
+	struct cam_vfe_top_priv_common *top_common, bool start_stop,
+	uint64_t                       *final_clk_rate, uint64_t request_id)
+{
+	int                            i, rc = 0;
+	uint64_t                       max_req_clk_rate = 0;
+
+	for (i = 0; i < top_common->num_mux; i++) {
+		if (top_common->req_clk_rate[i] > max_req_clk_rate)
+			max_req_clk_rate = top_common->req_clk_rate[i];
+	}
+
+	if (start_stop) {
+		/* need to vote current clk immediately */
+		*final_clk_rate = max_req_clk_rate;
+		/* Reset everything, we can start afresh */
+		memset(top_common->last_clk_vote, 0, sizeof(uint64_t) *
+			CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ);
+		top_common->last_clk_counter = 0;
+		top_common->last_clk_vote[top_common->last_clk_counter] =
+			max_req_clk_rate;
+		top_common->last_clk_counter = (top_common->last_clk_counter + 1) %
+			CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ;
+	} else {
+		top_common->last_clk_vote[top_common->last_clk_counter] =
+			max_req_clk_rate;
+		top_common->last_clk_counter =
+			(top_common->last_clk_counter + 1) %
+			CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ;
+
+		/* Find max clk request in last few requests */
+		cam_vfe_top_delay_clk_reduction(top_common, final_clk_rate);
+		if (!(*final_clk_rate)) {
+			CAM_ERR(CAM_PERF, "Final clock rate is zero");
+			return -EINVAL;
+		}
+	}
+
+	if (*final_clk_rate == top_common->applied_clk_rate)
+		top_common->clk_state = CAM_CLK_BW_STATE_UNCHANGED;
+	else if (*final_clk_rate > top_common->applied_clk_rate)
+		top_common->clk_state = CAM_CLK_BW_STATE_INCREASE;
+	else
+		top_common->clk_state = CAM_CLK_BW_STATE_DECREASE;
+
+	CAM_DBG(CAM_PERF, "VFE:%d Clock state:%s applied_clk_rate:%llu req_id:%d",
+		top_common->hw_idx, cam_vfe_top_clk_bw_state_to_string(top_common->clk_state),
+		top_common->applied_clk_rate, (start_stop ? -1 : request_id));
+
+	return rc;
+}
+
 int cam_vfe_top_clock_update(struct cam_vfe_top_priv_common *top_common,
 int cam_vfe_top_clock_update(struct cam_vfe_top_priv_common *top_common,
 	void *cmd_args, uint32_t arg_size)
 	void *cmd_args, uint32_t arg_size)
 {
 {
 	struct cam_vfe_clock_update_args     *clk_update = NULL;
 	struct cam_vfe_clock_update_args     *clk_update = NULL;
 	struct cam_isp_resource_node         *res = NULL;
 	struct cam_isp_resource_node         *res = NULL;
 	struct cam_hw_info                   *hw_info = NULL;
 	struct cam_hw_info                   *hw_info = NULL;
-	int                                   i, rc = 0;
+	int                                   i;
 
 
 	clk_update =
 	clk_update =
 		(struct cam_vfe_clock_update_args *)cmd_args;
 		(struct cam_vfe_clock_update_args *)cmd_args;
@@ -97,52 +189,21 @@ int cam_vfe_top_clock_update(struct cam_vfe_top_priv_common *top_common,
 		}
 		}
 	}
 	}
 
 
-	if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) {
-		CAM_DBG(CAM_PERF,
-			"VFE:%d Not ready to set clocks yet :%d",
-			res->hw_intf->hw_idx,
-			hw_info->hw_state);
-	} else {
-		rc = cam_vfe_top_set_hw_clk_rate(top_common);
-		if (rc)
-			CAM_ERR(CAM_PERF,
-				"VFE:%d Failed in setting clock rate rc=%d",
-				top_common->hw_idx, rc);
-	}
-
-	return rc;
+	return 0;
 }
 }
 
 
 static struct cam_axi_vote *cam_vfe_top_delay_bw_reduction(
 static struct cam_axi_vote *cam_vfe_top_delay_bw_reduction(
 	struct cam_vfe_top_priv_common *top_common,
 	struct cam_vfe_top_priv_common *top_common,
 	uint64_t *to_be_applied_bw)
 	uint64_t *to_be_applied_bw)
 {
 {
-	uint32_t i, j;
+	uint32_t i;
 	int vote_idx = -1;
 	int vote_idx = -1;
 	uint64_t max_bw = 0;
 	uint64_t max_bw = 0;
-	uint64_t total_bw;
-	struct cam_axi_vote *curr_l_vote;
-
-	for (i = 0; i < CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES; i++) {
-		total_bw = 0;
-		curr_l_vote = &top_common->last_vote[i];
-		for (j = 0; j < curr_l_vote->num_paths; j++) {
-			if (total_bw >
-				(U64_MAX -
-				curr_l_vote->axi_path[j].camnoc_bw)) {
-				CAM_ERR(CAM_PERF,
-					"ife[%d] : Integer overflow at hist idx: %d, path: %d, total_bw = %llu, camnoc_bw = %llu",
-					top_common->hw_idx, i, j, total_bw,
-					curr_l_vote->axi_path[j].camnoc_bw);
-				return NULL;
-			}
-
-			total_bw += curr_l_vote->axi_path[j].camnoc_bw;
-		}
 
 
-		if (total_bw > max_bw) {
+	for (i = 0; i < CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ; i++) {
+		if (top_common->last_total_bw_vote[i] > max_bw) {
 			vote_idx = i;
 			vote_idx = i;
-			max_bw = total_bw;
+			max_bw = top_common->last_total_bw_vote[i];
 		}
 		}
 	}
 	}
 
 
@@ -151,20 +212,20 @@ static struct cam_axi_vote *cam_vfe_top_delay_bw_reduction(
 
 
 	*to_be_applied_bw = max_bw;
 	*to_be_applied_bw = max_bw;
 
 
-	return &top_common->last_vote[vote_idx];
+	return &top_common->last_bw_vote[vote_idx];
 }
 }
 
 
-int cam_vfe_top_set_axi_bw_vote(struct cam_vfe_soc_private *soc_private,
-	struct cam_vfe_top_priv_common *top_common, bool start_stop)
+static int cam_vfe_top_calc_axi_bw_vote(
+	struct cam_vfe_top_priv_common *top_common, bool start_stop,
+	struct cam_axi_vote **to_be_applied_axi_vote, uint64_t *total_bw_new_vote,
+	uint64_t request_id)
 {
 {
-	struct cam_axi_vote agg_vote = {0};
-	struct cam_axi_vote *to_be_applied_axi_vote = NULL;
+	static struct cam_axi_vote agg_vote;
 	int rc = 0;
 	int rc = 0;
 	uint32_t i;
 	uint32_t i;
 	uint32_t num_paths = 0;
 	uint32_t num_paths = 0;
-	uint64_t total_bw_new_vote = 0;
 	bool bw_unchanged = true;
 	bool bw_unchanged = true;
-	bool apply_bw_update = false;
+	struct cam_axi_vote *final_bw_vote = NULL;
 
 
 	if (top_common->num_mux > CAM_VFE_TOP_MUX_MAX) {
 	if (top_common->num_mux > CAM_VFE_TOP_MUX_MAX) {
 		CAM_ERR(CAM_PERF,
 		CAM_ERR(CAM_PERF,
@@ -173,9 +234,10 @@ int cam_vfe_top_set_axi_bw_vote(struct cam_vfe_soc_private *soc_private,
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
+	memset(&agg_vote, 0, sizeof(struct cam_axi_vote));
 	for (i = 0; i < top_common->num_mux; i++) {
 	for (i = 0; i < top_common->num_mux; i++) {
 		if (top_common->axi_vote_control[i] ==
 		if (top_common->axi_vote_control[i] ==
-			CAM_VFE_BW_CONTROL_INCLUDE) {
+			CAM_ISP_BW_CONTROL_INCLUDE) {
 			if (num_paths +
 			if (num_paths +
 				top_common->req_axi_vote[i].num_paths >
 				top_common->req_axi_vote[i].num_paths >
 				CAM_CPAS_MAX_PATHS_PER_CLIENT) {
 				CAM_CPAS_MAX_PATHS_PER_CLIENT) {
@@ -184,7 +246,8 @@ int cam_vfe_top_set_axi_bw_vote(struct cam_vfe_soc_private *soc_private,
 					num_paths +
 					num_paths +
 					top_common->req_axi_vote[i].num_paths,
 					top_common->req_axi_vote[i].num_paths,
 					CAM_CPAS_MAX_PATHS_PER_CLIENT);
 					CAM_CPAS_MAX_PATHS_PER_CLIENT);
-				return -EINVAL;
+				rc = -EINVAL;
+				goto end;
 			}
 			}
 
 
 			memcpy(&agg_vote.axi_path[num_paths],
 			memcpy(&agg_vote.axi_path[num_paths],
@@ -202,7 +265,7 @@ int cam_vfe_top_set_axi_bw_vote(struct cam_vfe_soc_private *soc_private,
 		CAM_DBG(CAM_PERF,
 		CAM_DBG(CAM_PERF,
 			"ife[%d] : New BW Vote : counter[%d] [%s][%s] [%llu %llu %llu]",
 			"ife[%d] : New BW Vote : counter[%d] [%s][%s] [%llu %llu %llu]",
 			top_common->hw_idx,
 			top_common->hw_idx,
-			top_common->last_counter,
+			top_common->last_bw_counter,
 			cam_cpas_axi_util_path_type_to_string(
 			cam_cpas_axi_util_path_type_to_string(
 			agg_vote.axi_path[i].path_data_type),
 			agg_vote.axi_path[i].path_data_type),
 			cam_cpas_axi_util_trans_type_to_string(
 			cam_cpas_axi_util_trans_type_to_string(
@@ -211,88 +274,92 @@ int cam_vfe_top_set_axi_bw_vote(struct cam_vfe_soc_private *soc_private,
 			agg_vote.axi_path[i].mnoc_ab_bw,
 			agg_vote.axi_path[i].mnoc_ab_bw,
 			agg_vote.axi_path[i].mnoc_ib_bw);
 			agg_vote.axi_path[i].mnoc_ib_bw);
 
 
-		total_bw_new_vote += agg_vote.axi_path[i].camnoc_bw;
+		*total_bw_new_vote += agg_vote.axi_path[i].camnoc_bw;
 	}
 	}
 
 
-	memcpy(&top_common->last_vote[top_common->last_counter], &agg_vote,
+	memcpy(&top_common->last_bw_vote[top_common->last_bw_counter], &agg_vote,
 		sizeof(struct cam_axi_vote));
 		sizeof(struct cam_axi_vote));
-	top_common->last_counter = (top_common->last_counter + 1) %
-		CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES;
+	top_common->last_total_bw_vote[top_common->last_bw_counter] = *total_bw_new_vote;
+	top_common->last_bw_counter = (top_common->last_bw_counter + 1) %
+		CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ;
 
 
-	if ((agg_vote.num_paths != top_common->applied_axi_vote.num_paths) ||
-		(total_bw_new_vote != top_common->total_bw_applied))
+	if (*total_bw_new_vote != top_common->total_bw_applied)
 		bw_unchanged = false;
 		bw_unchanged = false;
 
 
 	CAM_DBG(CAM_PERF,
 	CAM_DBG(CAM_PERF,
-		"ife[%d] : applied_total=%lld, new_total=%lld unchanged=%d, start_stop=%d",
+		"ife[%d] : applied_total=%lld, new_total=%lld unchanged=%d, start_stop=%d req_id=%d",
 		top_common->hw_idx, top_common->total_bw_applied,
 		top_common->hw_idx, top_common->total_bw_applied,
-		total_bw_new_vote, bw_unchanged, start_stop);
+		*total_bw_new_vote, bw_unchanged, start_stop, (start_stop ? -1 : request_id));
 
 
 	if (bw_unchanged) {
 	if (bw_unchanged) {
 		CAM_DBG(CAM_PERF, "BW config unchanged");
 		CAM_DBG(CAM_PERF, "BW config unchanged");
-		return 0;
+		*to_be_applied_axi_vote = NULL;
+		top_common->bw_state = CAM_CLK_BW_STATE_UNCHANGED;
+		goto end;
 	}
 	}
 
 
 	if (start_stop) {
 	if (start_stop) {
 		/* need to vote current request immediately */
 		/* need to vote current request immediately */
-		to_be_applied_axi_vote = &agg_vote;
+		final_bw_vote = &agg_vote;
 		/* Reset everything, we can start afresh */
 		/* Reset everything, we can start afresh */
-		memset(top_common->last_vote, 0x0, sizeof(struct cam_axi_vote) *
-			CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES);
-		top_common->last_counter = 0;
-		top_common->last_vote[top_common->last_counter] = agg_vote;
-		top_common->last_counter = (top_common->last_counter + 1) %
-			CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES;
+		memset(top_common->last_bw_vote, 0, sizeof(struct cam_axi_vote) *
+			CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ);
+		memset(top_common->last_total_bw_vote, 0, sizeof(uint64_t) *
+			CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ);
+		top_common->last_bw_counter = 0;
+		top_common->last_bw_vote[top_common->last_bw_counter] = agg_vote;
+		top_common->last_total_bw_vote[top_common->last_bw_counter] = *total_bw_new_vote;
+		top_common->last_bw_counter = (top_common->last_bw_counter + 1) %
+			CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ;
 	} else {
 	} else {
 		/*
 		/*
 		 * Find max bw request in last few frames. This will the bw
 		 * Find max bw request in last few frames. This will the bw
 		 * that we want to vote to CPAS now.
 		 * that we want to vote to CPAS now.
 		 */
 		 */
-		to_be_applied_axi_vote =
+		final_bw_vote =
 			cam_vfe_top_delay_bw_reduction(top_common,
 			cam_vfe_top_delay_bw_reduction(top_common,
-			&total_bw_new_vote);
-		if (!to_be_applied_axi_vote) {
+				total_bw_new_vote);
+		if (!final_bw_vote) {
 			CAM_ERR(CAM_PERF, "to_be_applied_axi_vote is NULL");
 			CAM_ERR(CAM_PERF, "to_be_applied_axi_vote is NULL");
-			return -EINVAL;
+			rc = -EINVAL;
+			goto end;
 		}
 		}
 	}
 	}
 
 
-	for (i = 0; i < to_be_applied_axi_vote->num_paths; i++) {
+	for (i = 0; i < final_bw_vote->num_paths; i++) {
 		CAM_DBG(CAM_PERF,
 		CAM_DBG(CAM_PERF,
 			"ife[%d] : Apply BW Vote : [%s][%s] [%llu %llu %llu]",
 			"ife[%d] : Apply BW Vote : [%s][%s] [%llu %llu %llu]",
 			top_common->hw_idx,
 			top_common->hw_idx,
 			cam_cpas_axi_util_path_type_to_string(
 			cam_cpas_axi_util_path_type_to_string(
-			to_be_applied_axi_vote->axi_path[i].path_data_type),
+			final_bw_vote->axi_path[i].path_data_type),
 			cam_cpas_axi_util_trans_type_to_string(
 			cam_cpas_axi_util_trans_type_to_string(
-			to_be_applied_axi_vote->axi_path[i].transac_type),
-			to_be_applied_axi_vote->axi_path[i].camnoc_bw,
-			to_be_applied_axi_vote->axi_path[i].mnoc_ab_bw,
-			to_be_applied_axi_vote->axi_path[i].mnoc_ib_bw);
+			final_bw_vote->axi_path[i].transac_type),
+			final_bw_vote->axi_path[i].camnoc_bw,
+			final_bw_vote->axi_path[i].mnoc_ab_bw,
+			final_bw_vote->axi_path[i].mnoc_ib_bw);
 	}
 	}
 
 
-	if ((to_be_applied_axi_vote->num_paths !=
-		top_common->applied_axi_vote.num_paths) ||
-		(total_bw_new_vote != top_common->total_bw_applied))
-		apply_bw_update = true;
+	if (*total_bw_new_vote == top_common->total_bw_applied) {
+		CAM_DBG(CAM_PERF, "VFE:%d Final BW Unchanged after delay", top_common->hw_idx);
+		top_common->bw_state = CAM_CLK_BW_STATE_UNCHANGED;
+		*to_be_applied_axi_vote = NULL;
+		goto end;
+	} else if (*total_bw_new_vote > top_common->total_bw_applied) {
+		top_common->bw_state = CAM_CLK_BW_STATE_INCREASE;
+	} else {
+		top_common->bw_state = CAM_CLK_BW_STATE_DECREASE;
+	}
 
 
 	CAM_DBG(CAM_PERF,
 	CAM_DBG(CAM_PERF,
-		"ife[%d] : Delayed update: applied_total=%lld, new_total=%lld apply_bw_update=%d, start_stop=%d",
+		"ife[%d] : Delayed update: applied_total=%lld new_total=%lld start_stop=%d bw_state=%s req_id=%d",
 		top_common->hw_idx, top_common->total_bw_applied,
 		top_common->hw_idx, top_common->total_bw_applied,
-		total_bw_new_vote, apply_bw_update, start_stop);
-
-	if (apply_bw_update) {
-		rc = cam_cpas_update_axi_vote(soc_private->cpas_handle,
-			to_be_applied_axi_vote);
-		if (!rc) {
-			memcpy(&top_common->applied_axi_vote,
-				to_be_applied_axi_vote,
-				sizeof(struct cam_axi_vote));
-			top_common->total_bw_applied = total_bw_new_vote;
-		} else {
-			CAM_ERR(CAM_PERF, "BW request failed, rc=%d", rc);
-		}
-	}
+		*total_bw_new_vote, start_stop,
+		cam_vfe_top_clk_bw_state_to_string(top_common->bw_state),
+		(start_stop ? -1 : request_id));
+
+	*to_be_applied_axi_vote = final_bw_vote;
 
 
+end:
 	return rc;
 	return rc;
 }
 }
 
 
@@ -328,21 +395,11 @@ int cam_vfe_top_bw_update_v2(struct cam_vfe_soc_private *soc_private,
 				&bw_update->isp_vote,
 				&bw_update->isp_vote,
 				sizeof(struct cam_axi_vote));
 				sizeof(struct cam_axi_vote));
 			top_common->axi_vote_control[i] =
 			top_common->axi_vote_control[i] =
-				CAM_VFE_BW_CONTROL_INCLUDE;
+				CAM_ISP_BW_CONTROL_INCLUDE;
 			break;
 			break;
 		}
 		}
 	}
 	}
 
 
-	if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) {
-		CAM_ERR_RATE_LIMIT(CAM_PERF,
-			"VFE:%d Not ready to set BW yet :%d",
-			res->hw_intf->hw_idx,
-			hw_info->hw_state);
-	} else {
-		rc = cam_vfe_top_set_axi_bw_vote(soc_private, top_common,
-			false);
-	}
-
 	return rc;
 	return rc;
 }
 }
 
 
@@ -412,7 +469,7 @@ int cam_vfe_top_bw_update(struct cam_vfe_soc_private *soc_private,
 				bw_update->external_bw_bytes;
 				bw_update->external_bw_bytes;
 
 
 			top_common->axi_vote_control[i] =
 			top_common->axi_vote_control[i] =
-				CAM_VFE_BW_CONTROL_INCLUDE;
+				CAM_ISP_BW_CONTROL_INCLUDE;
 			break;
 			break;
 		}
 		}
 
 
@@ -428,16 +485,6 @@ int cam_vfe_top_bw_update(struct cam_vfe_soc_private *soc_private,
 		}
 		}
 	}
 	}
 
 
-	if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) {
-		CAM_ERR_RATE_LIMIT(CAM_PERF,
-			"VFE:%d Not ready to set BW yet :%d",
-			res->hw_intf->hw_idx,
-			hw_info->hw_state);
-	} else {
-		rc = cam_vfe_top_set_axi_bw_vote(soc_private, top_common,
-			false);
-	}
-
 	return rc;
 	return rc;
 }
 }
 
 
@@ -445,13 +492,13 @@ int cam_vfe_top_bw_control(struct cam_vfe_soc_private *soc_private,
 	struct cam_vfe_top_priv_common *top_common, void *cmd_args,
 	struct cam_vfe_top_priv_common *top_common, void *cmd_args,
 	uint32_t arg_size)
 	uint32_t arg_size)
 {
 {
-	struct cam_vfe_bw_control_args       *bw_ctrl = NULL;
+	struct cam_isp_bw_control_args       *bw_ctrl = NULL;
 	struct cam_isp_resource_node         *res = NULL;
 	struct cam_isp_resource_node         *res = NULL;
 	struct cam_hw_info                   *hw_info = NULL;
 	struct cam_hw_info                   *hw_info = NULL;
 	int                                   rc = 0;
 	int                                   rc = 0;
 	int                                   i;
 	int                                   i;
 
 
-	bw_ctrl = (struct cam_vfe_bw_control_args *)cmd_args;
+	bw_ctrl = (struct cam_isp_bw_control_args *)cmd_args;
 	res = bw_ctrl->node_res;
 	res = bw_ctrl->node_res;
 
 
 	if (!res || !res->hw_intf->hw_priv)
 	if (!res || !res->hw_intf->hw_priv)
@@ -480,8 +527,213 @@ int cam_vfe_top_bw_control(struct cam_vfe_soc_private *soc_private,
 			res->hw_intf->hw_idx,
 			res->hw_intf->hw_idx,
 			hw_info->hw_state);
 			hw_info->hw_state);
 	} else {
 	} else {
-		rc = cam_vfe_top_set_axi_bw_vote(soc_private, top_common, true);
+		rc = cam_vfe_top_apply_bw_start_stop(top_common);
 	}
 	}
 
 
 	return rc;
 	return rc;
 }
 }
+
+int cam_vfe_top_apply_clk_bw_update(struct cam_vfe_top_priv_common *top_common,
+	void *cmd_args, uint32_t arg_size)
+{
+	struct cam_hw_info                   *hw_info = NULL;
+	struct cam_hw_intf                   *hw_intf = NULL;
+	struct cam_axi_vote *to_be_applied_axi_vote = NULL;
+	struct cam_isp_apply_clk_bw_args *clk_bw_args = NULL;
+	uint64_t                              final_clk_rate = 0;
+	uint64_t                              total_bw_new_vote = 0;
+	uint64_t                              request_id;
+	int rc = 0;
+
+	if (arg_size != sizeof(struct cam_isp_apply_clk_bw_args)) {
+		CAM_ERR(CAM_ISP, "Invalid arg size: %u", arg_size);
+		return -EINVAL;
+	}
+
+	clk_bw_args = (struct cam_isp_apply_clk_bw_args *)cmd_args;
+	request_id = clk_bw_args->request_id;
+	hw_intf = clk_bw_args->hw_intf;
+	if (!hw_intf) {
+		CAM_ERR(CAM_PERF, "Invalid hw_intf");
+		return -EINVAL;
+	}
+
+	hw_info = hw_intf->hw_priv;
+	if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) {
+		CAM_DBG(CAM_PERF,
+			"VFE:%d Not ready to set clocks yet :%d",
+			hw_intf->hw_idx, hw_info->hw_state);
+		goto end;
+	}
+
+	rc = cam_vfe_top_calc_hw_clk_rate(top_common, false, &final_clk_rate, request_id);
+	if (rc) {
+		CAM_ERR(CAM_ISP,
+			"VFE:%d Failed in calculating clock rate rc=%d",
+			hw_intf->hw_idx, rc);
+		goto end;
+	}
+
+	rc = cam_vfe_top_calc_axi_bw_vote(top_common, false,
+		&to_be_applied_axi_vote, &total_bw_new_vote, request_id);
+	if (rc) {
+		CAM_ERR(CAM_ISP, "VFE:%d Failed in calculating bw vote rc=%d",
+			hw_intf->hw_idx, rc);
+		goto end;
+	}
+
+	if ((!to_be_applied_axi_vote) && (top_common->bw_state != CAM_CLK_BW_STATE_UNCHANGED)) {
+		CAM_ERR(CAM_PERF, "VFE:%d Invalid BW vote for state:%s", hw_intf->hw_idx,
+			cam_vfe_top_clk_bw_state_to_string(top_common->bw_state));
+		rc = -EINVAL;
+		goto end;
+	}
+
+	CAM_DBG(CAM_PERF, "VFE:%d APPLY CLK/BW req_id:%d clk_state:%s bw_state:%s ",
+		hw_intf->hw_idx, request_id,
+		cam_vfe_top_clk_bw_state_to_string(top_common->clk_state),
+		cam_vfe_top_clk_bw_state_to_string(top_common->bw_state));
+
+	/* Determine BW and clock voting sequence according to state */
+	if ((top_common->clk_state == CAM_CLK_BW_STATE_UNCHANGED) &&
+		(top_common->bw_state == CAM_CLK_BW_STATE_UNCHANGED)) {
+		goto end;
+	} else if (top_common->clk_state == CAM_CLK_BW_STATE_UNCHANGED) {
+		rc = cam_vfe_top_set_axi_bw_vote(top_common, to_be_applied_axi_vote,
+			total_bw_new_vote, false, request_id);
+		if (rc) {
+			CAM_ERR(CAM_ISP,
+				"VFE:%d Failed in voting final bw:%llu clk_state:%s bw_state:%s",
+				hw_intf->hw_idx, total_bw_new_vote,
+				cam_vfe_top_clk_bw_state_to_string(top_common->clk_state),
+				cam_vfe_top_clk_bw_state_to_string(top_common->bw_state));
+			goto end;
+		}
+	} else if (top_common->bw_state == CAM_CLK_BW_STATE_UNCHANGED) {
+		rc = cam_vfe_top_set_hw_clk_rate(top_common, final_clk_rate, false, request_id);
+		if (rc) {
+			CAM_ERR(CAM_ISP,
+				"VFE:%d Failed in voting final clk:%llu clk_state:%s bw_state:%s",
+				hw_intf->hw_idx, final_clk_rate,
+				cam_vfe_top_clk_bw_state_to_string(top_common->clk_state),
+				cam_vfe_top_clk_bw_state_to_string(top_common->bw_state));
+			goto end;
+		}
+	} else if (top_common->clk_state == CAM_CLK_BW_STATE_INCREASE) {
+		/* Set BW first, followed by Clock */
+		rc = cam_vfe_top_set_axi_bw_vote(top_common, to_be_applied_axi_vote,
+			total_bw_new_vote, false, request_id);
+		if (rc) {
+			CAM_ERR(CAM_ISP,
+				"VFE:%d Failed in voting final bw:%llu clk_state:%s bw_state:%s",
+				hw_intf->hw_idx, total_bw_new_vote,
+				cam_vfe_top_clk_bw_state_to_string(top_common->clk_state),
+				cam_vfe_top_clk_bw_state_to_string(top_common->bw_state));
+			goto end;
+		}
+
+		rc = cam_vfe_top_set_hw_clk_rate(top_common, final_clk_rate, false, 0);
+		if (rc) {
+			CAM_ERR(CAM_ISP,
+				"VFE:%d Failed in voting final clk:%llu clk_state:%s bw_state:%s",
+				hw_intf->hw_idx, final_clk_rate,
+				cam_vfe_top_clk_bw_state_to_string(top_common->clk_state),
+				cam_vfe_top_clk_bw_state_to_string(top_common->bw_state));
+			goto end;
+		}
+	} else if (top_common->clk_state == CAM_CLK_BW_STATE_DECREASE) {
+		/* Set Clock first, followed by BW */
+		rc = cam_vfe_top_set_hw_clk_rate(top_common, final_clk_rate, false, request_id);
+		if (rc) {
+			CAM_ERR(CAM_ISP,
+				"VFE:%d Failed in voting final clk:%llu clk_state:%s bw_state:%s",
+				hw_intf->hw_idx, final_clk_rate,
+				cam_vfe_top_clk_bw_state_to_string(top_common->clk_state),
+				cam_vfe_top_clk_bw_state_to_string(top_common->bw_state));
+			goto end;
+		}
+
+		rc = cam_vfe_top_set_axi_bw_vote(top_common, to_be_applied_axi_vote,
+			total_bw_new_vote, false, request_id);
+		if (rc) {
+			CAM_ERR(CAM_ISP,
+				"VFE:%d Failed in voting final bw:%llu clk_state:%s bw_state:%s",
+				hw_intf->hw_idx, total_bw_new_vote,
+				cam_vfe_top_clk_bw_state_to_string(top_common->clk_state),
+				cam_vfe_top_clk_bw_state_to_string(top_common->bw_state));
+			goto end;
+		}
+	} else {
+		CAM_ERR(CAM_ISP, "Invalid state to apply CLK/BW clk_state:%s bw_state:%s",
+			cam_vfe_top_clk_bw_state_to_string(top_common->clk_state),
+			cam_vfe_top_clk_bw_state_to_string(top_common->bw_state));
+		rc = -EINVAL;
+		goto end;
+	}
+
+end:
+	top_common->clk_state = CAM_CLK_BW_STATE_INIT;
+	top_common->bw_state = CAM_CLK_BW_STATE_INIT;
+	return rc;
+}
+
+int cam_vfe_top_apply_clock_start_stop(struct cam_vfe_top_priv_common *top_common)
+{
+	int rc = 0;
+	uint64_t final_clk_rate = 0;
+
+	rc = cam_vfe_top_calc_hw_clk_rate(top_common, true, &final_clk_rate, 0);
+	if (rc) {
+		CAM_ERR(CAM_ISP,
+			"VFE:%d Failed in calculating clock rate rc=%d",
+			top_common->hw_idx, rc);
+		goto end;
+	}
+
+	if (top_common->clk_state == CAM_CLK_BW_STATE_UNCHANGED)
+		goto end;
+
+	rc = cam_vfe_top_set_hw_clk_rate(top_common, final_clk_rate, true, 0);
+	if (rc) {
+		CAM_ERR(CAM_ISP, "VFE:%d Failed in voting final clk:%llu clk_state:%s",
+			top_common->hw_idx, final_clk_rate,
+			cam_vfe_top_clk_bw_state_to_string(top_common->clk_state));
+		goto end;
+	}
+
+end:
+	top_common->clk_state = CAM_CLK_BW_STATE_INIT;
+	return rc;
+}
+
+int cam_vfe_top_apply_bw_start_stop(struct cam_vfe_top_priv_common *top_common)
+{
+	int rc = 0;
+	uint64_t total_bw_new_vote = 0;
+	struct cam_axi_vote *to_be_applied_axi_vote = NULL;
+
+	rc = cam_vfe_top_calc_axi_bw_vote(top_common, true, &to_be_applied_axi_vote,
+		&total_bw_new_vote, 0);
+	if (rc) {
+		CAM_ERR(CAM_ISP, "VFE:%d Failed in calculating bw vote rc=%d",
+			top_common->hw_idx, rc);
+		goto end;
+	}
+
+	if (top_common->bw_state == CAM_CLK_BW_STATE_UNCHANGED)
+		goto end;
+
+	rc = cam_vfe_top_set_axi_bw_vote(top_common, to_be_applied_axi_vote, total_bw_new_vote,
+		true, 0);
+	if (rc) {
+		CAM_ERR(CAM_ISP, "VFE:%d Failed in voting final bw:%llu bw_state:%s",
+			top_common->hw_idx, total_bw_new_vote,
+			cam_vfe_top_clk_bw_state_to_string(top_common->bw_state));
+		goto end;
+	}
+
+end:
+	top_common->bw_state = CAM_CLK_BW_STATE_INIT;
+	return rc;
+}
+

+ 17 - 12
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_common.h

@@ -7,7 +7,6 @@
 #define _CAM_VFE_TOP_COMMON_H_
 #define _CAM_VFE_TOP_COMMON_H_
 
 
 #define CAM_VFE_TOP_MUX_MAX 6
 #define CAM_VFE_TOP_MUX_MAX 6
-#define CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES 18
 
 
 #include "cam_cpas_api.h"
 #include "cam_cpas_api.h"
 #include "cam_vfe_hw_intf.h"
 #include "cam_vfe_hw_intf.h"
@@ -23,14 +22,18 @@ struct cam_vfe_top_priv_common {
 	uint32_t                        hw_idx;
 	uint32_t                        hw_idx;
 	struct cam_axi_vote             applied_axi_vote;
 	struct cam_axi_vote             applied_axi_vote;
 	struct cam_axi_vote             req_axi_vote[CAM_VFE_TOP_MUX_MAX];
 	struct cam_axi_vote             req_axi_vote[CAM_VFE_TOP_MUX_MAX];
-	struct cam_axi_vote             last_vote[
-					CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES];
-	uint32_t                        last_counter;
+	struct cam_axi_vote             last_bw_vote[CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ];
+	uint64_t                        last_total_bw_vote[CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ];
+	uint32_t                        last_bw_counter;
+	uint64_t                        last_clk_vote[CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ];
+	uint32_t                        last_clk_counter;
 	uint64_t                        total_bw_applied;
 	uint64_t                        total_bw_applied;
+	enum cam_clk_bw_state           clk_state;
+	enum cam_clk_bw_state           bw_state;
 	uint32_t                        hw_version;
 	uint32_t                        hw_version;
-	enum cam_vfe_bw_control_action  axi_vote_control[CAM_VFE_TOP_MUX_MAX];
+	enum cam_isp_bw_control_action  axi_vote_control[CAM_VFE_TOP_MUX_MAX];
 	struct cam_hw_soc_info         *soc_info;
 	struct cam_hw_soc_info         *soc_info;
-	unsigned long                   hw_clk_rate;
+	unsigned long                   applied_clk_rate;
 	unsigned long                   req_clk_rate[CAM_VFE_TOP_MUX_MAX];
 	unsigned long                   req_clk_rate[CAM_VFE_TOP_MUX_MAX];
 
 
 };
 };
@@ -59,15 +62,9 @@ struct cam_vfe_top_dump_data {
 		lut_entry[CAM_VFE_TOP_MAX_LUT_DUMP_ENTRIES];
 		lut_entry[CAM_VFE_TOP_MAX_LUT_DUMP_ENTRIES];
 };
 };
 
 
-int cam_vfe_top_set_hw_clk_rate(
-	struct cam_vfe_top_priv_common *top_common);
-
 int cam_vfe_top_clock_update(struct cam_vfe_top_priv_common *top_common,
 int cam_vfe_top_clock_update(struct cam_vfe_top_priv_common *top_common,
 	void *cmd_args, uint32_t arg_size);
 	void *cmd_args, uint32_t arg_size);
 
 
-int cam_vfe_top_set_axi_bw_vote(struct cam_vfe_soc_private *soc_private,
-	struct cam_vfe_top_priv_common *top_common, bool start_stop);
-
 int cam_vfe_top_bw_update_v2(struct cam_vfe_soc_private *soc_private,
 int cam_vfe_top_bw_update_v2(struct cam_vfe_soc_private *soc_private,
 	struct cam_vfe_top_priv_common *top_common, void *cmd_args,
 	struct cam_vfe_top_priv_common *top_common, void *cmd_args,
 	uint32_t arg_size);
 	uint32_t arg_size);
@@ -80,4 +77,12 @@ int cam_vfe_top_bw_control(struct cam_vfe_soc_private *soc_private,
 	struct cam_vfe_top_priv_common *top_common, void *cmd_args,
 	struct cam_vfe_top_priv_common *top_common, void *cmd_args,
 	uint32_t arg_size);
 	uint32_t arg_size);
 
 
+int cam_vfe_top_apply_clk_bw_update(
+	struct cam_vfe_top_priv_common *top_common, void *cmd_args,
+	uint32_t arg_size);
+
+int cam_vfe_top_apply_clock_start_stop(struct cam_vfe_top_priv_common *top_common);
+
+int cam_vfe_top_apply_bw_start_stop(struct cam_vfe_top_priv_common *top_common);
+
 #endif /* _CAM_VFE_TOP_COMMON_H_ */
 #endif /* _CAM_VFE_TOP_COMMON_H_ */

+ 12 - 8
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c

@@ -422,7 +422,7 @@ int cam_vfe_top_init_hw(void *device_priv,
 	struct cam_vfe_top_ver2_priv   *top_priv = device_priv;
 	struct cam_vfe_top_ver2_priv   *top_priv = device_priv;
 	struct cam_vfe_top_ver2_common_data common_data = top_priv->common_data;
 	struct cam_vfe_top_ver2_common_data common_data = top_priv->common_data;
 
 
-	top_priv->top_common.hw_clk_rate = 0;
+	top_priv->top_common.applied_clk_rate = 0;
 
 
 	top_priv->top_common.hw_version =
 	top_priv->top_common.hw_version =
 		cam_io_r_mb(top_priv->top_common.soc_info->reg_map[0].mem_base +
 		cam_io_r_mb(top_priv->top_common.soc_info->reg_map[0].mem_base +
@@ -602,18 +602,19 @@ int cam_vfe_top_start(void *device_priv,
 	hw_info = (struct cam_hw_info  *)mux_res->hw_intf->hw_priv;
 	hw_info = (struct cam_hw_info  *)mux_res->hw_intf->hw_priv;
 
 
 	if (hw_info->hw_state == CAM_HW_STATE_POWER_UP) {
 	if (hw_info->hw_state == CAM_HW_STATE_POWER_UP) {
-		rc = cam_vfe_top_set_hw_clk_rate(&top_priv->top_common);
+		rc = cam_vfe_top_apply_clock_start_stop(&top_priv->top_common);
 		if (rc) {
 		if (rc) {
 			CAM_ERR(CAM_ISP,
 			CAM_ERR(CAM_ISP,
-				"set_hw_clk_rate failed, rc=%d", rc);
+				"VFE:%d Failed in applying start clock rc:%d",
+				hw_info->soc_info.index, rc);
 			return rc;
 			return rc;
 		}
 		}
 
 
-		rc = cam_vfe_top_set_axi_bw_vote(soc_private,
-			&top_priv->top_common, true);
+		rc = cam_vfe_top_apply_bw_start_stop(&top_priv->top_common);
 		if (rc) {
 		if (rc) {
 			CAM_ERR(CAM_ISP,
 			CAM_ERR(CAM_ISP,
-				"set_axi_bw_vote failed, rc=%d", rc);
+				"VFE:%d Failed in applying start bw rc:%d",
+				hw_info->soc_info.index, rc);
 			return rc;
 			return rc;
 		}
 		}
 
 
@@ -676,7 +677,7 @@ int cam_vfe_top_stop(void *device_priv,
 				top_priv->top_common.req_axi_vote[i]
 				top_priv->top_common.req_axi_vote[i]
 					.axi_path[0].mnoc_ib_bw = 0;
 					.axi_path[0].mnoc_ib_bw = 0;
 				top_priv->top_common.axi_vote_control[i] =
 				top_priv->top_common.axi_vote_control[i] =
-					CAM_VFE_BW_CONTROL_EXCLUDE;
+					CAM_ISP_BW_CONTROL_EXCLUDE;
 				break;
 				break;
 			}
 			}
 		}
 		}
@@ -765,6 +766,9 @@ int cam_vfe_top_process_cmd(void *device_priv, uint32_t cmd_type,
 	case CAM_ISP_HW_CMD_BLANKING_UPDATE:
 	case CAM_ISP_HW_CMD_BLANKING_UPDATE:
 		rc = cam_vfe_top_blanking_update(cmd_type, cmd_args, arg_size);
 		rc = cam_vfe_top_blanking_update(cmd_type, cmd_args, arg_size);
 		break;
 		break;
+	case CAM_ISP_HW_CMD_APPLY_CLK_BW_UPDATE:
+		rc = cam_vfe_top_apply_clk_bw_update(&top_priv->top_common, cmd_args, arg_size);
+		break;
 	default:
 	default:
 		rc = -EINVAL;
 		rc = -EINVAL;
 		CAM_ERR(CAM_ISP, "Error! Invalid cmd:%d", cmd_type);
 		CAM_ERR(CAM_ISP, "Error! Invalid cmd:%d", cmd_type);
@@ -802,7 +806,7 @@ int cam_vfe_top_ver2_init(
 	}
 	}
 
 
 	vfe_top->top_priv = top_priv;
 	vfe_top->top_priv = top_priv;
-	top_priv->top_common.hw_clk_rate = 0;
+	top_priv->top_common.applied_clk_rate = 0;
 	if (ver2_hw_info->num_mux > CAM_VFE_TOP_MUX_MAX) {
 	if (ver2_hw_info->num_mux > CAM_VFE_TOP_MUX_MAX) {
 		CAM_ERR(CAM_ISP, "Invalid number of input rsrc: %d, max: %d",
 		CAM_ERR(CAM_ISP, "Invalid number of input rsrc: %d, max: %d",
 			ver2_hw_info->num_mux, CAM_VFE_TOP_MUX_MAX);
 			ver2_hw_info->num_mux, CAM_VFE_TOP_MUX_MAX);

+ 12 - 8
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c

@@ -331,7 +331,7 @@ int cam_vfe_top_ver3_init_hw(void *device_priv,
 	struct cam_vfe_top_ver3_priv   *top_priv = device_priv;
 	struct cam_vfe_top_ver3_priv   *top_priv = device_priv;
 	struct cam_vfe_top_ver3_common_data common_data = top_priv->common_data;
 	struct cam_vfe_top_ver3_common_data common_data = top_priv->common_data;
 
 
-	top_priv->top_common.hw_clk_rate = 0;
+	top_priv->top_common.applied_clk_rate = 0;
 
 
 	/**
 	/**
 	 * Auto clock gating is enabled by default, but no harm
 	 * Auto clock gating is enabled by default, but no harm
@@ -545,18 +545,19 @@ int cam_vfe_top_ver3_start(void *device_priv,
 	hw_info = (struct cam_hw_info  *)mux_res->hw_intf->hw_priv;
 	hw_info = (struct cam_hw_info  *)mux_res->hw_intf->hw_priv;
 
 
 	if (hw_info->hw_state == CAM_HW_STATE_POWER_UP) {
 	if (hw_info->hw_state == CAM_HW_STATE_POWER_UP) {
-		rc = cam_vfe_top_set_hw_clk_rate(&top_priv->top_common);
+		rc = cam_vfe_top_apply_clock_start_stop(&top_priv->top_common);
 		if (rc) {
 		if (rc) {
 			CAM_ERR(CAM_ISP,
 			CAM_ERR(CAM_ISP,
-				"set_hw_clk_rate failed, rc=%d", rc);
+				"VFE:%d Failed in applying start clock rc:%d",
+				hw_info->soc_info.index, rc);
 			return rc;
 			return rc;
 		}
 		}
 
 
-		rc = cam_vfe_top_set_axi_bw_vote(soc_private,
-			&top_priv->top_common, true);
+		rc = cam_vfe_top_apply_bw_start_stop(&top_priv->top_common);
 		if (rc) {
 		if (rc) {
 			CAM_ERR(CAM_ISP,
 			CAM_ERR(CAM_ISP,
-				"set_axi_bw_vote failed, rc=%d", rc);
+				"VFE:%d Failed in applying start bw rc:%d",
+				hw_info->soc_info.index, rc);
 			return rc;
 			return rc;
 		}
 		}
 
 
@@ -614,7 +615,7 @@ int cam_vfe_top_ver3_stop(void *device_priv,
 				memset(&top_priv->top_common.req_axi_vote[i],
 				memset(&top_priv->top_common.req_axi_vote[i],
 					0, sizeof(struct cam_axi_vote));
 					0, sizeof(struct cam_axi_vote));
 				top_priv->top_common.axi_vote_control[i] =
 				top_priv->top_common.axi_vote_control[i] =
-					CAM_VFE_BW_CONTROL_EXCLUDE;
+					CAM_ISP_BW_CONTROL_EXCLUDE;
 				break;
 				break;
 			}
 			}
 		}
 		}
@@ -711,6 +712,9 @@ int cam_vfe_top_ver3_process_cmd(void *device_priv, uint32_t cmd_type,
 		rc = cam_vfe_top_ver3_get_path_port_map(top_priv, cmd_args,
 		rc = cam_vfe_top_ver3_get_path_port_map(top_priv, cmd_args,
 			arg_size);
 			arg_size);
 		break;
 		break;
+	case CAM_ISP_HW_CMD_APPLY_CLK_BW_UPDATE:
+		rc = cam_vfe_top_apply_clk_bw_update(&top_priv->top_common, cmd_args, arg_size);
+		break;
 	default:
 	default:
 		rc = -EINVAL;
 		rc = -EINVAL;
 		CAM_ERR(CAM_ISP, "Error, Invalid cmd:%d", cmd_type);
 		CAM_ERR(CAM_ISP, "Error, Invalid cmd:%d", cmd_type);
@@ -748,7 +752,7 @@ int cam_vfe_top_ver3_init(
 	}
 	}
 
 
 	vfe_top->top_priv = top_priv;
 	vfe_top->top_priv = top_priv;
-	top_priv->top_common.hw_clk_rate = 0;
+	top_priv->top_common.applied_clk_rate = 0;
 	if (ver3_hw_info->num_mux > CAM_VFE_TOP_MUX_MAX) {
 	if (ver3_hw_info->num_mux > CAM_VFE_TOP_MUX_MAX) {
 		CAM_ERR(CAM_ISP, "Invalid number of input rsrc: %d, max: %d",
 		CAM_ERR(CAM_ISP, "Invalid number of input rsrc: %d, max: %d",
 			ver3_hw_info->num_mux, CAM_VFE_TOP_MUX_MAX);
 			ver3_hw_info->num_mux, CAM_VFE_TOP_MUX_MAX);

+ 12 - 8
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver4.c

@@ -1119,7 +1119,7 @@ int cam_vfe_top_ver4_init_hw(void *device_priv,
 	struct cam_vfe_top_ver4_priv   *top_priv = device_priv;
 	struct cam_vfe_top_ver4_priv   *top_priv = device_priv;
 	struct cam_vfe_top_ver4_common_data common_data = top_priv->common_data;
 	struct cam_vfe_top_ver4_common_data common_data = top_priv->common_data;
 
 
-	top_priv->top_common.hw_clk_rate = 0;
+	top_priv->top_common.applied_clk_rate = 0;
 
 
 	/**
 	/**
 	 * Auto clock gating is enabled by default, but no harm
 	 * Auto clock gating is enabled by default, but no harm
@@ -1317,18 +1317,19 @@ int cam_vfe_top_ver4_start(void *device_priv,
 	hw_info = (struct cam_hw_info *)mux_res->hw_intf->hw_priv;
 	hw_info = (struct cam_hw_info *)mux_res->hw_intf->hw_priv;
 
 
 	if (hw_info->hw_state == CAM_HW_STATE_POWER_UP) {
 	if (hw_info->hw_state == CAM_HW_STATE_POWER_UP) {
-		rc = cam_vfe_top_set_hw_clk_rate(&top_priv->top_common);
+		rc = cam_vfe_top_apply_clock_start_stop(&top_priv->top_common);
 		if (rc) {
 		if (rc) {
 			CAM_ERR(CAM_ISP,
 			CAM_ERR(CAM_ISP,
-				"set_hw_clk_rate failed, rc=%d", rc);
+				"VFE:%d Failed in applying start clock rc:%d",
+				hw_info->soc_info.index, rc);
 			return rc;
 			return rc;
 		}
 		}
 
 
-		rc = cam_vfe_top_set_axi_bw_vote(soc_private,
-			&top_priv->top_common, true);
+		rc = cam_vfe_top_apply_bw_start_stop(&top_priv->top_common);
 		if (rc) {
 		if (rc) {
 			CAM_ERR(CAM_ISP,
 			CAM_ERR(CAM_ISP,
-				"set_axi_bw_vote failed, rc=%d", rc);
+				"VFE:%d Failed in applying start bw rc:%d",
+				hw_info->soc_info.index, rc);
 			return rc;
 			return rc;
 		}
 		}
 
 
@@ -1380,7 +1381,7 @@ int cam_vfe_top_ver4_stop(void *device_priv,
 				memset(&top_priv->top_common.req_axi_vote[i],
 				memset(&top_priv->top_common.req_axi_vote[i],
 					0, sizeof(struct cam_axi_vote));
 					0, sizeof(struct cam_axi_vote));
 				top_priv->top_common.axi_vote_control[i] =
 				top_priv->top_common.axi_vote_control[i] =
-					CAM_VFE_BW_CONTROL_EXCLUDE;
+					CAM_ISP_BW_CONTROL_EXCLUDE;
 				break;
 				break;
 			}
 			}
 		}
 		}
@@ -1468,6 +1469,9 @@ int cam_vfe_top_ver4_process_cmd(void *device_priv, uint32_t cmd_type,
 		rc = cam_vfe_top_ver4_get_path_port_map(top_priv, cmd_args,
 		rc = cam_vfe_top_ver4_get_path_port_map(top_priv, cmd_args,
 			arg_size);
 			arg_size);
 		break;
 		break;
+	case CAM_ISP_HW_CMD_APPLY_CLK_BW_UPDATE:
+		rc = cam_vfe_top_apply_clk_bw_update(&top_priv->top_common, cmd_args, arg_size);
+		break;
 	default:
 	default:
 		rc = -EINVAL;
 		rc = -EINVAL;
 		CAM_ERR(CAM_ISP, "Error, Invalid cmd:%d", cmd_type);
 		CAM_ERR(CAM_ISP, "Error, Invalid cmd:%d", cmd_type);
@@ -2167,7 +2171,7 @@ int cam_vfe_top_ver4_init(
 	}
 	}
 
 
 	vfe_top->top_priv = top_priv;
 	vfe_top->top_priv = top_priv;
-	top_priv->top_common.hw_clk_rate = 0;
+	top_priv->top_common.applied_clk_rate = 0;
 
 
 	if (hw_info->num_mux > CAM_VFE_TOP_MUX_MAX) {
 	if (hw_info->num_mux > CAM_VFE_TOP_MUX_MAX) {
 		CAM_ERR(CAM_ISP, "Invalid number of input rsrc: %d, max: %d",
 		CAM_ERR(CAM_ISP, "Invalid number of input rsrc: %d, max: %d",