Răsfoiți Sursa

Merge "video: driver: add core sub_state support"

qctecmdr 2 ani în urmă
părinte
comite
a06d7674ec

+ 5 - 4
driver/variant/common/src/msm_vidc_variant.c

@@ -8,6 +8,7 @@
 #include <linux/iopoll.h>
 
 #include "msm_vidc_core.h"
+#include "msm_vidc_driver.h"
 #include "msm_vidc_debug.h"
 #include "msm_vidc_variant.h"
 #include "msm_vidc_platform.h"
@@ -44,7 +45,7 @@ int __write_register(struct msm_vidc_core *core, u32 reg, u32 value)
 	if (rc)
 		return rc;
 
-	if (!core->power_enabled) {
+	if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE)) {
 		d_vpr_e("HFI Write register failed : Power is OFF\n");
 		return -EINVAL;
 	}
@@ -83,7 +84,7 @@ int __write_register_masked(struct msm_vidc_core *core, u32 reg, u32 value,
 	if (rc)
 		return rc;
 
-	if (!core->power_enabled) {
+	if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE)) {
 		d_vpr_e("%s: register write failed, power is off\n",
 			__func__);
 		return -EINVAL;
@@ -121,7 +122,7 @@ int __read_register(struct msm_vidc_core *core, u32 reg, u32 *value)
 		return -EINVAL;
 	}
 
-	if (!core->power_enabled) {
+	if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE)) {
 		d_vpr_e("HFI Read register failed : Power is OFF\n");
 		return -EINVAL;
 	}
@@ -152,7 +153,7 @@ int __read_register_with_poll_timeout(struct msm_vidc_core *core, u32 reg,
 		return -EINVAL;
 	}
 
-	if (!core->power_enabled) {
+	if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE)) {
 		d_vpr_e("%s failed: Power is OFF\n", __func__);
 		return -EINVAL;
 	}

+ 16 - 6
driver/variant/iris2/src/msm_vidc_iris2.c

@@ -252,7 +252,7 @@ static int __power_off_iris2_hardware(struct msm_vidc_core *core)
 	int rc = 0, i;
 	u32 value = 0;
 
-	if (core->hw_power_control) {
+	if (is_core_sub_state(core, CORE_SUBSTATE_FW_PWR_CTRL)) {
 		d_vpr_h("%s: hardware power control enabled\n", __func__);
 		goto disable_power;
 	}
@@ -417,7 +417,7 @@ static int __power_off_iris2(struct msm_vidc_core *core)
 		return -EINVAL;
 	}
 
-	if (!core->power_enabled)
+	if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE))
 		return 0;
 
 	/**
@@ -442,7 +442,7 @@ static int __power_off_iris2(struct msm_vidc_core *core)
 		disable_irq_nosync(core->resource->irq);
 	core->intr_status = 0;
 
-	core->power_enabled = false;
+	msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE, 0, __func__);
 
 	return rc;
 }
@@ -504,9 +504,15 @@ static int __power_on_iris2(struct msm_vidc_core *core)
 	u32 freq = 0;
 	int rc = 0;
 
-	if (core->power_enabled)
+	if (is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE))
 		return 0;
 
+	if (!core_in_valid_state(core)) {
+		d_vpr_e("%s: invalid core state %s\n",
+			__func__, core_state_name(core->state));
+		return -EINVAL;
+	}
+
 	/* Vote for all hardware resources */
 	rc = call_res_op(core, set_bw, core, INT_MAX, INT_MAX);
 	if (rc) {
@@ -526,7 +532,9 @@ static int __power_on_iris2(struct msm_vidc_core *core)
 		goto fail_power_on_hardware;
 	}
 	/* video controller and hardware powered on successfully */
-	core->power_enabled = true;
+	rc = msm_vidc_change_core_sub_state(core, 0, CORE_SUBSTATE_POWER_ENABLE, __func__);
+	if (rc)
+		goto fail_power_on_substate;
 
 	freq_tbl = core->resource->freq_set.freq_tbl;
 	freq = core->power.clk_freq ? core->power.clk_freq :
@@ -552,12 +560,14 @@ static int __power_on_iris2(struct msm_vidc_core *core)
 
 	return rc;
 
+fail_power_on_substate:
+	__power_off_iris2_hardware(core);
 fail_power_on_hardware:
 	__power_off_iris2_controller(core);
 fail_power_on_controller:
 	call_res_op(core, set_bw, core, 0, 0);
 fail_vote_buses:
-	core->power_enabled = false;
+	msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE, 0, __func__);
 	return rc;
 }
 

+ 24 - 12
driver/variant/iris3/src/msm_vidc_iris3.c

@@ -277,24 +277,26 @@ static int __power_off_iris3_hardware(struct msm_vidc_core *core)
 	 * Incase hw power control is enabled, for both CPU WD, video
 	 * hw unresponsive cases, check for power status to decide on
 	 * executing NOC reset sequence before disabling power. If there
-	 * is no CPU WD and hw_power_control is enabled, fw is expected
+	 * is no CPU WD and hw power control is enabled, fw is expected
 	 * to power collapse video hw always.
 	 */
-	if (core->hw_power_control) {
+	if (is_core_sub_state(core, CORE_SUBSTATE_FW_PWR_CTRL)) {
 		pwr_collapsed = is_iris3_hw_power_collapsed(core);
-		if (core->cpu_watchdog || core->video_unresponsive) {
+		if (is_core_sub_state(core, CORE_SUBSTATE_CPU_WATCHDOG) ||
+			is_core_sub_state(core, CORE_SUBSTATE_VIDEO_UNRESPONSIVE)) {
 			if (pwr_collapsed) {
-				d_vpr_e("%s: video hw power collapsed %d, %d\n",
-					__func__, core->cpu_watchdog, core->video_unresponsive);
+				d_vpr_e("%s: video hw power collapsed %s\n",
+					__func__, core->sub_state_name);
 				goto disable_power;
 			} else {
-				d_vpr_e("%s: video hw is power ON %d, %d\n",
-					__func__, core->cpu_watchdog, core->video_unresponsive);
+				d_vpr_e("%s: video hw is power ON %s\n",
+					__func__, core->sub_state_name);
 			}
 		} else {
 			if (!pwr_collapsed)
 				d_vpr_e("%s: video hw is not power collapsed\n", __func__);
 
+			d_vpr_h("%s: disabling hw power\n", __func__);
 			goto disable_power;
 		}
 	}
@@ -465,7 +467,7 @@ static int __power_off_iris3(struct msm_vidc_core *core)
 		return -EINVAL;
 	}
 
-	if (!core->power_enabled)
+	if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE))
 		return 0;
 
 	/**
@@ -490,7 +492,7 @@ static int __power_off_iris3(struct msm_vidc_core *core)
 		disable_irq_nosync(core->resource->irq);
 	core->intr_status = 0;
 
-	core->power_enabled = false;
+	msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE, 0, __func__);
 
 	return rc;
 }
@@ -552,9 +554,15 @@ static int __power_on_iris3(struct msm_vidc_core *core)
 	u32 freq = 0;
 	int rc = 0;
 
-	if (core->power_enabled)
+	if (is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE))
 		return 0;
 
+	if (!core_in_valid_state(core)) {
+		d_vpr_e("%s: invalid core state %s\n",
+			__func__, core_state_name(core->state));
+		return -EINVAL;
+	}
+
 	/* Vote for all hardware resources */
 	rc = call_res_op(core, set_bw, core, INT_MAX, INT_MAX);
 	if (rc) {
@@ -574,7 +582,9 @@ static int __power_on_iris3(struct msm_vidc_core *core)
 		goto fail_power_on_hardware;
 	}
 	/* video controller and hardware powered on successfully */
-	core->power_enabled = true;
+	rc = msm_vidc_change_core_sub_state(core, 0, CORE_SUBSTATE_POWER_ENABLE, __func__);
+	if (rc)
+		goto fail_power_on_substate;
 
 	freq_tbl = core->resource->freq_set.freq_tbl;
 	freq = core->power.clk_freq ? core->power.clk_freq :
@@ -597,12 +607,14 @@ static int __power_on_iris3(struct msm_vidc_core *core)
 
 	return rc;
 
+fail_power_on_substate:
+	__power_off_iris3_hardware(core);
 fail_power_on_hardware:
 	__power_off_iris3_controller(core);
 fail_power_on_controller:
 	call_res_op(core, set_bw, core, 0, 0);
 fail_vote_buses:
-	core->power_enabled = false;
+	msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE, 0, __func__);
 	return rc;
 }
 

+ 24 - 12
driver/variant/iris33/src/msm_vidc_iris33.c

@@ -280,24 +280,26 @@ static int __power_off_iris33_hardware(struct msm_vidc_core *core)
 	 * Incase hw power control is enabled, for both CPU WD, video
 	 * hw unresponsive cases, check for power status to decide on
 	 * executing NOC reset sequence before disabling power. If there
-	 * is no CPU WD and hw_power_control is enabled, fw is expected
+	 * is no CPU WD and hw power control is enabled, fw is expected
 	 * to power collapse video hw always.
 	 */
-	if (core->hw_power_control) {
+	if (is_core_sub_state(core, CORE_SUBSTATE_FW_PWR_CTRL)) {
 		pwr_collapsed = is_iris33_hw_power_collapsed(core);
-		if (core->cpu_watchdog || core->video_unresponsive) {
+		if (is_core_sub_state(core, CORE_SUBSTATE_CPU_WATCHDOG) ||
+			is_core_sub_state(core, CORE_SUBSTATE_VIDEO_UNRESPONSIVE)) {
 			if (pwr_collapsed) {
-				d_vpr_e("%s: video hw power collapsed %d, %d\n",
-					__func__, core->cpu_watchdog, core->video_unresponsive);
+				d_vpr_e("%s: video hw power collapsed %s\n",
+					__func__, core->sub_state_name);
 				goto disable_power;
 			} else {
-				d_vpr_e("%s: video hw is power ON %d, %d\n",
-					__func__, core->cpu_watchdog, core->video_unresponsive);
+				d_vpr_e("%s: video hw is power ON %s\n",
+					__func__, core->sub_state_name);
 			}
 		} else {
 			if (!pwr_collapsed)
 				d_vpr_e("%s: video hw is not power collapsed\n", __func__);
 
+			d_vpr_h("%s: disabling hw power\n", __func__);
 			goto disable_power;
 		}
 	}
@@ -530,7 +532,7 @@ static int __power_off_iris33(struct msm_vidc_core *core)
 		return -EINVAL;
 	}
 
-	if (!core->power_enabled)
+	if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE))
 		return 0;
 
 	/**
@@ -555,7 +557,7 @@ static int __power_off_iris33(struct msm_vidc_core *core)
 		disable_irq_nosync(core->resource->irq);
 	core->intr_status = 0;
 
-	core->power_enabled = false;
+	msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE, 0, __func__);
 
 	return rc;
 }
@@ -633,9 +635,15 @@ static int __power_on_iris33(struct msm_vidc_core *core)
 	u32 freq = 0;
 	int rc = 0;
 
-	if (core->power_enabled)
+	if (is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE))
 		return 0;
 
+	if (!core_in_valid_state(core)) {
+		d_vpr_e("%s: invalid core state %s\n",
+			__func__, core_state_name(core->state));
+		return -EINVAL;
+	}
+
 	/* Vote for all hardware resources */
 	rc = call_res_op(core, set_bw, core, INT_MAX, INT_MAX);
 	if (rc) {
@@ -655,7 +663,9 @@ static int __power_on_iris33(struct msm_vidc_core *core)
 		goto fail_power_on_hardware;
 	}
 	/* video controller and hardware powered on successfully */
-	core->power_enabled = true;
+	rc = msm_vidc_change_core_sub_state(core, 0, CORE_SUBSTATE_POWER_ENABLE, __func__);
+	if (rc)
+		goto fail_power_on_substate;
 
 	freq_tbl = core->resource->freq_set.freq_tbl;
 	freq = core->power.clk_freq ? core->power.clk_freq :
@@ -678,12 +688,14 @@ static int __power_on_iris33(struct msm_vidc_core *core)
 
 	return rc;
 
+fail_power_on_substate:
+	__power_off_iris33_hardware(core);
 fail_power_on_hardware:
 	__power_off_iris33_controller(core);
 fail_power_on_controller:
 	call_res_op(core, set_bw, core, 0, 0);
 fail_vote_buses:
-	core->power_enabled = false;
+	msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE, 0, __func__);
 	return rc;
 }
 

+ 19 - 7
driver/vidc/inc/msm_vidc_core.h

@@ -65,6 +65,18 @@ struct msm_vidc_core_power {
 
 enum msm_vidc_core_state FOREACH_CORE_STATE(GENERATE_MSM_VIDC_ENUM);
 
+enum msm_vidc_core_sub_state {
+	CORE_SUBSTATE_NONE                   = 0x0,
+	CORE_SUBSTATE_POWER_ENABLE           = BIT(0),
+	CORE_SUBSTATE_GDSC_HANDOFF           = BIT(1),
+	CORE_SUBSTATE_PM_SUSPEND             = BIT(2),
+	CORE_SUBSTATE_FW_PWR_CTRL            = BIT(3),
+	CORE_SUBSTATE_PAGE_FAULT             = BIT(4),
+	CORE_SUBSTATE_CPU_WATCHDOG           = BIT(5),
+	CORE_SUBSTATE_VIDEO_UNRESPONSIVE     = BIT(6),
+	CORE_SUBSTATE_MAX                    = BIT(7),
+};
+
 struct msm_vidc_core {
 	struct platform_device                *pdev;
 	struct msm_video_device                vdev[2];
@@ -76,13 +88,14 @@ struct msm_vidc_core {
 	struct dentry                         *debugfs_root;
 	char                                   fw_version[MAX_NAME_LENGTH];
 	enum msm_vidc_core_state               state;
+	enum msm_vidc_core_sub_state           sub_state;
+	char                                   sub_state_name[MAX_NAME_LENGTH];
 	struct mutex                           lock;
 	struct msm_vidc_resource              *resource;
 	struct msm_vidc_platform              *platform;
 	u32                                    intr_status;
 	u32                                    spur_count;
 	u32                                    reg_count;
-	bool                                   power_enabled;
 	u32                                    codecs_count;
 	struct msm_vidc_core_capability       *capabilities;
 	struct msm_vidc_inst_capability       *inst_caps;
@@ -96,7 +109,6 @@ struct msm_vidc_core {
 	struct work_struct                     ssr_work;
 	struct msm_vidc_core_power             power;
 	struct msm_vidc_ssr                    ssr;
-	bool                                   smmu_fault_handled;
 	u32                                    skip_pc_count;
 	u32                                    last_packet_type;
 	u8                                    *packet;
@@ -117,11 +129,11 @@ struct msm_vidc_core {
 	u32                                    header_id;
 	u32                                    packet_id;
 	u32                                    sys_init_id;
-	bool                                   handoff_done;
-	bool                                   hw_power_control;
-	bool                                   pm_suspended;
-	bool                                   cpu_watchdog;
-	bool                                   video_unresponsive;
 };
 
+static inline bool core_in_valid_state(struct msm_vidc_core *core)
+{
+	return core->state != MSM_VIDC_CORE_DEINIT;
+}
+
 #endif // _MSM_VIDC_CORE_H_

+ 16 - 1
driver/vidc/inc/msm_vidc_driver.h

@@ -370,6 +370,17 @@ static inline bool is_sub_state(struct msm_vidc_inst *inst,
 	return (inst->sub_state & sub_state);
 }
 
+static inline bool is_core_state(struct msm_vidc_core *core, enum msm_vidc_core_state state)
+{
+	return core->state == state;
+}
+
+static inline bool is_core_sub_state(struct msm_vidc_core *core,
+	enum msm_vidc_core_sub_state sub_state)
+{
+	return !!(core->sub_state & sub_state);
+}
+
 const char *cap_name(enum msm_vidc_inst_capability_type cap_id);
 const char *v4l2_pixelfmt_name(struct msm_vidc_inst *inst, u32 pixelfmt);
 const char *v4l2_type_name(u32 port);
@@ -434,6 +445,9 @@ int msm_vidc_kill_session(struct msm_vidc_inst* inst);
 int msm_vidc_get_inst_capability(struct msm_vidc_inst *inst);
 int msm_vidc_change_core_state(struct msm_vidc_core *core,
 	enum msm_vidc_core_state request_state, const char *func);
+int msm_vidc_change_core_sub_state(struct msm_vidc_core *core,
+	enum msm_vidc_core_sub_state clear_sub_states,
+	enum msm_vidc_core_sub_state set_sub_states, const char *func);
 int msm_vidc_core_init(struct msm_vidc_core *core);
 int msm_vidc_core_init_wait(struct msm_vidc_core *core);
 int msm_vidc_core_deinit(struct msm_vidc_core *core, bool force);
@@ -451,7 +465,7 @@ int msm_vidc_trigger_stability(struct msm_vidc_core *core,
 void msm_vidc_stability_handler(struct work_struct *work);
 int cancel_stability_work_sync(struct msm_vidc_inst *inst);
 void msm_vidc_fw_unload_handler(struct work_struct *work);
-int msm_vidc_suspend(struct msm_vidc_core *core);
+int msm_vidc_suspend_locked(struct msm_vidc_core *core);
 void msm_vidc_batch_handler(struct work_struct *work);
 int msm_vidc_event_queue_init(struct msm_vidc_inst *inst);
 int msm_vidc_event_queue_deinit(struct msm_vidc_inst *inst);
@@ -516,6 +530,7 @@ enum msm_vidc_allow msm_vidc_allow_qbuf(struct msm_vidc_inst *inst, u32 type);
 enum msm_vidc_allow msm_vidc_allow_input_psc(struct msm_vidc_inst *inst);
 bool msm_vidc_allow_drain_last_flag(struct msm_vidc_inst *inst);
 bool msm_vidc_allow_psc_last_flag(struct msm_vidc_inst *inst);
+bool msm_vidc_allow_pm_suspend(struct msm_vidc_core *core);
 int msm_vidc_state_change_streamon(struct msm_vidc_inst *inst, u32 type);
 int msm_vidc_state_change_streamoff(struct msm_vidc_inst *inst, u32 type);
 int msm_vidc_state_change_input_psc(struct msm_vidc_inst *inst);

+ 0 - 1
driver/vidc/inc/msm_vidc_internal.h

@@ -949,7 +949,6 @@ struct msm_vidc_input_timer {
 enum msm_vidc_allow FOREACH_ALLOW(GENERATE_ENUM);
 
 struct msm_vidc_ssr {
-	bool                               trigger;
 	enum msm_vidc_ssr_trigger_type     ssr_type;
 	u32                                sub_client_id;
 	u32                                test_addr;

+ 0 - 1
driver/vidc/inc/venus_hfi.h

@@ -73,6 +73,5 @@ irqreturn_t venus_hfi_isr(int irq, void *data);
 irqreturn_t venus_hfi_isr_handler(int irq, void *data);
 
 int __prepare_pc(struct msm_vidc_core *core);
-bool __core_in_valid_state(struct msm_vidc_core *core);
 
 #endif // _VENUS_HFI_H_

+ 108 - 40
driver/vidc/src/msm_vidc_driver.c

@@ -146,6 +146,23 @@ exit:
 	return name;
 }
 
+const char *core_sub_state_name(enum msm_vidc_core_sub_state sub_state)
+{
+	switch (sub_state) {
+	case CORE_SUBSTATE_NONE:                 return "NONE ";
+	case CORE_SUBSTATE_GDSC_HANDOFF:         return "GDSC_HANDOFF ";
+	case CORE_SUBSTATE_PM_SUSPEND:           return "PM_SUSPEND ";
+	case CORE_SUBSTATE_FW_PWR_CTRL:          return "FW_PWR_CTRL ";
+	case CORE_SUBSTATE_POWER_ENABLE:         return "POWER_ENABLE ";
+	case CORE_SUBSTATE_PAGE_FAULT:           return "PAGE_FAULT ";
+	case CORE_SUBSTATE_CPU_WATCHDOG:         return "CPU_WATCHDOG ";
+	case CORE_SUBSTATE_VIDEO_UNRESPONSIVE:   return "VIDEO_UNRESPONSIVE ";
+	case CORE_SUBSTATE_MAX:                  return "MAX ";
+	}
+
+	return "UNKNOWN ";
+}
+
 const char *v4l2_type_name(u32 port)
 {
 	switch (port) {
@@ -304,7 +321,7 @@ static u32 msm_vidc_get_buffer_stats_flag(struct msm_vidc_inst *inst)
 	return flags;
 }
 
-static int msm_vidc_suspend_locked(struct msm_vidc_core *core)
+int msm_vidc_suspend_locked(struct msm_vidc_core *core)
 {
 	int rc = 0;
 
@@ -1027,6 +1044,53 @@ int msm_vidc_change_core_state(struct msm_vidc_core *core,
 	return 0;
 }
 
+int msm_vidc_change_core_sub_state(struct msm_vidc_core *core,
+		enum msm_vidc_core_sub_state clear_sub_state,
+		enum msm_vidc_core_sub_state set_sub_state, const char *func)
+{
+	int i = 0;
+	enum msm_vidc_core_sub_state prev_sub_state;
+
+	if (!core) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	/* final value will not change */
+	if (clear_sub_state == set_sub_state)
+		return 0;
+
+	/* sanitize clear & set value */
+	if (set_sub_state > CORE_SUBSTATE_MAX ||
+		clear_sub_state > CORE_SUBSTATE_MAX) {
+		d_vpr_e("%s: invalid sub states. clear %#x or set %#x\n",
+			func, clear_sub_state, set_sub_state);
+		return -EINVAL;
+	}
+
+	prev_sub_state = core->sub_state;
+	core->sub_state |= set_sub_state;
+	core->sub_state &= ~clear_sub_state;
+
+	/* print substates only when there is a change */
+	if (core->sub_state != prev_sub_state) {
+		strscpy(core->sub_state_name, "\0", sizeof(core->sub_state_name));
+		for (i = 0; BIT(i) < CORE_SUBSTATE_MAX; i++) {
+			if (core->sub_state == CORE_SUBSTATE_NONE) {
+				strscpy(core->sub_state_name, "CORE_SUBSTATE_NONE",
+					sizeof(core->sub_state_name));
+				break;
+			}
+			if (core->sub_state & BIT(i))
+				strlcat(core->sub_state_name, core_sub_state_name(BIT(i)),
+					sizeof(core->sub_state_name));
+		}
+		d_vpr_h("%s: core sub state changed to %s\n", func, core->sub_state_name);
+	}
+
+	return 0;
+}
+
 int msm_vidc_change_state(struct msm_vidc_inst *inst,
 		enum msm_vidc_state request_state, const char *func)
 {
@@ -1561,6 +1625,29 @@ bool msm_vidc_allow_psc_last_flag(struct msm_vidc_inst *inst)
 	return false;
 }
 
+bool msm_vidc_allow_pm_suspend(struct msm_vidc_core *core)
+{
+	if (!core) {
+		d_vpr_e("%s: invalid param\n", __func__);
+		return false;
+	}
+
+	/* core must be in valid state to do pm_suspend */
+	if (!core_in_valid_state(core)) {
+		d_vpr_e("%s: invalid core state %s\n",
+			__func__, core_state_name(core->state));
+		return false;
+	}
+
+	/* check if power is enabled */
+	if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE)) {
+		d_vpr_e("%s: Power already disabled\n", __func__);
+		return false;
+	}
+
+	return true;
+}
+
 bool is_hevc_10bit_decode_session(struct msm_vidc_inst *inst)
 {
 	bool is10bit = false;
@@ -4640,7 +4727,7 @@ int msm_vidc_core_deinit_locked(struct msm_vidc_core *core, bool force)
 		return rc;
 	}
 
-	if (core->state == MSM_VIDC_CORE_DEINIT)
+	if (is_core_state(core, MSM_VIDC_CORE_DEINIT))
 		return 0;
 
 	if (force) {
@@ -4693,10 +4780,10 @@ int msm_vidc_core_init_wait(struct msm_vidc_core *core)
 	}
 
 	core_lock(core, __func__);
-	if (core->state == MSM_VIDC_CORE_INIT) {
+	if (is_core_state(core, MSM_VIDC_CORE_INIT)) {
 		rc = 0;
 		goto unlock;
-	} else if (core->state == MSM_VIDC_CORE_DEINIT) {
+	} else if (is_core_state(core, MSM_VIDC_CORE_DEINIT)) {
 		rc = -EINVAL;
 		goto unlock;
 	}
@@ -4715,14 +4802,16 @@ int msm_vidc_core_init_wait(struct msm_vidc_core *core)
 	d_vpr_h("%s: state %s, interval %u, count %u, max_tries %u\n", __func__,
 		core_state_name(core->state), interval, count, max_tries);
 
-	if (core->state == MSM_VIDC_CORE_INIT) {
+	if (is_core_state(core, MSM_VIDC_CORE_INIT)) {
 		d_vpr_h("%s: sys init successful\n", __func__);
 		rc = 0;
 		goto unlock;
 	} else {
 		d_vpr_h("%s: sys init wait timedout. state %s\n",
 			__func__, core_state_name(core->state));
-		core->video_unresponsive = true;
+		/* mark video hw unresponsive */
+		msm_vidc_change_core_sub_state(core,
+			0, CORE_SUBSTATE_VIDEO_UNRESPONSIVE, __func__);
 		rc = -EINVAL;
 		goto unlock;
 	}
@@ -4743,14 +4832,14 @@ int msm_vidc_core_init(struct msm_vidc_core *core)
 	}
 
 	core_lock(core, __func__);
-	if (core->state == MSM_VIDC_CORE_INIT ||
-			core->state == MSM_VIDC_CORE_INIT_WAIT)
+	if (is_core_state(core, MSM_VIDC_CORE_INIT) ||
+			is_core_state(core, MSM_VIDC_CORE_INIT_WAIT))
 		goto unlock;
 
 	msm_vidc_change_core_state(core, MSM_VIDC_CORE_INIT_WAIT, __func__);
-	core->smmu_fault_handled = false;
-	core->ssr.trigger = false;
-	core->pm_suspended = false;
+	/* clear PM suspend from core sub_state */
+	msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_PM_SUSPEND, 0, __func__);
+	msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_PAGE_FAULT, 0, __func__);
 
 	rc = venus_hfi_core_init(core);
 	if (rc) {
@@ -4798,7 +4887,8 @@ int msm_vidc_inst_timeout(struct msm_vidc_inst *inst)
 		goto unlock;
 	}
 	/* mark video hw unresponsive */
-	core->video_unresponsive = true;
+	msm_vidc_change_core_sub_state(core,
+		0, CORE_SUBSTATE_VIDEO_UNRESPONSIVE, __func__);
 
 	/* call core deinit for a valid instance timeout case */
 	msm_vidc_core_deinit_locked(core, true);
@@ -4938,7 +5028,7 @@ int msm_vidc_smmu_fault_handler(struct iommu_domain *domain,
 		return -EINVAL;
 	}
 
-	if (core->smmu_fault_handled) {
+	if (is_core_sub_state(core, CORE_SUBSTATE_PAGE_FAULT)) {
 		if (core->capabilities[NON_FATAL_FAULTS].value) {
 			dprintk_ratelimit(VIDC_ERR, "err ",
 					"%s: non-fatal pagefault address: %lx\n",
@@ -4949,7 +5039,8 @@ int msm_vidc_smmu_fault_handler(struct iommu_domain *domain,
 
 	d_vpr_e(FMT_STRING_FAULT_HANDLER, __func__, iova);
 
-	core->smmu_fault_handled = true;
+	/* mark smmu fault as handled */
+	msm_vidc_change_core_sub_state(core, 0, CORE_SUBSTATE_PAGE_FAULT, __func__);
 
 	/* print noc error log registers */
 	venus_hfi_noc_error_info(core);
@@ -5005,20 +5096,17 @@ void msm_vidc_ssr_handler(struct work_struct *work)
 	ssr = &core->ssr;
 
 	core_lock(core, __func__);
-	if (core->state == MSM_VIDC_CORE_INIT) {
+	if (is_core_state(core, MSM_VIDC_CORE_INIT)) {
 		/*
 		 * In current implementation, user-initiated SSR triggers
 		 * a fatal error from hardware. However, there is no way
 		 * to know if fatal error is due to SSR or not. Handle
 		 * user SSR as non-fatal.
 		 */
-		core->ssr.trigger = true;
 		rc = venus_hfi_trigger_ssr(core, ssr->ssr_type,
 			ssr->sub_client_id, ssr->test_addr);
-		if (rc) {
+		if (rc)
 			d_vpr_e("%s: trigger_ssr failed\n", __func__);
-			core->ssr.trigger = false;
-		}
 	} else {
 		d_vpr_e("%s: video core not initialized\n", __func__);
 	}
@@ -5114,26 +5202,6 @@ void msm_vidc_fw_unload_handler(struct work_struct *work)
 
 }
 
-int msm_vidc_suspend(struct msm_vidc_core *core)
-{
-	int rc = 0;
-
-	if (!core) {
-		d_vpr_e("%s: invalid params\n", __func__);
-		return -EINVAL;
-	}
-
-	core_lock(core, __func__);
-	d_vpr_h("%s: initiate PM suspend\n", __func__);
-	rc = msm_vidc_suspend_locked(core);
-	if (rc)
-		goto exit;
-
-exit:
-	core_unlock(core, __func__);
-	return rc;
-}
-
 void msm_vidc_batch_handler(struct work_struct *work)
 {
 	struct msm_vidc_inst *inst;
@@ -5155,7 +5223,7 @@ void msm_vidc_batch_handler(struct work_struct *work)
 		goto exit;
 	}
 
-	if (core->pm_suspended) {
+	if (is_core_sub_state(core, CORE_SUBSTATE_PM_SUSPEND)) {
 		i_vpr_h(inst, "%s: device in pm suspend state\n", __func__);
 		goto exit;
 	}

+ 19 - 3
driver/vidc/src/msm_vidc_probe.c

@@ -815,6 +815,7 @@ static int msm_vidc_pm_suspend(struct device *dev)
 {
 	int rc = 0;
 	struct msm_vidc_core *core;
+	bool allow = false;
 
 	/*
 	 * Bail out if
@@ -831,15 +832,25 @@ static int msm_vidc_pm_suspend(struct device *dev)
 		return -EINVAL;
 	}
 
+	core_lock(core, __func__);
+	allow = msm_vidc_allow_pm_suspend(core);
+	if (!allow) {
+		d_vpr_e("%s: pm suspend not allowed\n", __func__);
+		rc = 0;
+		goto unlock;
+	}
+
 	d_vpr_h("%s\n", __func__);
-	rc = msm_vidc_suspend(core);
+	rc = msm_vidc_suspend_locked(core);
 	if (rc == -ENOTSUPP)
 		rc = 0;
 	else if (rc)
 		d_vpr_e("Failed to suspend: %d\n", rc);
 	else
-		core->pm_suspended  = true;
+		msm_vidc_change_core_sub_state(core, 0, CORE_SUBSTATE_PM_SUSPEND, __func__);
 
+unlock:
+	core_unlock(core, __func__);
 	return rc;
 }
 
@@ -863,7 +874,12 @@ static int msm_vidc_pm_resume(struct device *dev)
 	}
 
 	d_vpr_h("%s\n", __func__);
-	core->pm_suspended  = false;
+
+	/* remove PM suspend from core sub_state */
+	core_lock(core, __func__);
+	msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_PM_SUSPEND, 0, __func__);
+	core_unlock(core, __func__);
+
 	return 0;
 }
 

+ 12 - 4
driver/vidc/src/resources.c

@@ -16,6 +16,7 @@
 #include "msm_vidc_core.h"
 #include "msm_vidc_debug.h"
 #include "msm_vidc_power.h"
+#include "msm_vidc_driver.h"
 #include "msm_vidc_platform.h"
 #include "venus_hfi.h"
 
@@ -668,7 +669,9 @@ static int __acquire_regulator(struct msm_vidc_core *core,
 
 		if (regulator_get_mode(rinfo->regulator) ==
 				REGULATOR_MODE_NORMAL) {
-			core->handoff_done = false;
+			/* clear handoff from core sub_state */
+			msm_vidc_change_core_sub_state(core,
+				CORE_SUBSTATE_GDSC_HANDOFF, 0, __func__);
 			d_vpr_h("Skip acquire regulator %s\n", rinfo->name);
 			goto exit;
 		}
@@ -685,7 +688,9 @@ static int __acquire_regulator(struct msm_vidc_core *core,
 				rinfo->name);
 			goto exit;
 		} else {
-			core->handoff_done = false;
+			/* reset handoff from core sub_state */
+			msm_vidc_change_core_sub_state(core,
+				CORE_SUBSTATE_GDSC_HANDOFF, 0, __func__);
 			d_vpr_h("Acquired regulator control from HW: %s\n",
 					rinfo->name);
 
@@ -731,7 +736,9 @@ static int __hand_off_regulator(struct msm_vidc_core *core,
 				rinfo->name);
 			return rc;
 		} else {
-			core->handoff_done = true;
+			/* set handoff done in core sub_state */
+			msm_vidc_change_core_sub_state(core,
+				0, CORE_SUBSTATE_GDSC_HANDOFF, __func__);
 			d_vpr_h("Hand off regulator control to HW: %s\n",
 					rinfo->name);
 		}
@@ -800,7 +807,8 @@ static int __disable_regulator(struct msm_vidc_core *core, const char *reg_name)
 			WARN_ON(true);
 			return rc;
 		}
-		core->handoff_done = false;
+		/* reset handoff done from core sub_state */
+		msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_GDSC_HANDOFF, 0, __func__);
 
 		rc = regulator_disable(rinfo->regulator);
 		if (rc) {

+ 47 - 30
driver/vidc/src/venus_hfi.c

@@ -59,11 +59,6 @@ static int __strict_check(struct msm_vidc_core *core, const char *function)
 	return fatal ? -EINVAL : 0;
 }
 
-bool __core_in_valid_state(struct msm_vidc_core *core)
-{
-	return core->state != MSM_VIDC_CORE_DEINIT;
-}
-
 static bool __valdiate_session(struct msm_vidc_core *core,
 		struct msm_vidc_inst *inst, const char *func)
 {
@@ -253,12 +248,18 @@ static int __sys_set_power_control(struct msm_vidc_core *core, bool enable)
 {
 	int rc = 0;
 
-	if (!core->handoff_done) {
+	if (!is_core_sub_state(core, CORE_SUBSTATE_GDSC_HANDOFF)) {
 		d_vpr_e("%s: skipping as power control hanfoff was not done\n",
 			__func__);
 		return rc;
 	}
 
+	if (!core_in_valid_state(core)) {
+		d_vpr_e("%s: invalid core state %s\n",
+			__func__, core_state_name(core->state));
+		return rc;
+	}
+
 	rc = hfi_packet_sys_intraframe_powercollapse(core,
 		core->packet, core->packet_size, enable);
 	if (rc)
@@ -268,7 +269,10 @@ static int __sys_set_power_control(struct msm_vidc_core *core, bool enable)
 	if (rc)
 		return rc;
 
-	core->hw_power_control = true;
+	rc = msm_vidc_change_core_sub_state(core, 0, CORE_SUBSTATE_FW_PWR_CTRL, __func__);
+	if (rc)
+		return rc;
+
 	d_vpr_h("%s: set hardware power control successful\n", __func__);
 
 	return rc;
@@ -300,12 +304,12 @@ static int __power_collapse(struct msm_vidc_core *core, bool force)
 		d_vpr_e("%s: invalid params\n", __func__);
 		return -EINVAL;
 	}
-	if (!core->power_enabled) {
+	if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE)) {
 		d_vpr_h("%s: Power already disabled\n", __func__);
 		goto exit;
 	}
 
-	if (!__core_in_valid_state(core)) {
+	if (!core_in_valid_state(core)) {
 		d_vpr_e("%s: Core not in init state\n", __func__);
 		return -EINVAL;
 	}
@@ -534,7 +538,7 @@ static int __venus_power_off(struct msm_vidc_core* core)
 {
 	int rc = 0;
 
-	if (!core->power_enabled)
+	if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE))
 		return 0;
 
 	rc = call_venus_op(core, power_off, core);
@@ -542,7 +546,7 @@ static int __venus_power_off(struct msm_vidc_core* core)
 		d_vpr_e("Failed to power off, err: %d\n", rc);
 		return rc;
 	}
-	core->power_enabled = false;
+	msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE, 0, __func__);
 
 	return rc;
 }
@@ -551,7 +555,7 @@ static int __venus_power_on(struct msm_vidc_core *core)
 {
 	int rc = 0;
 
-	if (core->power_enabled)
+	if (is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE))
 		return 0;
 
 	rc = call_venus_op(core, power_on, core);
@@ -559,7 +563,10 @@ static int __venus_power_on(struct msm_vidc_core *core)
 		d_vpr_e("Failed to power on, err: %d\n", rc);
 		return rc;
 	}
-	core->power_enabled = true;
+
+	rc = msm_vidc_change_core_sub_state(core, 0, CORE_SUBSTATE_POWER_ENABLE, __func__);
+	if (rc)
+		return rc;
 
 	return rc;
 }
@@ -571,7 +578,7 @@ static int __suspend(struct msm_vidc_core *core)
 	if (!core) {
 		d_vpr_e("%s: invalid params\n", __func__);
 		return -EINVAL;
-	} else if (!core->power_enabled) {
+	} else if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE)) {
 		d_vpr_h("Power already disabled\n");
 		return 0;
 	}
@@ -605,9 +612,9 @@ static int __resume(struct msm_vidc_core *core)
 	if (!core) {
 		d_vpr_e("%s: invalid params\n", __func__);
 		return -EINVAL;
-	} else if (core->power_enabled) {
+	} else if (is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE)) {
 		goto exit;
-	} else if (!__core_in_valid_state(core)) {
+	} else if (!core_in_valid_state(core)) {
 		d_vpr_e("%s: core not in valid state\n", __func__);
 		return -EINVAL;
 	}
@@ -617,8 +624,14 @@ static int __resume(struct msm_vidc_core *core)
 		return rc;
 
 	d_vpr_h("Resuming from power collapse\n");
-	core->handoff_done = false;
-	core->hw_power_control = false;
+	/* reset handoff done from core sub_state */
+	rc = msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_GDSC_HANDOFF, 0, __func__);
+	if (rc)
+		return rc;
+	/* reset hw pwr ctrl from core sub_state */
+	rc = msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_FW_PWR_CTRL, 0, __func__);
+	if (rc)
+		return rc;
 
 	rc = __venus_power_on(core);
 	if (rc) {
@@ -684,10 +697,8 @@ int __load_fw(struct msm_vidc_core *core)
 	int rc = 0;
 
 	d_vpr_h("%s\n", __func__);
-	core->handoff_done = false;
-	core->hw_power_control = false;
-	core->cpu_watchdog = false;
-	core->video_unresponsive = false;
+	/* clear all substates */
+	msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_MAX - 1, 0, __func__);
 
 	trace_msm_v4l2_vidc_fw_load("START");
 	rc = __venus_power_on(core);
@@ -726,8 +737,8 @@ void __unload_fw(struct msm_vidc_core *core)
 	fw_unload(core);
 	__venus_power_off(core);
 
-	core->cpu_watchdog = false;
-	core->video_unresponsive = false;
+	/* clear all substates */
+	msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_MAX - 1, 0, __func__);
 
 	d_vpr_h("%s done\n", __func__);
 }
@@ -738,7 +749,10 @@ static int __response_handler(struct msm_vidc_core *core)
 
 	if (call_venus_op(core, watchdog, core, core->intr_status)) {
 		struct hfi_packet pkt = {.type = HFI_SYS_ERROR_WD_TIMEOUT};
-		core->cpu_watchdog = true;
+
+		/* mark cpu watchdog error */
+		msm_vidc_change_core_sub_state(core,
+			0, CORE_SUBSTATE_CPU_WATCHDOG, __func__);
 		d_vpr_e("%s: CPU WD error received\n", __func__);
 
 		return handle_system_error(core, &pkt);
@@ -817,15 +831,18 @@ void venus_hfi_pm_work_handler(struct work_struct *work)
 		d_vpr_e("Failed to PC for %d times\n",
 				core->skip_pc_count);
 		core->skip_pc_count = 0;
-		core->video_unresponsive = true;
+		/* mark video hw unresponsive */
+		msm_vidc_change_core_sub_state(core,
+			0, CORE_SUBSTATE_VIDEO_UNRESPONSIVE, __func__);
 		msm_vidc_core_deinit(core, true);
 		return;
 	}
 
 	core_lock(core, __func__);
 	/* core already deinited - skip power collapse */
-	if (core->state == MSM_VIDC_CORE_DEINIT) {
-		d_vpr_e("%s: core is already de-inited\n", __func__);
+	if (is_core_state(core, MSM_VIDC_CORE_DEINIT)) {
+		d_vpr_e("%s: invalid core state %s\n",
+			__func__, core_state_name(core->state));
 		goto unlock;
 	}
 
@@ -962,7 +979,7 @@ int venus_hfi_core_deinit(struct msm_vidc_core *core, bool force)
 	if (rc)
 		return rc;
 
-	if (core->state == MSM_VIDC_CORE_DEINIT)
+	if (is_core_state(core, MSM_VIDC_CORE_DEINIT))
 		return 0;
 	__resume(core);
 	__flush_debug_queue(core, (!force ? core->packet : NULL), core->packet_size);
@@ -993,7 +1010,7 @@ int venus_hfi_noc_error_info(struct msm_vidc_core *core)
 		return 0;
 
 	core_lock(core, __func__);
-	if (core->state == MSM_VIDC_CORE_DEINIT)
+	if (is_core_state(core, MSM_VIDC_CORE_DEINIT))
 		goto unlock;
 
 	/* resume venus before accessing noc registers */

+ 2 - 7
driver/vidc/src/venus_hfi_queue.c

@@ -22,11 +22,6 @@ static int __strict_check(struct msm_vidc_core *core, const char *function)
 	return fatal ? -EINVAL : 0;
 }
 
-static bool __core_in_valid_state(struct msm_vidc_core *core)
-{
-	return core->state != MSM_VIDC_CORE_DEINIT;
-}
-
 static void __set_queue_hdr_defaults(struct hfi_queue_header *q_hdr)
 {
 	q_hdr->qhdr_status = 0x1;
@@ -290,7 +285,7 @@ static int __iface_cmdq_write_relaxed(struct msm_vidc_core *core,
 	if (rc)
 		return rc;
 
-	if (!__core_in_valid_state(core)) {
+	if (!core_in_valid_state(core)) {
 		d_vpr_e("%s: fw not in init state\n", __func__);
 		rc = -EINVAL;
 		goto err_q_null;
@@ -355,7 +350,7 @@ int venus_hfi_queue_msg_read(struct msm_vidc_core *core, void *pkt)
 		return -EINVAL;
 	}
 
-	if (!__core_in_valid_state(core)) {
+	if (!core_in_valid_state(core)) {
 		d_vpr_e("%s: fw not in init state\n", __func__);
 		rc = -EINVAL;
 		goto read_error_null;

+ 1 - 1
driver/vidc/src/venus_hfi_response.c

@@ -495,7 +495,7 @@ static int handle_system_init(struct msm_vidc_core *core,
 {
 	if (pkt->flags & HFI_FW_FLAGS_SUCCESS) {
 		core_lock(core, __func__);
-		if (core->state == MSM_VIDC_CORE_INIT_WAIT &&
+		if (is_core_state(core, MSM_VIDC_CORE_INIT_WAIT) &&
 				pkt->packet_id == core->sys_init_id) {
 			msm_vidc_change_core_state(core, MSM_VIDC_CORE_INIT, __func__);
 			d_vpr_h("%s: successful\n", __func__);