diff --git a/driver/variant/common/src/msm_vidc_variant.c b/driver/variant/common/src/msm_vidc_variant.c index 293099d4c7..6587c0b29b 100644 --- a/driver/variant/common/src/msm_vidc_variant.c +++ b/driver/variant/common/src/msm_vidc_variant.c @@ -8,6 +8,7 @@ #include #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; } diff --git a/driver/variant/iris2/src/msm_vidc_iris2.c b/driver/variant/iris2/src/msm_vidc_iris2.c index e365d2c0c4..af9c582b29 100644 --- a/driver/variant/iris2/src/msm_vidc_iris2.c +++ b/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; } diff --git a/driver/variant/iris3/src/msm_vidc_iris3.c b/driver/variant/iris3/src/msm_vidc_iris3.c index 6dd48d6fab..0890c9f300 100644 --- a/driver/variant/iris3/src/msm_vidc_iris3.c +++ b/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; } diff --git a/driver/variant/iris33/src/msm_vidc_iris33.c b/driver/variant/iris33/src/msm_vidc_iris33.c index c4182861b4..dd863cfd7d 100644 --- a/driver/variant/iris33/src/msm_vidc_iris33.c +++ b/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; } diff --git a/driver/vidc/inc/msm_vidc_core.h b/driver/vidc/inc/msm_vidc_core.h index 5c0e682aff..e4c3e826ac 100644 --- a/driver/vidc/inc/msm_vidc_core.h +++ b/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_ diff --git a/driver/vidc/inc/msm_vidc_driver.h b/driver/vidc/inc/msm_vidc_driver.h index 0b93025bde..83c2bcdc1b 100644 --- a/driver/vidc/inc/msm_vidc_driver.h +++ b/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); diff --git a/driver/vidc/inc/msm_vidc_internal.h b/driver/vidc/inc/msm_vidc_internal.h index 5fe78f407b..2c8182161d 100644 --- a/driver/vidc/inc/msm_vidc_internal.h +++ b/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; diff --git a/driver/vidc/inc/venus_hfi.h b/driver/vidc/inc/venus_hfi.h index 650e8eb305..48f759dabc 100644 --- a/driver/vidc/inc/venus_hfi.h +++ b/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_ diff --git a/driver/vidc/src/msm_vidc_driver.c b/driver/vidc/src/msm_vidc_driver.c index 01761be851..b6beae1710 100644 --- a/driver/vidc/src/msm_vidc_driver.c +++ b/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; } diff --git a/driver/vidc/src/msm_vidc_probe.c b/driver/vidc/src/msm_vidc_probe.c index 01cfa57626..fd9f4765e5 100644 --- a/driver/vidc/src/msm_vidc_probe.c +++ b/driver/vidc/src/msm_vidc_probe.c @@ -806,6 +806,7 @@ static int msm_vidc_pm_suspend(struct device *dev) { int rc = 0; struct msm_vidc_core *core; + bool allow = false; /* * Bail out if @@ -822,15 +823,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; } @@ -854,7 +865,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; } diff --git a/driver/vidc/src/resources.c b/driver/vidc/src/resources.c index 8a2772a562..97de92349b 100644 --- a/driver/vidc/src/resources.c +++ b/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" @@ -666,7 +667,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; } @@ -683,7 +686,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); @@ -729,7 +734,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); } @@ -798,7 +805,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) { diff --git a/driver/vidc/src/venus_hfi.c b/driver/vidc/src/venus_hfi.c index 60e55ebee4..98e99b63a9 100644 --- a/driver/vidc/src/venus_hfi.c +++ b/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 */ diff --git a/driver/vidc/src/venus_hfi_queue.c b/driver/vidc/src/venus_hfi_queue.c index 4fea4fa357..6fe2aaf82f 100644 --- a/driver/vidc/src/venus_hfi_queue.c +++ b/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; diff --git a/driver/vidc/src/venus_hfi_response.c b/driver/vidc/src/venus_hfi_response.c index aa1fb065e8..c7f3ab82fc 100644 --- a/driver/vidc/src/venus_hfi_response.c +++ b/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__);