Browse Source

Merge "msm: camera: isp: Add support for BW limiter" into camera-kernel.lnx.5.0

Camera Software Integration 4 years ago
parent
commit
80f937e481

+ 207 - 0
drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c

@@ -8035,6 +8035,161 @@ static int cam_isp_blob_sensor_blanking_config(
 	return rc;
 }
 
+static int cam_isp_blob_bw_limit_update(
+	uint32_t                                   blob_type,
+	struct cam_isp_generic_blob_info          *blob_info,
+	struct cam_isp_out_rsrc_bw_limiter_config *bw_limit_cfg,
+	struct cam_hw_prepare_update_args         *prepare,
+	enum cam_isp_hw_type                       hw_type)
+{
+	struct cam_isp_wm_bw_limiter_config   *wm_bw_limit_cfg;
+	struct cam_kmd_buf_info               *kmd_buf_info;
+	struct cam_ife_hw_mgr_ctx             *ctx = NULL;
+	struct cam_isp_hw_mgr_res             *isp_out_res;
+	uint32_t                               res_id_out, i;
+	uint32_t                               total_used_bytes = 0;
+	uint32_t                               kmd_buf_remain_size;
+	uint32_t                              *cmd_buf_addr;
+	uint32_t                               bytes_used = 0;
+	int                                    num_ent, rc = 0;
+
+	ctx = prepare->ctxt_to_hw_map;
+
+	if ((prepare->num_hw_update_entries + 1) >=
+			prepare->max_hw_update_entries) {
+		CAM_ERR(CAM_ISP, "Insufficient HW entries: %d max: %d",
+			prepare->num_hw_update_entries,
+			prepare->max_hw_update_entries);
+		return -EINVAL;
+	}
+
+	kmd_buf_info = blob_info->kmd_buf_info;
+	for (i = 0; i < bw_limit_cfg->num_ports; i++) {
+		wm_bw_limit_cfg = &bw_limit_cfg->bw_limiter_config[i];
+		res_id_out = wm_bw_limit_cfg->res_type & 0xFF;
+
+		if ((hw_type == CAM_ISP_HW_TYPE_SFE) &&
+			!((wm_bw_limit_cfg->res_type >=
+			CAM_ISP_SFE_OUT_RES_BASE) &&
+			(wm_bw_limit_cfg->res_type <
+			CAM_ISP_SFE_OUT_RES_MAX)))
+			continue;
+
+		if ((hw_type == CAM_ISP_HW_TYPE_VFE) &&
+			!((wm_bw_limit_cfg->res_type >=
+			CAM_ISP_IFE_OUT_RES_BASE) &&
+			(wm_bw_limit_cfg->res_type <
+			(CAM_ISP_IFE_OUT_RES_BASE + max_ife_out_res))))
+			continue;
+
+		CAM_DBG(CAM_ISP, "%s BW limit config idx: %d port: 0x%x enable: %d [0x%x:0x%x]",
+			(hw_type == CAM_ISP_HW_TYPE_SFE ? "SFE" : "VFE"),
+			i, wm_bw_limit_cfg->res_type,
+			wm_bw_limit_cfg->enable_limiter,
+			wm_bw_limit_cfg->counter_limit[0],
+			wm_bw_limit_cfg->counter_limit[1]);
+
+		if ((kmd_buf_info->used_bytes
+			+ total_used_bytes) < kmd_buf_info->size) {
+			kmd_buf_remain_size = kmd_buf_info->size -
+			(kmd_buf_info->used_bytes +
+			total_used_bytes);
+		} else {
+			CAM_ERR(CAM_ISP,
+				"No free kmd memory for base idx: %d",
+				blob_info->base_info->idx);
+			rc = -ENOMEM;
+			return rc;
+		}
+
+		cmd_buf_addr = kmd_buf_info->cpu_addr +
+			(kmd_buf_info->used_bytes / 4) +
+			(total_used_bytes / 4);
+
+		if (hw_type == CAM_ISP_HW_TYPE_SFE)
+			isp_out_res = &ctx->res_list_sfe_out[res_id_out];
+		else
+			isp_out_res = &ctx->res_list_ife_out[res_id_out];
+
+		rc = cam_isp_add_cmd_buf_update(
+			isp_out_res, blob_type,
+			CAM_ISP_HW_CMD_WM_BW_LIMIT_CONFIG,
+			blob_info->base_info->idx,
+			(void *)cmd_buf_addr,
+			kmd_buf_remain_size,
+			(void *)wm_bw_limit_cfg,
+			&bytes_used);
+		if (rc < 0) {
+			CAM_ERR(CAM_ISP,
+				"Failed to update %s BW limiter config for res:0x%x enable:%d [0x%x:0x%x] base_idx:%d bytes_used:%u rc:%d",
+				((hw_type == CAM_ISP_HW_TYPE_SFE) ?
+				"SFE" : "VFE"),
+				wm_bw_limit_cfg->res_type,
+				wm_bw_limit_cfg->enable_limiter,
+				wm_bw_limit_cfg->counter_limit[0],
+				wm_bw_limit_cfg->counter_limit[1],
+				blob_info->base_info->idx, bytes_used, rc);
+			return rc;
+		}
+
+		total_used_bytes += bytes_used;
+	}
+
+	if (total_used_bytes) {
+		num_ent = prepare->num_hw_update_entries;
+		prepare->hw_update_entries[num_ent].handle =
+			kmd_buf_info->handle;
+		prepare->hw_update_entries[num_ent].len = total_used_bytes;
+		prepare->hw_update_entries[num_ent].offset =
+			kmd_buf_info->offset;
+		num_ent++;
+		kmd_buf_info->used_bytes += total_used_bytes;
+		kmd_buf_info->offset     += total_used_bytes;
+		prepare->num_hw_update_entries = num_ent;
+	}
+
+	return rc;
+}
+
+static inline int cam_isp_validate_bw_limiter_blob(
+	uint32_t blob_size,
+	struct cam_isp_out_rsrc_bw_limiter_config *bw_limit_config)
+{
+	if ((bw_limit_config->num_ports >  (max_ife_out_res +
+		g_ife_hw_mgr.isp_bus_caps.max_sfe_out_res_type)) ||
+		(bw_limit_config->num_ports == 0)) {
+		CAM_ERR(CAM_ISP,
+			"Invalid num_ports:%u in bw limit config",
+			bw_limit_config->num_ports);
+			return -EINVAL;
+	}
+
+	/* Check for integer overflow */
+	if (bw_limit_config->num_ports != 1) {
+		if (sizeof(struct cam_isp_wm_bw_limiter_config) > ((UINT_MAX -
+			sizeof(struct cam_isp_out_rsrc_bw_limiter_config)) /
+			(bw_limit_config->num_ports - 1))) {
+			CAM_ERR(CAM_ISP,
+				"Max size exceeded in bw limit config num_ports:%u size per port:%lu",
+				bw_limit_config->num_ports,
+				sizeof(struct cam_isp_wm_bw_limiter_config));
+			return -EINVAL;
+		}
+	}
+
+	if (blob_size < (sizeof(struct cam_isp_out_rsrc_bw_limiter_config) +
+		(bw_limit_config->num_ports - 1) *
+		sizeof(struct cam_isp_wm_bw_limiter_config))) {
+		CAM_ERR(CAM_ISP, "Invalid blob size %u expected %lu",
+			blob_size, sizeof(struct cam_isp_out_rsrc_bw_limiter_config)
+			+ (bw_limit_config->num_ports - 1) *
+			sizeof(struct cam_isp_wm_bw_limiter_config));
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int cam_isp_packet_generic_blob_handler(void *user_data,
 	uint32_t blob_type, uint32_t blob_size, uint8_t *blob_data)
 {
@@ -8586,6 +8741,32 @@ static int cam_isp_packet_generic_blob_handler(void *user_data,
 			CAM_ERR(CAM_ISP, "MUP Update Failed");
 	}
 		break;
+	case CAM_ISP_GENERIC_BLOB_TYPE_BW_LIMITER_CFG: {
+		struct cam_isp_out_rsrc_bw_limiter_config *bw_limit_config;
+
+		if (blob_size <
+			sizeof(struct cam_isp_out_rsrc_bw_limiter_config)) {
+			CAM_ERR(CAM_ISP, "Invalid blob size %u",
+				blob_size,
+				sizeof(struct cam_isp_out_rsrc_bw_limiter_config));
+			return -EINVAL;
+		}
+
+		bw_limit_config =
+			(struct cam_isp_out_rsrc_bw_limiter_config *)blob_data;
+
+		rc = cam_isp_validate_bw_limiter_blob(blob_size,
+			bw_limit_config);
+		if (rc)
+			return rc;
+
+		rc = cam_isp_blob_bw_limit_update(blob_type, blob_info,
+			bw_limit_config, prepare, CAM_ISP_HW_TYPE_VFE);
+		if (rc)
+			CAM_ERR(CAM_ISP,
+				"BW limit update failed for IFE rc: %d", rc);
+	}
+		break;
 	default:
 		CAM_WARN(CAM_ISP, "Invalid blob type %d", blob_type);
 		break;
@@ -8984,6 +9165,32 @@ static int cam_sfe_packet_generic_blob_handler(void *user_data,
 			CAM_ERR(CAM_ISP, "SFE exp order update failed");
 	}
 		break;
+	case CAM_ISP_GENERIC_BLOB_TYPE_BW_LIMITER_CFG: {
+		struct cam_isp_out_rsrc_bw_limiter_config *bw_limit_config;
+
+		if (blob_size <
+			sizeof(struct cam_isp_out_rsrc_bw_limiter_config)) {
+			CAM_ERR(CAM_ISP, "Invalid blob size %u",
+				blob_size,
+				sizeof(struct cam_isp_out_rsrc_bw_limiter_config));
+			return -EINVAL;
+		}
+
+		bw_limit_config =
+			(struct cam_isp_out_rsrc_bw_limiter_config *)blob_data;
+
+		rc = cam_isp_validate_bw_limiter_blob(blob_size,
+			bw_limit_config);
+		if (rc)
+			return rc;
+
+		rc = cam_isp_blob_bw_limit_update(blob_type, blob_info,
+			bw_limit_config, prepare, CAM_ISP_HW_TYPE_SFE);
+		if (rc)
+			CAM_ERR(CAM_ISP,
+				"BW limit update failed for SFE rc: %d", rc);
+	}
+		break;
 	case CAM_ISP_GENERIC_BLOB_TYPE_HFR_CONFIG:
 	case CAM_ISP_GENERIC_BLOB_TYPE_CLOCK_CONFIG:
 	case CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG:

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

@@ -160,6 +160,7 @@ enum cam_isp_hw_cmd_type {
 	CAM_ISP_HW_CMD_IFE_BUS_DEBUG_CFG,
 	CAM_ISP_HW_SFE_SYS_CACHE_WM_CONFIG,
 	CAM_ISP_HW_SFE_SYS_CACHE_RM_CONFIG,
+	CAM_ISP_HW_CMD_WM_BW_LIMIT_CONFIG,
 	CAM_ISP_HW_CMD_MAX,
 };
 

+ 18 - 4
drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe680.h

@@ -425,6 +425,7 @@ static struct cam_sfe_bus_wr_hw_info sfe680_bus_wr_hw_info = {
 			.debug_status_1           = 0x00000A88,
 			.mmu_prefetch_cfg         = 0x00000A60,
 			.mmu_prefetch_max_offset  = 0x00000A64,
+			.bw_limiter_addr          = 0x00000A1C,
 			.comp_group               = CAM_SFE_BUS_WR_COMP_GRP_0,
 		},
 		/* BUS Client 1 LCR */
@@ -454,6 +455,7 @@ static struct cam_sfe_bus_wr_hw_info sfe680_bus_wr_hw_info = {
 			.debug_status_1           = 0x00000B88,
 			.mmu_prefetch_cfg         = 0x00000B60,
 			.mmu_prefetch_max_offset  = 0x00000B64,
+			.bw_limiter_addr          = 0x00000B1C,
 			.comp_group               = CAM_SFE_BUS_WR_COMP_GRP_1,
 		},
 		/* BUS Client 2 STATS_BE_0 */
@@ -483,6 +485,7 @@ static struct cam_sfe_bus_wr_hw_info sfe680_bus_wr_hw_info = {
 			.debug_status_1           = 0x00000C88,
 			.mmu_prefetch_cfg         = 0x00000C60,
 			.mmu_prefetch_max_offset  = 0x00000C64,
+			.bw_limiter_addr          = 0x00000C1C,
 			.comp_group               = CAM_SFE_BUS_WR_COMP_GRP_2,
 		},
 		/* BUS Client 3 STATS_BHIST_0 */
@@ -512,6 +515,7 @@ static struct cam_sfe_bus_wr_hw_info sfe680_bus_wr_hw_info = {
 			.debug_status_1           = 0x00000D88,
 			.mmu_prefetch_cfg         = 0x00000D60,
 			.mmu_prefetch_max_offset  = 0x00000D64,
+			.bw_limiter_addr          = 0x00000D1C,
 			.comp_group               = CAM_SFE_BUS_WR_COMP_GRP_2,
 		},
 		/* BUS Client 4 STATS_BE_1 */
@@ -541,6 +545,7 @@ static struct cam_sfe_bus_wr_hw_info sfe680_bus_wr_hw_info = {
 			.debug_status_1           = 0x00000E88,
 			.mmu_prefetch_cfg         = 0x00000E60,
 			.mmu_prefetch_max_offset  = 0x00000E64,
+			.bw_limiter_addr          = 0x00000E1C,
 			.comp_group               = CAM_SFE_BUS_WR_COMP_GRP_3,
 		},
 		/* BUS Client 5 STATS_BHIST_1 */
@@ -570,6 +575,7 @@ static struct cam_sfe_bus_wr_hw_info sfe680_bus_wr_hw_info = {
 			.debug_status_1           = 0x00000F88,
 			.mmu_prefetch_cfg         = 0x00000F60,
 			.mmu_prefetch_max_offset  = 0x00000F64,
+			.bw_limiter_addr          = 0x00000F1C,
 			.comp_group               = CAM_SFE_BUS_WR_COMP_GRP_3,
 		},
 		/* BUS Client 6 STATS_BE_2 */
@@ -599,6 +605,7 @@ static struct cam_sfe_bus_wr_hw_info sfe680_bus_wr_hw_info = {
 			.debug_status_1           = 0x00001088,
 			.mmu_prefetch_cfg         = 0x00001060,
 			.mmu_prefetch_max_offset  = 0x00001064,
+			.bw_limiter_addr          = 0x0000101C,
 			.comp_group               = CAM_SFE_BUS_WR_COMP_GRP_4,
 		},
 		/* BUS Client 7 STATS_BHIST_2 */
@@ -628,6 +635,7 @@ static struct cam_sfe_bus_wr_hw_info sfe680_bus_wr_hw_info = {
 			.debug_status_1           = 0x00001188,
 			.mmu_prefetch_cfg         = 0x00001160,
 			.mmu_prefetch_max_offset  = 0x00001164,
+			.bw_limiter_addr          = 0x0000111C,
 			.comp_group               = CAM_SFE_BUS_WR_COMP_GRP_4,
 		},
 		/* BUS Client 8 RDI0 */
@@ -657,6 +665,7 @@ static struct cam_sfe_bus_wr_hw_info sfe680_bus_wr_hw_info = {
 			.debug_status_1           = 0x00001288,
 			.mmu_prefetch_cfg         = 0x00001260,
 			.mmu_prefetch_max_offset  = 0x00001264,
+			.bw_limiter_addr          = 0x0000121C,
 			.comp_group               = CAM_SFE_BUS_WR_COMP_GRP_5,
 		},
 		/* BUS Client 9 RDI1 */
@@ -686,6 +695,7 @@ static struct cam_sfe_bus_wr_hw_info sfe680_bus_wr_hw_info = {
 			.debug_status_1           = 0x00001388,
 			.mmu_prefetch_cfg         = 0x00001360,
 			.mmu_prefetch_max_offset  = 0x00001364,
+			.bw_limiter_addr          = 0x0000131C,
 			.comp_group               = CAM_SFE_BUS_WR_COMP_GRP_6,
 		},
 		/* BUS Client 10 RDI2 */
@@ -715,6 +725,7 @@ static struct cam_sfe_bus_wr_hw_info sfe680_bus_wr_hw_info = {
 			.debug_status_1           = 0x00001488,
 			.mmu_prefetch_cfg         = 0x00001460,
 			.mmu_prefetch_max_offset  = 0x00001464,
+			.bw_limiter_addr          = 0x0000141C,
 			.comp_group               = CAM_SFE_BUS_WR_COMP_GRP_7,
 		},
 		/* BUS Client 11 RDI3 */
@@ -744,6 +755,7 @@ static struct cam_sfe_bus_wr_hw_info sfe680_bus_wr_hw_info = {
 			.debug_status_1           = 0x00001588,
 			.mmu_prefetch_cfg         = 0x00001560,
 			.mmu_prefetch_max_offset  = 0x00001564,
+			.bw_limiter_addr          = 0x0000151C,
 			.comp_group               = CAM_SFE_BUS_WR_COMP_GRP_8,
 		},
 		/* BUS Client 12 RDI4 */
@@ -773,6 +785,7 @@ static struct cam_sfe_bus_wr_hw_info sfe680_bus_wr_hw_info = {
 			.debug_status_1           = 0x00001688,
 			.mmu_prefetch_cfg         = 0x00001660,
 			.mmu_prefetch_max_offset  = 0x00001664,
+			.bw_limiter_addr          = 0x0000161C,
 			.comp_group               = CAM_SFE_BUS_WR_COMP_GRP_9,
 		},
 	},
@@ -980,10 +993,11 @@ static struct cam_sfe_bus_wr_hw_info sfe680_bus_wr_hw_info = {
 			.error_description = "Meta Stride unalign"
 		},
 	},
-	.num_comp_grp    = 10,
-	.comp_done_shift = 17,
-	.line_done_cfg   = 0x11,
-	.top_irq_shift   = 0x0,
+	.num_comp_grp         = 10,
+	.comp_done_shift      = 17,
+	.line_done_cfg        = 0x11,
+	.top_irq_shift        = 0x0,
+	.max_bw_counter_limit = 0xFF,
 };
 
 static struct cam_irq_register_set sfe680_top_irq_reg_set[1] = {

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

@@ -335,6 +335,7 @@ int cam_sfe_process_cmd(void *hw_priv, uint32_t cmd_type,
 	case CAM_ISP_HW_CMD_GET_SECURE_MODE:
 	case CAM_ISP_HW_CMD_QUERY_BUS_CAP:
 	case CAM_ISP_HW_SFE_SYS_CACHE_WM_CONFIG:
+	case CAM_ISP_HW_CMD_WM_BW_LIMIT_CONFIG:
 		rc = core_info->sfe_bus_wr->hw_ops.process_cmd(
 			core_info->sfe_bus_wr->bus_priv, cmd_type,
 			cmd_args, arg_size);

+ 132 - 14
drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_wr.c

@@ -89,6 +89,7 @@ struct cam_sfe_bus_wr_common_data {
 	uint32_t                                    addr_no_sync;
 	uint32_t                                    comp_done_shift;
 	uint32_t                                    line_done_cfg;
+	uint32_t                                    max_bw_counter_limit;
 	bool                                        err_irq_subscribe;
 	cam_hw_mgr_event_cb_func                    event_cb;
 
@@ -2626,6 +2627,119 @@ static int cam_sfe_bus_wr_update_wm_config(
 	return 0;
 }
 
+static int cam_sfe_bus_wr_update_bw_limiter(
+	void *priv, void *cmd_args, uint32_t arg_size)
+{
+	struct cam_sfe_bus_wr_priv             *bus_priv;
+	struct cam_isp_hw_get_cmd_update       *wm_config_update;
+	struct cam_sfe_bus_wr_out_data         *sfe_out_data = NULL;
+	struct cam_cdm_utils_ops               *cdm_util_ops;
+	struct cam_sfe_bus_wr_wm_resource_data *wm_data = NULL;
+	struct cam_isp_wm_bw_limiter_config    *wm_bw_limit_cfg = NULL;
+	uint32_t                                counter_limit = 0, reg_val = 0;
+	uint32_t                               *reg_val_pair, num_regval_pairs = 0;
+	uint32_t                                i, j, size = 0;
+
+	bus_priv         = (struct cam_sfe_bus_wr_priv  *) priv;
+	wm_config_update = (struct cam_isp_hw_get_cmd_update *) cmd_args;
+	wm_bw_limit_cfg  = (struct cam_isp_wm_bw_limiter_config  *)
+			wm_config_update->data;
+
+	sfe_out_data = (struct cam_sfe_bus_wr_out_data *)
+		wm_config_update->res->res_priv;
+
+	cdm_util_ops = sfe_out_data->cdm_util_ops;
+
+	if (!sfe_out_data || !cdm_util_ops) {
+		CAM_ERR(CAM_SFE,
+			"Failed invalid data out_data: %pK cdm_utils_ops: %pK",
+			sfe_out_data, cdm_util_ops);
+		return -EINVAL;
+	}
+
+	reg_val_pair = &sfe_out_data->common_data->io_buf_update[0];
+	for (i = 0, j = 0; i < sfe_out_data->num_wm; i++) {
+		if (j >= (MAX_REG_VAL_PAIR_SIZE - (MAX_BUF_UPDATE_REG_NUM * 2))) {
+			CAM_ERR(CAM_SFE,
+				"reg_val_pair %d exceeds the array limit %zu for WM idx %d",
+				j, MAX_REG_VAL_PAIR_SIZE, i);
+			return -ENOMEM;
+		}
+
+		/* Num WMs needs to match max planes */
+		if (i >= CAM_PACKET_MAX_PLANES) {
+			CAM_WARN(CAM_SFE,
+				"Num of WMs: %d exceeded max planes", i);
+			goto add_reg_pair;
+		}
+
+		wm_data = (struct cam_sfe_bus_wr_wm_resource_data *)
+			sfe_out_data->wm_res[i].res_priv;
+		if (!wm_data->hw_regs->bw_limiter_addr) {
+			CAM_ERR(CAM_SFE,
+				"WM: %d %s has no support for bw limiter",
+				wm_data->index, sfe_out_data->wm_res[i].res_name);
+			return -EINVAL;
+		}
+
+		counter_limit = wm_bw_limit_cfg->counter_limit[i];
+
+		/* Validate max counter limit */
+		if (counter_limit >
+			wm_data->common_data->max_bw_counter_limit) {
+			CAM_WARN(CAM_SFE,
+				"Invalid counter limit: 0x%x capping to max: 0x%x",
+				wm_bw_limit_cfg->counter_limit[i],
+				wm_data->common_data->max_bw_counter_limit);
+			counter_limit = wm_data->common_data->max_bw_counter_limit;
+		}
+
+		if (wm_bw_limit_cfg->enable_limiter && counter_limit) {
+			reg_val = 1;
+			reg_val |= (counter_limit << 1);
+		} else {
+			reg_val = 0;
+		}
+
+		CAM_SFE_ADD_REG_VAL_PAIR(reg_val_pair, j,
+			wm_data->hw_regs->bw_limiter_addr, reg_val);
+		CAM_DBG(CAM_SFE, "WM: %d %s bw_limter: 0x%x",
+			wm_data->index, sfe_out_data->wm_res[i].res_name,
+			reg_val_pair[j-1]);
+	}
+
+add_reg_pair:
+
+	num_regval_pairs = j / 2;
+
+	if (num_regval_pairs) {
+		size = cdm_util_ops->cdm_required_size_reg_random(
+			num_regval_pairs);
+
+		/* cdm util returns dwords, need to convert to bytes */
+		if ((size * 4) > wm_config_update->cmd.size) {
+			CAM_ERR(CAM_SFE,
+				"Failed! Buf size:%d insufficient, expected size:%d",
+				wm_config_update->cmd.size, size);
+			return -ENOMEM;
+		}
+
+		cdm_util_ops->cdm_write_regrandom(
+			wm_config_update->cmd.cmd_buf_addr, num_regval_pairs,
+			reg_val_pair);
+
+		/* cdm util returns dwords, need to convert to bytes */
+		wm_config_update->cmd.used_bytes = size * 4;
+	} else {
+		CAM_DBG(CAM_SFE,
+			"No reg val pairs. num_wms: %u",
+			sfe_out_data->num_wm);
+		wm_config_update->cmd.used_bytes = 0;
+	}
+
+	return 0;
+}
+
 static int cam_sfe_bus_wr_start_hw(void *hw_priv,
 	void *start_hw_args, uint32_t arg_size)
 {
@@ -2783,6 +2897,9 @@ static int cam_sfe_bus_wr_process_cmd(
 	case CAM_ISP_HW_CMD_SET_SFE_DEBUG_CFG:
 		rc = cam_sfe_bus_wr_set_debug_cfg(priv, cmd_args);
 		break;
+	case CAM_ISP_HW_CMD_WM_BW_LIMIT_CONFIG:
+		rc = cam_sfe_bus_wr_update_bw_limiter(priv, cmd_args, arg_size);
+		break;
 	default:
 		CAM_ERR_RATE_LIMIT(CAM_SFE, "Invalid HW command type:%d",
 			cmd_type);
@@ -2832,21 +2949,22 @@ int cam_sfe_bus_wr_init(
 	}
 	sfe_bus_local->bus_priv = bus_priv;
 
-	bus_priv->num_client                     = hw_info->num_client;
-	bus_priv->num_out                        = hw_info->num_out;
-	bus_priv->num_comp_grp                   = hw_info->num_comp_grp;
-	bus_priv->top_irq_shift                  = hw_info->top_irq_shift;
-	bus_priv->common_data.num_sec_out        = 0;
-	bus_priv->common_data.secure_mode        = CAM_SECURE_MODE_NON_SECURE;
-	bus_priv->common_data.core_index         = soc_info->index;
-	bus_priv->common_data.mem_base           =
+	bus_priv->num_client                       = hw_info->num_client;
+	bus_priv->num_out                          = hw_info->num_out;
+	bus_priv->num_comp_grp                     = hw_info->num_comp_grp;
+	bus_priv->top_irq_shift                    = hw_info->top_irq_shift;
+	bus_priv->common_data.num_sec_out          = 0;
+	bus_priv->common_data.secure_mode          = CAM_SECURE_MODE_NON_SECURE;
+	bus_priv->common_data.core_index           = soc_info->index;
+	bus_priv->common_data.mem_base             =
 		CAM_SOC_GET_REG_MAP_START(soc_info, SFE_CORE_BASE_IDX);
-	bus_priv->common_data.hw_intf            = hw_intf;
-	bus_priv->common_data.common_reg         = &hw_info->common_reg;
-	bus_priv->common_data.comp_done_shift    = hw_info->comp_done_shift;
-	bus_priv->common_data.line_done_cfg      = hw_info->line_done_cfg;
-	bus_priv->common_data.err_irq_subscribe  = false;
-	bus_priv->common_data.sfe_irq_controller = sfe_irq_controller;
+	bus_priv->common_data.hw_intf              = hw_intf;
+	bus_priv->common_data.common_reg           = &hw_info->common_reg;
+	bus_priv->common_data.comp_done_shift      = hw_info->comp_done_shift;
+	bus_priv->common_data.line_done_cfg        = hw_info->line_done_cfg;
+	bus_priv->common_data.max_bw_counter_limit = hw_info->max_bw_counter_limit;
+	bus_priv->common_data.err_irq_subscribe    = false;
+	bus_priv->common_data.sfe_irq_controller   = sfe_irq_controller;
 	bus_priv->constraint_error_list = hw_info->constraint_error_list;
 	rc = cam_cpas_get_cpas_hw_version(&bus_priv->common_data.hw_version);
 	if (rc) {

+ 11 - 8
drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_wr.h

@@ -116,6 +116,7 @@ struct cam_sfe_bus_reg_offset_bus_client {
 	uint32_t debug_status_1;
 	uint32_t mmu_prefetch_cfg;
 	uint32_t mmu_prefetch_max_offset;
+	uint32_t bw_limiter_addr;
 	uint32_t comp_group;
 };
 
@@ -140,15 +141,16 @@ struct cam_sfe_bus_sfe_out_hw_info {
  *
  * @Brief:            HW register info for entire Bus
  *
- * @common_reg:       Common register details
- * @num_client:       Total number of write clients
- * @bus_client_reg:   Bus client register info
- * @sfe_out_hw_info:  SFE output capability
+ * @common_reg:            Common register details
+ * @num_client:            Total number of write clients
+ * @bus_client_reg:        Bus client register info
+ * @sfe_out_hw_info:       SFE output capability
  * @constraint_error_list: Static list of all constraint errors
- * @num_comp_grp:     Number of composite groups
- * @comp_done_shift:  Mask shift for comp done mask
- * @line_done_cfg:    Line done cfg for wr/rd sync
- * @top_irq_shift:    Mask shift for top level BUS WR irq
+ * @num_comp_grp:          Number of composite groups
+ * @comp_done_shift:       Mask shift for comp done mask
+ * @line_done_cfg:         Line done cfg for wr/rd sync
+ * @top_irq_shift:         Mask shift for top level BUS WR irq
+ * @max_bw_counter_limit:  Max BW counter limit
  */
 struct cam_sfe_bus_wr_hw_info {
 	struct cam_sfe_bus_reg_offset_common common_reg;
@@ -164,6 +166,7 @@ struct cam_sfe_bus_wr_hw_info {
 	uint32_t comp_done_shift;
 	uint32_t line_done_cfg;
 	uint32_t top_irq_shift;
+	uint32_t max_bw_counter_limit;
 };
 
 /*

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

@@ -532,6 +532,7 @@ int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type,
 	case CAM_ISP_HW_CMD_GET_RES_FOR_MID:
 	case CAM_ISP_HW_CMD_QUERY_BUS_CAP:
 	case CAM_ISP_HW_CMD_IFE_BUS_DEBUG_CFG:
+	case CAM_ISP_HW_CMD_WM_BW_LIMIT_CONFIG:
 		rc = core_info->vfe_bus->hw_ops.process_cmd(
 			core_info->vfe_bus->bus_priv, cmd_type, cmd_args,
 			arg_size);

+ 34 - 5
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe680.h

@@ -676,6 +676,7 @@ static struct cam_vfe_bus_ver3_hw_info vfe680_bus_hw_info = {
 			.debug_status_cfg         = 0x00000E80,
 			.debug_status_0           = 0x00000E84,
 			.debug_status_1           = 0x00000E88,
+			.bw_limiter_addr          = 0x00000E1C,
 			.comp_group               = CAM_VFE_BUS_VER3_COMP_GRP_0,
 			.ubwc_regs                = &vfe680_ubwc_regs_client_0,
 		},
@@ -705,6 +706,7 @@ static struct cam_vfe_bus_ver3_hw_info vfe680_bus_hw_info = {
 			.debug_status_cfg         = 0x00000F80,
 			.debug_status_0           = 0x00000F84,
 			.debug_status_1           = 0x00000F88,
+			.bw_limiter_addr          = 0x00000F1C,
 			.comp_group               = CAM_VFE_BUS_VER3_COMP_GRP_0,
 			.ubwc_regs                = &vfe680_ubwc_regs_client_1,
 		},
@@ -731,6 +733,7 @@ static struct cam_vfe_bus_ver3_hw_info vfe680_bus_hw_info = {
 			.debug_status_cfg         = 0x00001080,
 			.debug_status_0           = 0x00001084,
 			.debug_status_1           = 0x00001088,
+			.bw_limiter_addr          = 0x0000101C,
 			.comp_group               = CAM_VFE_BUS_VER3_COMP_GRP_0,
 			.ubwc_regs                = NULL,
 		},
@@ -757,6 +760,7 @@ static struct cam_vfe_bus_ver3_hw_info vfe680_bus_hw_info = {
 			.debug_status_cfg         = 0x00001180,
 			.debug_status_0           = 0x00001184,
 			.debug_status_1           = 0x00001188,
+			.bw_limiter_addr          = 0x0000111C,
 			.comp_group               = CAM_VFE_BUS_VER3_COMP_GRP_0,
 			.ubwc_regs                = NULL,
 		},
@@ -786,6 +790,7 @@ static struct cam_vfe_bus_ver3_hw_info vfe680_bus_hw_info = {
 			.debug_status_cfg         = 0x00001280,
 			.debug_status_0           = 0x00001284,
 			.debug_status_1           = 0x00001288,
+			.bw_limiter_addr          = 0x0000121C,
 			.comp_group               = CAM_VFE_BUS_VER3_COMP_GRP_1,
 			.ubwc_regs                = &vfe680_ubwc_regs_client_4,
 		},
@@ -815,6 +820,7 @@ static struct cam_vfe_bus_ver3_hw_info vfe680_bus_hw_info = {
 			.debug_status_cfg         = 0x00001380,
 			.debug_status_0           = 0x00001384,
 			.debug_status_1           = 0x00001388,
+			.bw_limiter_addr          = 0x0000131C,
 			.comp_group               = CAM_VFE_BUS_VER3_COMP_GRP_1,
 			.ubwc_regs                = &vfe680_ubwc_regs_client_5,
 		},
@@ -841,6 +847,7 @@ static struct cam_vfe_bus_ver3_hw_info vfe680_bus_hw_info = {
 			.debug_status_cfg         = 0x00001480,
 			.debug_status_0           = 0x00001484,
 			.debug_status_1           = 0x00001488,
+			.bw_limiter_addr          = 0x0000141C,
 			.comp_group               = CAM_VFE_BUS_VER3_COMP_GRP_1,
 			.ubwc_regs                = NULL,
 		},
@@ -867,6 +874,7 @@ static struct cam_vfe_bus_ver3_hw_info vfe680_bus_hw_info = {
 			.debug_status_cfg         = 0x00001580,
 			.debug_status_0           = 0x00001584,
 			.debug_status_1           = 0x00001588,
+			.bw_limiter_addr          = 0x0000151C,
 			.comp_group               = CAM_VFE_BUS_VER3_COMP_GRP_1,
 			.ubwc_regs                = NULL,
 		},
@@ -896,6 +904,7 @@ static struct cam_vfe_bus_ver3_hw_info vfe680_bus_hw_info = {
 			.debug_status_cfg         = 0x00001680,
 			.debug_status_0           = 0x00001684,
 			.debug_status_1           = 0x00001688,
+			.bw_limiter_addr          = 0x0000161C,
 			.comp_group               = CAM_VFE_BUS_VER3_COMP_GRP_2,
 			.ubwc_regs                = NULL,
 		},
@@ -922,6 +931,7 @@ static struct cam_vfe_bus_ver3_hw_info vfe680_bus_hw_info = {
 			.debug_status_cfg         = 0x00001780,
 			.debug_status_0           = 0x00001784,
 			.debug_status_1           = 0x00001788,
+			.bw_limiter_addr          = 0x0000171C,
 			.comp_group               = CAM_VFE_BUS_VER3_COMP_GRP_2,
 			.ubwc_regs                = NULL,
 		},
@@ -951,6 +961,7 @@ static struct cam_vfe_bus_ver3_hw_info vfe680_bus_hw_info = {
 			.debug_status_cfg         = 0x00001880,
 			.debug_status_0           = 0x00001884,
 			.debug_status_1           = 0x00001888,
+			.bw_limiter_addr          = 0x0000181C,
 			.comp_group               = CAM_VFE_BUS_VER3_COMP_GRP_3,
 			.ubwc_regs                = NULL,
 		},
@@ -980,6 +991,7 @@ static struct cam_vfe_bus_ver3_hw_info vfe680_bus_hw_info = {
 			.debug_status_cfg         = 0x00001980,
 			.debug_status_0           = 0x00001984,
 			.debug_status_1           = 0x00001988,
+			.bw_limiter_addr          = 0x0000191C,
 			.comp_group               = CAM_VFE_BUS_VER3_COMP_GRP_4,
 			.ubwc_regs                = NULL,
 		},
@@ -1009,6 +1021,7 @@ static struct cam_vfe_bus_ver3_hw_info vfe680_bus_hw_info = {
 			.debug_status_cfg         = 0x00001A80,
 			.debug_status_0           = 0x00001A84,
 			.debug_status_1           = 0x00001A88,
+			.bw_limiter_addr          = 0x00001A1C,
 			.comp_group               = CAM_VFE_BUS_VER3_COMP_GRP_4,
 			.ubwc_regs                = NULL,
 		},
@@ -1038,6 +1051,7 @@ static struct cam_vfe_bus_ver3_hw_info vfe680_bus_hw_info = {
 			.debug_status_cfg         = 0x00001B80,
 			.debug_status_0           = 0x00001B84,
 			.debug_status_1           = 0x00001B88,
+			.bw_limiter_addr          = 0x00001B1C,
 			.comp_group               = CAM_VFE_BUS_VER3_COMP_GRP_5,
 			.ubwc_regs                = NULL,
 		},
@@ -1067,6 +1081,7 @@ static struct cam_vfe_bus_ver3_hw_info vfe680_bus_hw_info = {
 			.debug_status_cfg         = 0x00001C80,
 			.debug_status_0           = 0x00001C84,
 			.debug_status_1           = 0x00001C88,
+			.bw_limiter_addr          = 0x00001C1C,
 			.comp_group               = CAM_VFE_BUS_VER3_COMP_GRP_6,
 			.ubwc_regs                = NULL,
 		},
@@ -1096,6 +1111,7 @@ static struct cam_vfe_bus_ver3_hw_info vfe680_bus_hw_info = {
 			.debug_status_cfg         = 0x00001D80,
 			.debug_status_0           = 0x00001D84,
 			.debug_status_1           = 0x00001D88,
+			.bw_limiter_addr          = 0x00001D1C,
 			.comp_group               = CAM_VFE_BUS_VER3_COMP_GRP_6,
 			.ubwc_regs                = NULL,
 		},
@@ -1125,6 +1141,7 @@ static struct cam_vfe_bus_ver3_hw_info vfe680_bus_hw_info = {
 			.debug_status_cfg         = 0x00001E80,
 			.debug_status_0           = 0x00001E84,
 			.debug_status_1           = 0x00001E88,
+			.bw_limiter_addr          = 0x00001E1C,
 			.comp_group               = CAM_VFE_BUS_VER3_COMP_GRP_7,
 			.ubwc_regs                = NULL,
 		},
@@ -1154,6 +1171,7 @@ static struct cam_vfe_bus_ver3_hw_info vfe680_bus_hw_info = {
 			.debug_status_cfg         = 0x00001F80,
 			.debug_status_0           = 0x00001F84,
 			.debug_status_1           = 0x00001F88,
+			.bw_limiter_addr          = 0x00001F1C,
 			.comp_group               = CAM_VFE_BUS_VER3_COMP_GRP_8,
 			.ubwc_regs                = NULL,
 		},
@@ -1183,6 +1201,7 @@ static struct cam_vfe_bus_ver3_hw_info vfe680_bus_hw_info = {
 			.debug_status_cfg         = 0x00002080,
 			.debug_status_0           = 0x00002084,
 			.debug_status_1           = 0x00002088,
+			.bw_limiter_addr          = 0x0000201C,
 			.comp_group               = CAM_VFE_BUS_VER3_COMP_GRP_9,
 			.ubwc_regs                = NULL,
 		},
@@ -1212,6 +1231,7 @@ static struct cam_vfe_bus_ver3_hw_info vfe680_bus_hw_info = {
 			.debug_status_cfg         = 0x00002180,
 			.debug_status_0           = 0x00002184,
 			.debug_status_1           = 0x00002188,
+			.bw_limiter_addr          = 0x0000211C,
 			.comp_group              = CAM_VFE_BUS_VER3_COMP_GRP_10,
 			.ubwc_regs                = NULL,
 		},
@@ -1241,6 +1261,7 @@ static struct cam_vfe_bus_ver3_hw_info vfe680_bus_hw_info = {
 			.debug_status_cfg         = 0x00002280,
 			.debug_status_0           = 0x00002284,
 			.debug_status_1           = 0x00002288,
+			.bw_limiter_addr          = 0x0000221C,
 			.comp_group              = CAM_VFE_BUS_VER3_COMP_GRP_12,
 			.ubwc_regs                = NULL,
 		},
@@ -1270,6 +1291,7 @@ static struct cam_vfe_bus_ver3_hw_info vfe680_bus_hw_info = {
 			.debug_status_cfg         = 0x00002380,
 			.debug_status_0           = 0x00002384,
 			.debug_status_1           = 0x00002388,
+			.bw_limiter_addr          = 0x0000231C,
 			.comp_group              = CAM_VFE_BUS_VER3_COMP_GRP_13,
 			.ubwc_regs                = NULL,
 		},
@@ -1299,6 +1321,7 @@ static struct cam_vfe_bus_ver3_hw_info vfe680_bus_hw_info = {
 			.debug_status_cfg         = 0x00002480,
 			.debug_status_0           = 0x00002484,
 			.debug_status_1           = 0x00002488,
+			.bw_limiter_addr          = 0x0000241C,
 			.comp_group              = CAM_VFE_BUS_VER3_COMP_GRP_13,
 			.ubwc_regs                = NULL,
 		},
@@ -1328,6 +1351,7 @@ static struct cam_vfe_bus_ver3_hw_info vfe680_bus_hw_info = {
 			.debug_status_cfg         = 0x00002580,
 			.debug_status_0           = 0x00002584,
 			.debug_status_1           = 0x00002588,
+			.bw_limiter_addr          = 0x0000251C,
 			.comp_group              = CAM_VFE_BUS_VER3_COMP_GRP_11,
 			.ubwc_regs                = NULL,
 		},
@@ -1357,6 +1381,7 @@ static struct cam_vfe_bus_ver3_hw_info vfe680_bus_hw_info = {
 			.debug_status_cfg         = 0x00002680,
 			.debug_status_0           = 0x00002684,
 			.debug_status_1           = 0x00002688,
+			.bw_limiter_addr          = 0x0000261C,
 			.comp_group              = CAM_VFE_BUS_VER3_COMP_GRP_14,
 			.ubwc_regs                = NULL,
 		},
@@ -1386,6 +1411,7 @@ static struct cam_vfe_bus_ver3_hw_info vfe680_bus_hw_info = {
 			.debug_status_cfg         = 0x00002780,
 			.debug_status_0           = 0x00002784,
 			.debug_status_1           = 0x00002788,
+			.bw_limiter_addr          = 0x0000271C,
 			.comp_group              = CAM_VFE_BUS_VER3_COMP_GRP_15,
 			.ubwc_regs                = NULL,
 		},
@@ -1415,6 +1441,7 @@ static struct cam_vfe_bus_ver3_hw_info vfe680_bus_hw_info = {
 			.debug_status_cfg         = 0x00002880,
 			.debug_status_0           = 0x00002884,
 			.debug_status_1           = 0x00002888,
+			.bw_limiter_addr          = 0x0000281C,
 			.comp_group              = CAM_VFE_BUS_VER3_COMP_GRP_16,
 			.ubwc_regs                = NULL,
 		},
@@ -1444,6 +1471,7 @@ static struct cam_vfe_bus_ver3_hw_info vfe680_bus_hw_info = {
 			.debug_status_cfg         = 0x00002980,
 			.debug_status_0           = 0x00002984,
 			.debug_status_1           = 0x00002988,
+			.bw_limiter_addr          = 0x0000291C,
 			.comp_group              = CAM_VFE_BUS_VER3_COMP_GRP_3,
 			.ubwc_regs                = NULL,
 		},
@@ -1909,12 +1937,13 @@ static struct cam_vfe_bus_ver3_hw_info vfe680_bus_hw_info = {
 			.error_description = "Meta Stride unalign"
 		},
 	},
-	.num_comp_grp    = 17,
+	.num_comp_grp          = 17,
 	.support_consumed_addr = true,
-	.comp_done_shift = 0,
-	.top_irq_shift   = 1,
-	.max_out_res = CAM_ISP_IFE_OUT_RES_BASE + 33,
-	.pack_align_shift = 5,
+	.comp_done_shift       = 0,
+	.top_irq_shift         = 1,
+	.max_out_res           = CAM_ISP_IFE_OUT_RES_BASE + 33,
+	.pack_align_shift      = 5,
+	.max_bw_counter_limit  = 0xFF,
 };
 
 static struct cam_vfe_irq_hw_info vfe680_irq_hw_info = {

+ 125 - 1
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c

@@ -104,6 +104,7 @@ struct cam_vfe_bus_ver3_common_data {
 	cam_hw_mgr_event_cb_func                    event_cb;
 	int                        rup_irq_handle[CAM_VFE_BUS_VER3_SRC_GRP_MAX];
 	uint32_t                                    pack_align_shift;
+	uint32_t                                    max_bw_counter_limit;
 };
 
 struct cam_vfe_bus_ver3_wm_resource_data {
@@ -2948,7 +2949,11 @@ static int cam_vfe_bus_ver3_update_ubwc_regs(
 	CAM_DBG(CAM_ISP, "WM:%d off_lossy_var 0x%X",
 		wm_data->index, reg_val_pair[*j-1]);
 
-	if (wm_data->ubwc_bandwidth_limit) {
+	/*
+	 * If limit value >= 0xFFFF, limit configured by
+	 * generic limiter blob
+	 */
+	if (wm_data->ubwc_bandwidth_limit < 0xFFFF) {
 		CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j,
 			ubwc_regs->bw_limit, wm_data->ubwc_bandwidth_limit);
 		CAM_DBG(CAM_ISP, "WM:%d ubwc bw limit 0x%X",
@@ -3540,6 +3545,120 @@ static int cam_vfe_bus_ver3_update_wm_config(
 	return 0;
 }
 
+static int cam_vfe_bus_update_bw_limiter(
+	void *priv, void *cmd_args, uint32_t arg_size)
+{
+	struct cam_vfe_bus_ver3_priv             *bus_priv;
+	struct cam_isp_hw_get_cmd_update         *wm_config_update;
+	struct cam_vfe_bus_ver3_vfe_out_data     *vfe_out_data = NULL;
+	struct cam_cdm_utils_ops                 *cdm_util_ops;
+	struct cam_vfe_bus_ver3_wm_resource_data *wm_data = NULL;
+	struct cam_isp_wm_bw_limiter_config      *wm_bw_limit_cfg = NULL;
+	uint32_t                                  counter_limit = 0, reg_val = 0;
+	uint32_t                                 *reg_val_pair, num_regval_pairs = 0;
+	uint32_t                                  i, j, size = 0;
+
+	bus_priv         = (struct cam_vfe_bus_ver3_priv  *) priv;
+	wm_config_update = (struct cam_isp_hw_get_cmd_update *) cmd_args;
+	wm_bw_limit_cfg  = (struct cam_isp_wm_bw_limiter_config  *)
+			wm_config_update->data;
+
+	vfe_out_data = (struct cam_vfe_bus_ver3_vfe_out_data *)
+		wm_config_update->res->res_priv;
+
+	cdm_util_ops = vfe_out_data->cdm_util_ops;
+
+	if (!vfe_out_data || !cdm_util_ops) {
+		CAM_ERR(CAM_ISP,
+			"Failed invalid data out_data: %pK cdm_utils_ops: %pK",
+			vfe_out_data, cdm_util_ops);
+		return -EINVAL;
+	}
+
+	reg_val_pair = &vfe_out_data->common_data->io_buf_update[0];
+	for (i = 0, j = 0; i < vfe_out_data->num_wm; i++) {
+		if (j >= (MAX_REG_VAL_PAIR_SIZE - (MAX_BUF_UPDATE_REG_NUM * 2))) {
+			CAM_ERR(CAM_ISP,
+				"reg_val_pair %d exceeds the array limit %zu for WM idx %d",
+				j, MAX_REG_VAL_PAIR_SIZE, i);
+			return -ENOMEM;
+		}
+
+		/* Num WMs needs to match max planes */
+		if (i >= CAM_PACKET_MAX_PLANES) {
+			CAM_WARN(CAM_ISP,
+				"Num of WMs: %d exceeded max planes", i);
+			goto add_reg_pair;
+		}
+
+		wm_data = (struct cam_vfe_bus_ver3_wm_resource_data *)
+			vfe_out_data->wm_res[i].res_priv;
+		if (!wm_data->hw_regs->bw_limiter_addr) {
+			CAM_ERR(CAM_ISP,
+				"WM: %d %s has no support for bw limiter",
+				wm_data->index, vfe_out_data->wm_res[i].res_name);
+			return -EINVAL;
+		}
+
+		counter_limit = wm_bw_limit_cfg->counter_limit[i];
+
+		/* Validate max counter limit */
+		if (counter_limit >
+			wm_data->common_data->max_bw_counter_limit) {
+			CAM_WARN(CAM_ISP,
+				"Invalid counter limit: 0x%x capping to max: 0x%x",
+				wm_bw_limit_cfg->counter_limit[i],
+				wm_data->common_data->max_bw_counter_limit);
+			counter_limit =
+				wm_data->common_data->max_bw_counter_limit;
+		}
+
+		if (wm_bw_limit_cfg->enable_limiter && counter_limit) {
+			reg_val = 1;
+			reg_val |= (counter_limit << 1);
+		} else {
+			reg_val = 0;
+		}
+
+		CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j,
+			wm_data->hw_regs->bw_limiter_addr, reg_val);
+		CAM_DBG(CAM_ISP, "WM: %d for %s bw_limter: 0x%x",
+			wm_data->index, vfe_out_data->wm_res[i].res_name,
+			reg_val_pair[j-1]);
+	}
+
+add_reg_pair:
+
+	num_regval_pairs = j / 2;
+
+	if (num_regval_pairs) {
+		size = cdm_util_ops->cdm_required_size_reg_random(
+			num_regval_pairs);
+
+		/* cdm util returns dwords, need to convert to bytes */
+		if ((size * 4) > wm_config_update->cmd.size) {
+			CAM_ERR(CAM_ISP,
+				"Failed! Buf size:%d insufficient, expected size:%d",
+				wm_config_update->cmd.size, size);
+			return -ENOMEM;
+		}
+
+		cdm_util_ops->cdm_write_regrandom(
+			wm_config_update->cmd.cmd_buf_addr, num_regval_pairs,
+			reg_val_pair);
+
+		/* cdm util returns dwords, need to convert to bytes */
+		wm_config_update->cmd.used_bytes = size * 4;
+	} else {
+		CAM_DBG(CAM_ISP,
+			"No reg val pairs. num_wms: %u",
+			vfe_out_data->num_wm);
+		wm_config_update->cmd.used_bytes = 0;
+	}
+
+	return 0;
+}
+
 static int cam_vfe_bus_ver3_start_hw(void *hw_priv,
 	void *start_hw_args, uint32_t arg_size)
 {
@@ -3739,6 +3858,9 @@ static int cam_vfe_bus_ver3_process_cmd(
 			"disabled" : "enabled");
 		rc = 0;
 		break;
+	case CAM_ISP_HW_CMD_WM_BW_LIMIT_CONFIG:
+		rc = cam_vfe_bus_update_bw_limiter(priv, cmd_args, arg_size);
+		break;
 	default:
 		CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid camif process command:%d",
 			cmd_type);
@@ -3823,6 +3945,8 @@ int cam_vfe_bus_ver3_init(
 	bus_priv->common_data.disable_mmu_prefetch = false;
 	bus_priv->common_data.pack_align_shift =
 		ver3_hw_info->pack_align_shift;
+	bus_priv->common_data.max_bw_counter_limit =
+		ver3_hw_info->max_bw_counter_limit;
 	bus_priv->constraint_error_list = ver3_hw_info->constraint_error_list;
 
 	if (bus_priv->num_out >= CAM_VFE_BUS_VER3_VFE_OUT_MAX) {

+ 3 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.h

@@ -174,6 +174,7 @@ struct cam_vfe_bus_ver3_reg_offset_bus_client {
 	uint32_t debug_status_cfg;
 	uint32_t debug_status_0;
 	uint32_t debug_status_1;
+	uint32_t bw_limiter_addr;
 	uint32_t comp_group;
 };
 
@@ -212,6 +213,7 @@ struct cam_vfe_bus_ver3_vfe_out_hw_info {
  * @supported_irq:         Mask to indicate the IRQ supported
  * @comp_cfg_needed:       Composite group config is needed for hw
  * @pack_align_shift:      Shift value for alignment of packer format
+ * @max_bw_counter_limit:  Max BW counter limit
  */
 struct cam_vfe_bus_ver3_hw_info {
 	struct cam_vfe_bus_ver3_reg_offset_common common_reg;
@@ -231,6 +233,7 @@ struct cam_vfe_bus_ver3_hw_info {
 	uint32_t supported_irq;
 	bool comp_cfg_needed;
 	uint32_t pack_align_shift;
+	uint32_t max_bw_counter_limit;
 };
 
 /*

+ 4 - 0
include/uapi/camera/media/cam_defs.h

@@ -333,6 +333,10 @@ struct cam_ubwc_plane_cfg_v1 {
  * @lossy_threshold0            UBWC lossy threshold 0
  * @lossy_threshold1            UBWC lossy threshold 1
  * @lossy_var_offset            UBWC offset variance thrshold
+ * @bandwidth_limit:            BW counter limit
+ *                              BW limiter config skipped if value is 0xFFFF or more
+ *                              If skipped here, use generic BW limiter blob to
+ *                              configure the appropriate value.
  *
  */
 struct cam_ubwc_plane_cfg_v2 {

+ 34 - 0
include/uapi/camera/media/cam_isp.h

@@ -121,6 +121,7 @@
 #define CAM_ISP_GENERIC_BLOB_TYPE_SENSOR_BLANKING_CONFIG    13
 #define CAM_ISP_GENERIC_BLOB_TYPE_TPG_CORE_CONFIG           14
 #define CAM_ISP_GENERIC_BLOB_TYPE_DYNAMIC_MODE_SWITCH       15
+#define CAM_ISP_GENERIC_BLOB_TYPE_BW_LIMITER_CFG            16
 #define CAM_ISP_GENERIC_BLOB_TYPE_SFE_CLOCK_CONFIG          21
 #define CAM_ISP_GENERIC_BLOB_TYPE_SFE_CORE_CONFIG           22
 #define CAM_ISP_GENERIC_BLOB_TYPE_SFE_OUT_CONFIG            23
@@ -932,6 +933,39 @@ struct cam_isp_discard_initial_frames {
 	__u32                    discard_params[5];
 } __attribute__((packed));
 
+/**
+ * struct cam_isp_wm_bw_limiter_config - ISP write master
+ *                                       BW limter config
+ *
+ *
+ * @res_type          : output resource type defined in file
+ *                      cam_isp_sfe.h or cam_isp_ife.h
+ * @enable_limiter    : 0 for disable else enabled
+ * @counter_limit     : Max counter value
+ * @additional_params : Params for future use
+ */
+struct cam_isp_wm_bw_limiter_config {
+	__u32         res_type;
+	__u32         enable_limiter;
+	__u32         counter_limit[CAM_PACKET_MAX_PLANES];
+	__u32         additional_params[5];
+};
+
+/**
+ * struct cam_isp_out_rsrc_bw_limiter_config - ISP out rsrc BW limiter config
+ *
+ *    Configure BW limiter for ISP WMs
+ *
+ * @num_ports        : Number of ports
+ * @reserved         : Reserved field
+ * @bw_limit_config  : WM BW limiter config
+ */
+struct cam_isp_out_rsrc_bw_limiter_config {
+	__u32                                   num_ports;
+	__u32                                   reserved;
+	struct cam_isp_wm_bw_limiter_config     bw_limiter_config[1];
+};
+
 #define CAM_ISP_ACQUIRE_COMMON_VER0         0x1000
 
 #define CAM_ISP_ACQUIRE_COMMON_SIZE_VER0    0x0