Browse Source

msm: camera: isp: Add support for clk bw update on config

Move clock update call from prepare to config. Add delay
in clock reduction and enable src clock update only when blob
is received. Optimize bw update and combine application of
clock and bw in ife and sfe. Finish update will be common for
clock and bw update, and will be called once per acquired hw.

CRs-Fixed: 2841729
Change-Id: Ideb8e8cfe6838bb9d5c861fb6b7cbc5e499ebee5
Signed-off-by: Mukund Madhusudan Atre <[email protected]>
Mukund Madhusudan Atre 4 years ago
parent
commit
fc00541bb9

+ 10 - 1
drivers/cam_core/cam_hw_intf.h

@@ -1,6 +1,6 @@
 /* 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_
@@ -13,6 +13,15 @@
  * 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
  *

+ 1 - 0
drivers/cam_isp/cam_isp_context.c

@@ -4977,6 +4977,7 @@ static int __cam_isp_ctx_config_dev_in_top_state(
 	cfg.pf_data = &(req->pf_data);
 	cfg.num_out_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.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 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(
 	void                                *priv,
 	uint32_t                             evt_id,
 	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(
 	struct list_head          *res_list,
 	enum cam_isp_hw_split_id   split_id,
@@ -5348,6 +5387,10 @@ static int cam_isp_blob_bw_update_v2(
 				bw_upd_args.node_res =
 					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(
 					hw_intf->hw_priv,
 					CAM_ISP_HW_CMD_BW_UPDATE_V2,
@@ -5387,6 +5430,10 @@ static int cam_isp_blob_bw_update_v2(
 				sfe_bw_update_args.node_res =
 					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(
 					hw_intf->hw_priv,
 					CAM_ISP_HW_CMD_BW_UPDATE_V2,
@@ -5573,38 +5620,64 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv,
 		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,
 		"Enter ctx id:%d num_hw_upd_entries %d request id: %llu",
 		ctx->ctx_index, cfg->num_hw_update_entries, cfg->request_id);
@@ -5752,11 +5825,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,
-	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_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;
 	uint32_t                               i;
 
@@ -5777,7 +5850,30 @@ static int cam_ife_mgr_bw_control(struct cam_ife_hw_mgr_ctx *ctx,
 					hw_intf->hw_priv,
 					CAM_ISP_HW_CMD_BW_CONTROL,
 					&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)
 					CAM_ERR(CAM_ISP, "BW Update failed");
 			} else
@@ -5790,7 +5886,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)
 {
-	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 */
@@ -7618,30 +7714,21 @@ static int cam_isp_blob_sfe_core_cfg_update(
 	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_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_hw_intf                    *hw_intf;
 	struct cam_vfe_clock_update_args       clock_upd_args;
 	uint64_t                               clk_rate = 0;
 	int                                    rc = -EINVAL;
-	uint32_t                               i;
-	uint32_t                               j;
+	uint32_t                               i, j;
 	bool                                   camif_l_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) {
 		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
@@ -7649,26 +7736,9 @@ static int cam_isp_blob_clock_update(
 			if (!hw_mgr_res->hw_res[i])
 				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 (camif_l_clk_updated)
 						continue;
@@ -7703,38 +7773,43 @@ static int cam_isp_blob_clock_update(
 
 			hw_intf = hw_mgr_res->hw_res[i]->hw_intf;
 			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,
-				"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;
 
+				/*
+				 * 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(
 					hw_intf->hw_priv,
 					CAM_ISP_HW_CMD_CLOCK_UPDATE,
 					&clock_upd_args,
 					sizeof(
 					struct cam_vfe_clock_update_args));
-				if (rc)
+				if (rc) {
 					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
 				CAM_WARN(CAM_ISP, "NULL hw_intf!");
 		}
 	}
 
+end:
 	return rc;
 }
 
+
 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_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_hw_intf                    *hw_intf;
 	struct cam_sfe_clock_update_args       clock_upd_args;
@@ -7744,13 +7819,10 @@ static int cam_isp_blob_sfe_clock_update(
 	bool                                   l_clk_updated = false;
 	bool                                   r_clk_updated = false;
 
-	ctx = prepare->ctxt_to_hw_map;
 
 	CAM_DBG(CAM_PERF,
 		"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) {
 		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
@@ -7789,6 +7861,10 @@ static int cam_isp_blob_sfe_clock_update(
 				hw_mgr_res->res_id, i, 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(
 					hw_intf->hw_priv,
 					CAM_ISP_HW_CMD_CLOCK_UPDATE,
@@ -8167,7 +8243,9 @@ static int cam_isp_packet_generic_blob_handler(void *user_data,
 	}
 		break;
 	case CAM_ISP_GENERIC_BLOB_TYPE_CLOCK_CONFIG: {
+		size_t clock_config_size = 0;
 		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)) {
 			CAM_ERR(CAM_ISP, "Invalid blob size %u", blob_size);
@@ -8205,10 +8283,14 @@ static int cam_isp_packet_generic_blob_handler(void *user_data,
 			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;
 	case CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG: {
@@ -8255,7 +8337,7 @@ static int cam_isp_packet_generic_blob_handler(void *user_data,
 		}
 
 		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",
 				bw_config->usage_type);
 			return -EINVAL;
@@ -8264,10 +8346,10 @@ static int cam_isp_packet_generic_blob_handler(void *user_data,
 		prepare_hw_data = (struct cam_isp_prepare_hw_update_data  *)
 			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;
 	case CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG_V2: {
@@ -8317,7 +8399,7 @@ static int cam_isp_packet_generic_blob_handler(void *user_data,
 		}
 
 		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",
 				bw_config->usage_type);
 			return -EINVAL;
@@ -8326,17 +8408,16 @@ static int cam_isp_packet_generic_blob_handler(void *user_data,
 		prepare_hw_data = (struct cam_isp_prepare_hw_update_data  *)
 			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->num_paths - 1) *
 			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;
 	case CAM_ISP_GENERIC_BLOB_TYPE_UBWC_CONFIG: {
@@ -8760,7 +8841,9 @@ static int cam_sfe_packet_generic_blob_handler(void *user_data,
 
 	switch (blob_type) {
 	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_prepare_hw_update_data *prepare_hw_data;
 
 		if (blob_size < sizeof(struct cam_isp_clock_config)) {
 			CAM_ERR(CAM_ISP, "Invalid blob size %u", blob_size);
@@ -8798,10 +8881,14 @@ static int cam_sfe_packet_generic_blob_handler(void *user_data,
 			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;
 	case CAM_ISP_GENERIC_BLOB_TYPE_SFE_OUT_CONFIG: {
@@ -9625,13 +9712,6 @@ static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv,
 	prepare->num_out_map_entries = 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 */
 	if (ctx->ctx_type != CAM_IFE_CTX_TYPE_SFE)
 		res_list_ife_rd_tmp = &ctx->res_list_ife_in_rd;
@@ -9836,7 +9916,7 @@ end:
 
 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(

+ 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.
  * @sfe_info                SFE info pertaining to this stream
  * @flags                   Flags pertainting to this ctx
+ * @bw_config_version       BW Config version
  *
  */
 struct cam_ife_hw_mgr_ctx {
@@ -256,6 +257,7 @@ struct cam_ife_hw_mgr_ctx {
 	void                           *buf_done_controller;
 	struct cam_ife_hw_mgr_sfe_info  sfe_info;
 	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;
 	}
 
-	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,
-					"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;
 	struct cam_isp_generic_blob_info  *blob_info = user_data;
 	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) {
 		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;
 	}
 
+	tfe_mgr_ctx = prepare->ctxt_to_hw_map;
 	CAM_DBG(CAM_ISP, "BLOB Type: %d", blob_type);
 	switch (blob_type) {
 	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->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->num_paths - 1) *
 			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;
 	case CAM_ISP_TFE_GENERIC_BLOB_TYPE_CSID_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_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++) {
 		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
  * @dual_tfe_irq_mismatch_cnt irq mismatch count value per core, used for
  *                              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 list_head                list;
@@ -124,6 +125,7 @@ struct cam_tfe_hw_mgr_ctx {
 	uint32_t                        slave_hw_idx;
 	uint32_t                        dual_tfe_irq_mismatch_cnt;
 	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;
 };
 
-
+/**
+ * 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
@@ -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_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
  *
@@ -146,11 +188,7 @@ struct cam_isp_bw_config_internal {
  * @frame_header_cpu_addr:  Frame header cpu addr
  * @frame_header_iova:      Frame header iova
  * @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
  * @num_reg_dump_buf:      Count of descriptors in reg_dump_buf_desc
  * @packet                 CSL packet from user mode driver
@@ -164,10 +202,7 @@ struct cam_isp_prepare_hw_update_data {
 	uint32_t                             *frame_header_cpu_addr;
 	uint64_t                              frame_header_iova;
 	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[
 						CAM_REG_DUMP_MAX_BUF_ENTRIES];
 	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
 
+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:
  *
@@ -69,6 +96,12 @@ enum cam_isp_hw_split_id {
 	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 {
 	CAM_ISP_HW_SYNC_NONE,
 	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_CMD_WM_BW_LIMIT_CONFIG,
 	CAM_ISP_HW_CMD_RM_ENABLE_DISABLE,
+	CAM_ISP_HW_CMD_APPLY_CLK_BW_UPDATE,
 	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,
 };
 
-enum cam_sfe_bw_control_action {
-	CAM_SFE_BW_CONTROL_EXCLUDE,
-	CAM_SFE_BW_CONTROL_INCLUDE,
-};
-
 enum cam_sfe_hw_irq_regs {
 	CAM_SFE_IRQ_TOP_REG_STATUS0,
 	CAM_SFE_IRQ_REGISTERS_MAX,
@@ -96,17 +91,6 @@ struct cam_sfe_debug_cfg_params {
 	} 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:
  *

+ 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 */
 /*
- * 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_
@@ -269,22 +269,6 @@ struct cam_vfe_fe_update_args {
 	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:
  *

+ 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_CORE_CONFIG:
 	case CAM_ISP_HW_NOTIFY_OVERFLOW:
+	case CAM_ISP_HW_CMD_APPLY_CLK_BW_UPDATE:
 		rc = core_info->sfe_top->hw_ops.process_cmd(
 			core_info->sfe_top->top_priv, cmd_type,
 			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_core.h"
 
-#define CAM_SFE_DELAY_BW_REDUCTION_NUM_FRAMES 18
-
 struct cam_sfe_core_cfg {
 	uint32_t   mode_sel;
 	uint32_t   ops_mode_cfg;
@@ -35,14 +33,18 @@ struct cam_sfe_top_priv {
 	struct cam_sfe_top_common_data  common_data;
 	struct cam_isp_resource_node    in_rsrc[CAM_SFE_TOP_IN_PORT_MAX];
 	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];
-	uint32_t                        last_counter;
+	uint32_t                        last_bw_counter;
+	uint32_t                        last_clk_counter;
 	uint64_t                        total_bw_applied;
 	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];
 	struct cam_axi_vote             applied_axi_vote;
 	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(
 	uint32_t num_reg, uint32_t *reg_val,
 	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,
 	uint64_t *to_be_applied_bw)
 {
-	uint32_t i, j;
+	uint32_t i;
 	int vote_idx = -1;
 	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;
-			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;
 
-	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;
 	uint32_t i;
 	uint32_t num_paths = 0;
-	uint64_t total_bw_new_vote = 0;
 	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++) {
 		if (top_priv->axi_vote_control[i] ==
-			CAM_SFE_BW_CONTROL_INCLUDE) {
+			CAM_ISP_BW_CONTROL_INCLUDE) {
 			if (num_paths +
 				top_priv->req_axi_vote[i].num_paths >
 				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 +
 					top_priv->req_axi_vote[i].num_paths,
 					CAM_CPAS_MAX_PATHS_PER_CLIENT);
-				return -EINVAL;
+				rc = -EINVAL;
+				goto end;
 			}
 
 			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,
 			"sfe[%d] : New BW Vote : counter[%d] [%s][%s] [%llu %llu %llu]",
 			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(
 			agg_vote.axi_path[i].path_data_type),
 			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_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));
-	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;
 
 	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,
-		total_bw_new_vote, bw_unchanged, start_stop);
+		*total_bw_new_vote, bw_unchanged, start_stop, (start_stop ? -1 : request_id));
 
 	if (bw_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) {
 		/* need to vote current request immediately */
-		to_be_applied_axi_vote = &agg_vote;
+		final_bw_vote = &agg_vote;
 		/* 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 {
 		/*
 		 * Find max bw request in last few frames. This will the bw
 		 * 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,
 			"sfe[%d] : Apply BW Vote : [%s][%s] [%llu %llu %llu]",
 			top_priv->common_data.hw_intf->hw_idx,
 			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(
-			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,
-		"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;
 }
 
@@ -665,21 +744,11 @@ int cam_sfe_top_bw_update(struct cam_sfe_soc_private *soc_private,
 				&bw_update->sfe_vote,
 				sizeof(struct cam_axi_vote));
 			top_priv->axi_vote_control[i] =
-				CAM_SFE_BW_CONTROL_INCLUDE;
+				CAM_ISP_BW_CONTROL_INCLUDE;
 			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;
 }
 
@@ -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,
 	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_hw_info                   *hw_info = NULL;
 	int                                   rc = 0;
 	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;
 
 	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,
 			hw_info->hw_state);
 	} 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;
@@ -751,66 +820,71 @@ static int cam_sfe_top_core_cfg(
 	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 {
-		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;
 }
 
+
 static int cam_sfe_top_get_base(
 	struct cam_sfe_top_priv *top_priv,
 	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_isp_resource_node         *res = NULL;
 	struct cam_hw_info                   *hw_info = NULL;
-	int                                   rc = 0, i;
+	int i;
 
 	if (arg_size != sizeof(struct cam_sfe_clock_update_args)) {
 		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(
@@ -971,6 +1037,208 @@ static int cam_sfe_top_handle_overflow(
 	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,
 	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);
 		break;
 	case CAM_ISP_HW_CMD_BW_CONTROL:
+		rc = cam_sfe_top_bw_control(soc_private, top_priv, cmd_args, arg_size);
 		break;
 	case CAM_ISP_HW_CMD_CORE_CONFIG:
 		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:
 		rc = cam_sfe_top_handle_overflow(top_priv, cmd_type);
 		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:
 		CAM_ERR(CAM_SFE, "Invalid cmd type: %d", cmd_type);
 		rc = -EINVAL;
@@ -1450,15 +1722,17 @@ int cam_sfe_top_start(
 	}
 
 	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;
+	}
 
-	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) {
-		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;
 	}
 
@@ -1585,7 +1859,7 @@ int cam_sfe_top_stop(
 			memset(&top_priv->req_axi_vote[i], 0,
 				sizeof(struct cam_axi_vote));
 			top_priv->axi_vote_control[i] =
-				CAM_SFE_BW_CONTROL_EXCLUDE;
+				CAM_ISP_BW_CONTROL_EXCLUDE;
 			break;
 		}
 	}
@@ -1629,7 +1903,7 @@ int cam_sfe_top_stop(
 	 * when all resources are streamed off
 	 */
 	if (!start_stop_cnt) {
-		top_priv->hw_clk_rate = 0;
+		top_priv->applied_clk_rate = 0;
 		if (top_priv->error_irq_handle > 0) {
 			cam_irq_controller_unsubscribe_irq(
 				top_priv->common_data.sfe_irq_controller,
@@ -1681,10 +1955,8 @@ int cam_sfe_top_init(
 		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;
-	memset(top_priv->last_vote, 0x0, sizeof(struct cam_axi_vote) *
-		CAM_SFE_DELAY_BW_REDUCTION_NUM_FRAMES);
 	memset(&top_priv->core_cfg, 0x0,
 		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_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_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_FE_UPDATE_IN_RD:
 	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(
 			core_info->vfe_top->top_priv, cmd_type, cmd_args,
 			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
 /*
- * 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_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_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_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) {
-		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);
 		if (rc) {
 			CAM_WARN(CAM_ISP,
 				"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);
 			rc = 0;
 			goto end;
@@ -63,13 +91,77 @@ end:
 	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,
 	void *cmd_args, uint32_t arg_size)
 {
 	struct cam_vfe_clock_update_args     *clk_update = NULL;
 	struct cam_isp_resource_node         *res = NULL;
 	struct cam_hw_info                   *hw_info = NULL;
-	int                                   i, rc = 0;
+	int                                   i;
 
 	clk_update =
 		(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(
 	struct cam_vfe_top_priv_common *top_common,
 	uint64_t *to_be_applied_bw)
 {
-	uint32_t i, j;
+	uint32_t i;
 	int vote_idx = -1;
 	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;
-			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;
 
-	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;
 	uint32_t i;
 	uint32_t num_paths = 0;
-	uint64_t total_bw_new_vote = 0;
 	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) {
 		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;
 	}
 
+	memset(&agg_vote, 0, sizeof(struct cam_axi_vote));
 	for (i = 0; i < top_common->num_mux; i++) {
 		if (top_common->axi_vote_control[i] ==
-			CAM_VFE_BW_CONTROL_INCLUDE) {
+			CAM_ISP_BW_CONTROL_INCLUDE) {
 			if (num_paths +
 				top_common->req_axi_vote[i].num_paths >
 				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 +
 					top_common->req_axi_vote[i].num_paths,
 					CAM_CPAS_MAX_PATHS_PER_CLIENT);
-				return -EINVAL;
+				rc = -EINVAL;
+				goto end;
 			}
 
 			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,
 			"ife[%d] : New BW Vote : counter[%d] [%s][%s] [%llu %llu %llu]",
 			top_common->hw_idx,
-			top_common->last_counter,
+			top_common->last_bw_counter,
 			cam_cpas_axi_util_path_type_to_string(
 			agg_vote.axi_path[i].path_data_type),
 			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_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));
-	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;
 
 	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,
-		total_bw_new_vote, bw_unchanged, start_stop);
+		*total_bw_new_vote, bw_unchanged, start_stop, (start_stop ? -1 : request_id));
 
 	if (bw_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) {
 		/* need to vote current request immediately */
-		to_be_applied_axi_vote = &agg_vote;
+		final_bw_vote = &agg_vote;
 		/* 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 {
 		/*
 		 * Find max bw request in last few frames. This will the bw
 		 * that we want to vote to CPAS now.
 		 */
-		to_be_applied_axi_vote =
+		final_bw_vote =
 			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");
-			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,
 			"ife[%d] : Apply BW Vote : [%s][%s] [%llu %llu %llu]",
 			top_common->hw_idx,
 			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(
-			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,
-		"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,
-		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;
 }
 
@@ -328,21 +395,11 @@ int cam_vfe_top_bw_update_v2(struct cam_vfe_soc_private *soc_private,
 				&bw_update->isp_vote,
 				sizeof(struct cam_axi_vote));
 			top_common->axi_vote_control[i] =
-				CAM_VFE_BW_CONTROL_INCLUDE;
+				CAM_ISP_BW_CONTROL_INCLUDE;
 			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;
 }
 
@@ -412,7 +469,7 @@ int cam_vfe_top_bw_update(struct cam_vfe_soc_private *soc_private,
 				bw_update->external_bw_bytes;
 
 			top_common->axi_vote_control[i] =
-				CAM_VFE_BW_CONTROL_INCLUDE;
+				CAM_ISP_BW_CONTROL_INCLUDE;
 			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;
 }
 
@@ -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,
 	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_hw_info                   *hw_info = NULL;
 	int                                   rc = 0;
 	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;
 
 	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,
 			hw_info->hw_state);
 	} 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;
 }
+
+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_MUX_MAX 6
-#define CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES 18
 
 #include "cam_cpas_api.h"
 #include "cam_vfe_hw_intf.h"
@@ -23,14 +22,18 @@ struct cam_vfe_top_priv_common {
 	uint32_t                        hw_idx;
 	struct cam_axi_vote             applied_axi_vote;
 	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;
+	enum cam_clk_bw_state           clk_state;
+	enum cam_clk_bw_state           bw_state;
 	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;
-	unsigned long                   hw_clk_rate;
+	unsigned long                   applied_clk_rate;
 	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];
 };
 
-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,
 	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,
 	struct cam_vfe_top_priv_common *top_common, void *cmd_args,
 	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,
 	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_ */

+ 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_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 =
 		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;
 
 	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) {
 			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;
 		}
 
-		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) {
 			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;
 		}
 
@@ -676,7 +677,7 @@ int cam_vfe_top_stop(void *device_priv,
 				top_priv->top_common.req_axi_vote[i]
 					.axi_path[0].mnoc_ib_bw = 0;
 				top_priv->top_common.axi_vote_control[i] =
-					CAM_VFE_BW_CONTROL_EXCLUDE;
+					CAM_ISP_BW_CONTROL_EXCLUDE;
 				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:
 		rc = cam_vfe_top_blanking_update(cmd_type, cmd_args, arg_size);
 		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:
 		rc = -EINVAL;
 		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;
-	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) {
 		CAM_ERR(CAM_ISP, "Invalid number of input rsrc: %d, max: %d",
 			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_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
@@ -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;
 
 	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) {
 			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;
 		}
 
-		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) {
 			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;
 		}
 
@@ -614,7 +615,7 @@ int cam_vfe_top_ver3_stop(void *device_priv,
 				memset(&top_priv->top_common.req_axi_vote[i],
 					0, sizeof(struct cam_axi_vote));
 				top_priv->top_common.axi_vote_control[i] =
-					CAM_VFE_BW_CONTROL_EXCLUDE;
+					CAM_ISP_BW_CONTROL_EXCLUDE;
 				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,
 			arg_size);
 		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:
 		rc = -EINVAL;
 		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;
-	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) {
 		CAM_ERR(CAM_ISP, "Invalid number of input rsrc: %d, max: %d",
 			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_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
@@ -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;
 
 	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) {
 			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;
 		}
 
-		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) {
 			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;
 		}
 
@@ -1380,7 +1381,7 @@ int cam_vfe_top_ver4_stop(void *device_priv,
 				memset(&top_priv->top_common.req_axi_vote[i],
 					0, sizeof(struct cam_axi_vote));
 				top_priv->top_common.axi_vote_control[i] =
-					CAM_VFE_BW_CONTROL_EXCLUDE;
+					CAM_ISP_BW_CONTROL_EXCLUDE;
 				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,
 			arg_size);
 		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:
 		rc = -EINVAL;
 		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;
-	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) {
 		CAM_ERR(CAM_ISP, "Invalid number of input rsrc: %d, max: %d",