msm: vidc: Update operating rate handling

Validate incoming operating rate setting and
consider special value of operating rate indicating
client's intention to set turbo mode. Vote for the
highest frequency if one of the instance sets
operating rate as INT_MAX.

Change-Id: I4803ed419cee0e327d96b81d7bf372cee82a2e8d
Signed-off-by: Saurabh Kothawade <skothawa@codeaurora.org>
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index aa20a07..62b1bec 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -413,7 +413,16 @@
 		.minimum = 0,
 		.maximum = INT_MAX,
 		.default_value = 0,
-		.step = OPERATING_FRAME_RATE_STEP,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE,
+		.name = "Set Decoder Frame rate",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = INT_MAX,
+		.default_value = 0,
+		.step = 1,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_MODE,
@@ -1107,11 +1116,27 @@
 		}
 		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE:
-		dprintk(VIDC_DBG,
-			"inst(%pK) operating rate changed from %d to %d\n",
-			inst, inst->clk_data.operating_rate >> 16,
-				ctrl->val >> 16);
-		inst->clk_data.operating_rate = ctrl->val;
+		if (((ctrl->val >> 16) < inst->capability.frame_rate.min ||
+			(ctrl->val >> 16) > inst->capability.frame_rate.max) &&
+			ctrl->val != INT_MAX) {
+			dprintk(VIDC_ERR, "Invalid operating rate %u\n",
+				(ctrl->val >> 16));
+			rc = -ENOTSUPP;
+		} else if (ctrl->val == INT_MAX) {
+			dprintk(VIDC_DBG,
+				"inst(%pK) Request for turbo mode\n", inst);
+			inst->clk_data.turbo_mode = true;
+		} else if (msm_vidc_validate_operating_rate(inst, ctrl->val)) {
+			dprintk(VIDC_ERR, "Failed to set operating rate\n");
+			rc = -ENOTSUPP;
+		} else {
+			dprintk(VIDC_DBG,
+				"inst(%pK) operating rate changed from %d to %d\n",
+				inst, inst->clk_data.operating_rate >> 16,
+					ctrl->val >> 16);
+			inst->clk_data.operating_rate = ctrl->val;
+			inst->clk_data.turbo_mode = false;
+		}
 		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_MODE:
 		if (ctrl->val ==
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index dfb2ad5..35154a22 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -909,7 +909,16 @@
 		.minimum = 0,
 		.maximum = INT_MAX,
 		.default_value = 0,
-		.step = OPERATING_FRAME_RATE_STEP,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE,
+		.name = "Set Encoder Frame rate",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = INT_MAX,
+		.default_value = 0,
+		.step = 1,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_VENC_BITRATE_TYPE,
@@ -1817,12 +1826,27 @@
 		}
 		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE:
-		dprintk(VIDC_DBG,
-			"inst(%pK) operating rate changed from %d to %d\n",
-			inst, inst->clk_data.operating_rate >> 16,
+		if (((ctrl->val >> 16) < inst->capability.frame_rate.min ||
+			 (ctrl->val >> 16) > inst->capability.frame_rate.max) &&
+			  ctrl->val != INT_MAX) {
+			dprintk(VIDC_ERR, "Invalid operating rate %u\n",
+				(ctrl->val >> 16));
+			rc = -ENOTSUPP;
+		} else if (ctrl->val == INT_MAX) {
+			dprintk(VIDC_DBG, "inst(%pK) Request for turbo mode\n",
+				inst);
+			inst->clk_data.turbo_mode = true;
+		} else if (msm_vidc_validate_operating_rate(inst, ctrl->val)) {
+			dprintk(VIDC_ERR, "Failed to set operating rate\n");
+			rc = -ENOTSUPP;
+		} else {
+			dprintk(VIDC_DBG,
+				"inst(%pK) operating rate changed from %d to %d\n",
+				inst, inst->clk_data.operating_rate >> 16,
 				ctrl->val >> 16);
-		inst->clk_data.operating_rate = ctrl->val;
-
+			inst->clk_data.operating_rate = ctrl->val;
+			inst->clk_data.turbo_mode = false;
+		}
 		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_VENC_BITRATE_TYPE:
 	{
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 920e91a..167c948 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -179,6 +179,10 @@
 	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
 		msm_vidc_ctrl_get_range(ctrl, &inst->capability.slice_bytes);
 		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE:
+	case V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE:
+		msm_vidc_ctrl_get_range(ctrl, &inst->capability.frame_rate);
+		break;
 	case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
 	case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE:
 	case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_PROFILE:
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
index d557959..1ef1282 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
@@ -569,6 +569,12 @@
 	mutex_lock(&core->lock);
 	list_for_each_entry(temp, &core->instances, list) {
 		freq += temp->clk_data.curr_freq;
+		if (temp->clk_data.turbo_mode) {
+			dprintk(VIDC_PROF,
+				"Found an instance with Turbo request\n");
+			freq = msm_vidc_max_freq(core);
+			break;
+		}
 	}
 	for (i = core->resources.allowed_clks_tbl_size - 1; i >= 0; i--) {
 		rate = allowed_clks_tbl[i].clock_rate;
@@ -587,19 +593,22 @@
 	return rc;
 }
 
-int msm_vidc_update_operating_rate(struct msm_vidc_inst *inst)
+int msm_vidc_validate_operating_rate(struct msm_vidc_inst *inst,
+	u32 operating_rate)
 {
-	struct v4l2_ctrl *ctrl = NULL;
 	struct msm_vidc_inst *temp;
 	struct msm_vidc_core *core;
 	unsigned long max_freq, freq_left, ops_left, load, cycles, freq = 0;
 	unsigned long mbs_per_second;
+	int rc = 0;
+	u32 curr_operating_rate = 0;
 
 	if (!inst || !inst->core) {
 		dprintk(VIDC_ERR, "%s Invalid args\n", __func__);
 		return -EINVAL;
 	}
 	core = inst->core;
+	curr_operating_rate = inst->clk_data.operating_rate >> 16;
 
 	mutex_lock(&core->lock);
 	max_freq = msm_vidc_max_freq(core);
@@ -614,51 +623,35 @@
 
 	freq_left = max_freq - freq;
 
-	list_for_each_entry(temp, &core->instances, list) {
-
-		if (!temp ||
-				temp->state < MSM_VIDC_START_DONE ||
-				temp->state >= MSM_VIDC_RELEASE_RESOURCES_DONE)
-			continue;
-
-		mbs_per_second = msm_comm_get_inst_load_per_core(temp,
+	mbs_per_second = msm_comm_get_inst_load_per_core(inst,
 		LOAD_CALC_NO_QUIRKS);
 
-		cycles = temp->clk_data.entry->vpp_cycles;
-		if (temp->session_type == MSM_VIDC_ENCODER)
-			cycles = temp->flags & VIDC_LOW_POWER ?
-				temp->clk_data.entry->low_power_cycles :
-				cycles;
+	cycles = inst->clk_data.entry->vpp_cycles;
+	if (inst->session_type == MSM_VIDC_ENCODER)
+		cycles = inst->flags & VIDC_LOW_POWER ?
+			inst->clk_data.entry->low_power_cycles :
+			cycles;
 
-		load = cycles * mbs_per_second;
+	load = cycles * mbs_per_second;
 
-		ops_left = load ? (freq_left / load) : 0;
-		/* Convert remaining operating rate to Q16 format */
-		ops_left = ops_left << 16;
+	ops_left = load ? (freq_left / load) : 0;
 
-		ctrl = v4l2_ctrl_find(&temp->ctrl_handler,
-			V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE);
-		if (ctrl) {
-			dprintk(VIDC_DBG,
-				"%s: Before Range = %lld --> %lld\n",
-				ctrl->name, ctrl->minimum, ctrl->maximum);
-			dprintk(VIDC_DBG,
-				"%s: Before Def value = %lld Cur val = %d\n",
-				ctrl->name, ctrl->default_value, ctrl->val);
-			v4l2_ctrl_modify_range(ctrl, ctrl->minimum,
-				ctrl->val + ops_left, ctrl->step,
-				ctrl->default_value);
-			dprintk(VIDC_DBG,
-				"%s: Updated Range = %lld --> %lld\n",
-				ctrl->name, ctrl->minimum, ctrl->maximum);
-			dprintk(VIDC_DBG,
-				"%s: Updated Def value = %lld Cur val = %d\n",
-				ctrl->name, ctrl->default_value, ctrl->val);
-		}
+	operating_rate = operating_rate >> 16;
+
+	if ((curr_operating_rate + ops_left) >= operating_rate) {
+		dprintk(VIDC_DBG,
+			"Requestd operating rate is valid %u\n",
+			operating_rate);
+		rc = 0;
+	} else {
+		dprintk(VIDC_DBG,
+			"Current load is high for requested settings. Cannot set operating rate to %u\n",
+			operating_rate);
+		rc = -EINVAL;
 	}
 	mutex_unlock(&core->lock);
 
-	return 0;
+	return rc;
 }
 
 int msm_comm_scale_clocks(struct msm_vidc_inst *inst)
@@ -980,8 +973,8 @@
 		return 0;
 	}
 	mbs_per_frame = msm_vidc_get_mbs_per_frame(inst);
-	if (mbs_per_frame >= inst->core->resources.max_hq_mbs_per_frame ||
-		inst->prop.fps >= inst->core->resources.max_hq_fps) {
+	if (mbs_per_frame > inst->core->resources.max_hq_mbs_per_frame ||
+		inst->prop.fps > inst->core->resources.max_hq_fps) {
 		enable = true;
 	}
 
@@ -1184,7 +1177,37 @@
 
 	rc = msm_comm_scale_clocks_and_bus(inst);
 
+	msm_print_core_status(core, VIDC_CORE_ID_1);
+	msm_print_core_status(core, VIDC_CORE_ID_2);
+
 	return rc;
 }
 
+void msm_print_core_status(struct msm_vidc_core *core, u32 core_id)
+{
+	struct msm_vidc_inst *inst = NULL;
 
+	dprintk(VIDC_PROF, "Instances running on core %u", core_id);
+	mutex_lock(&core->lock);
+	list_for_each_entry(inst, &core->instances, list) {
+
+		if (!((inst->clk_data.core_id & core_id) ||
+			  (inst->clk_data.core_id & VIDC_CORE_ID_3)))
+			continue;
+
+		dprintk(VIDC_PROF,
+			"inst %pK (%4ux%4u) to (%4ux%4u) %3u %s %s %s %s\n",
+			inst,
+			inst->prop.width[OUTPUT_PORT],
+			inst->prop.height[OUTPUT_PORT],
+			inst->prop.width[CAPTURE_PORT],
+			inst->prop.height[CAPTURE_PORT],
+			inst->prop.fps,
+			inst->session_type == MSM_VIDC_ENCODER ? "ENC" : "DEC",
+			inst->clk_data.work_mode == VIDC_WORK_MODE_1 ?
+				"WORK_MODE_1" : "WORK_MODE_2",
+			inst->flags & VIDC_LOW_POWER ? "LP" : "HQ",
+			inst->flags & VIDC_REALTIME ? "RealTime" : "NonRTime");
+	}
+	mutex_unlock(&core->lock);
+}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.h b/drivers/media/platform/msm/vidc/msm_vidc_clocks.h
index 707f034..142d63f 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.h
@@ -22,7 +22,8 @@
 #define DCVS_DEC_EXTRA_OUTPUT_BUFFERS 4
 
 void msm_clock_data_reset(struct msm_vidc_inst *inst);
-int msm_vidc_update_operating_rate(struct msm_vidc_inst *inst);
+int msm_vidc_validate_operating_rate(struct msm_vidc_inst *inst,
+	u32 operating_rate);
 int msm_vidc_get_extra_buff_count(struct msm_vidc_inst *inst,
 	enum hal_buffer buffer_type);
 int msm_dcvs_try_enable(struct msm_vidc_inst *inst);
@@ -31,6 +32,7 @@
 void msm_comm_free_freq_table(struct msm_vidc_inst *inst);
 int msm_vidc_decide_work_mode(struct msm_vidc_inst *inst);
 int msm_vidc_decide_core_and_power_mode(struct msm_vidc_inst *inst);
+void msm_print_core_status(struct msm_vidc_core *core, u32 core_id);
 void msm_vidc_clear_freq_entry(struct msm_vidc_inst *inst,
 	u32 device_addr);
 void msm_comm_free_input_cr_table(struct msm_vidc_inst *inst);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 8fd1dd1..318b7182 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -1439,6 +1439,9 @@
 				V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES,
 				&inst->capability.bframe);
 	}
+	msm_vidc_comm_update_ctrl(inst,
+		V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE,
+		&inst->capability.frame_rate);
 }
 
 static void handle_session_init_done(enum hal_command_response cmd, void *data)
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index ba05059..3aae708 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -279,6 +279,7 @@
 	u32 opb_fourcc;
 	enum hal_work_mode work_mode;
 	bool low_latency_mode;
+	bool turbo_mode;
 };
 
 struct profile_data {