video: driver: add core sub_state support
Introduce core->sub_state similar to inst->sub_state. [1] pm_suspended - moved to this substate in case of PM suspend [2] handoff - moved to this state after successful handoff_regulator call. [3] fw_power_control - moved to this state in case of IFPC. [4] power_enable - will track core power_on/power_off status. [5] page_fault - used to rate_limit fault logs. [6] cpu_wd - indicates hw fired wd interrupt. [7] video_unresponsive - moved to this state if sync cmd fails. Change-Id: Iceb65cf404fd93aff7846860b0276307e4eab570 Signed-off-by: Govindaraj Rajagopal <quic_grajagop@quicinc.com>
This commit is contained in:
@@ -8,6 +8,7 @@
|
|||||||
#include <linux/iopoll.h>
|
#include <linux/iopoll.h>
|
||||||
|
|
||||||
#include "msm_vidc_core.h"
|
#include "msm_vidc_core.h"
|
||||||
|
#include "msm_vidc_driver.h"
|
||||||
#include "msm_vidc_debug.h"
|
#include "msm_vidc_debug.h"
|
||||||
#include "msm_vidc_variant.h"
|
#include "msm_vidc_variant.h"
|
||||||
#include "msm_vidc_platform.h"
|
#include "msm_vidc_platform.h"
|
||||||
@@ -44,7 +45,7 @@ int __write_register(struct msm_vidc_core *core, u32 reg, u32 value)
|
|||||||
if (rc)
|
if (rc)
|
||||||
return 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");
|
d_vpr_e("HFI Write register failed : Power is OFF\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@@ -83,7 +84,7 @@ int __write_register_masked(struct msm_vidc_core *core, u32 reg, u32 value,
|
|||||||
if (rc)
|
if (rc)
|
||||||
return 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",
|
d_vpr_e("%s: register write failed, power is off\n",
|
||||||
__func__);
|
__func__);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -121,7 +122,7 @@ int __read_register(struct msm_vidc_core *core, u32 reg, u32 *value)
|
|||||||
return -EINVAL;
|
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");
|
d_vpr_e("HFI Read register failed : Power is OFF\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@@ -152,7 +153,7 @@ int __read_register_with_poll_timeout(struct msm_vidc_core *core, u32 reg,
|
|||||||
return -EINVAL;
|
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__);
|
d_vpr_e("%s failed: Power is OFF\n", __func__);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@@ -252,7 +252,7 @@ static int __power_off_iris2_hardware(struct msm_vidc_core *core)
|
|||||||
int rc = 0, i;
|
int rc = 0, i;
|
||||||
u32 value = 0;
|
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__);
|
d_vpr_h("%s: hardware power control enabled\n", __func__);
|
||||||
goto disable_power;
|
goto disable_power;
|
||||||
}
|
}
|
||||||
@@ -417,7 +417,7 @@ static int __power_off_iris2(struct msm_vidc_core *core)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!core->power_enabled)
|
if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -442,7 +442,7 @@ static int __power_off_iris2(struct msm_vidc_core *core)
|
|||||||
disable_irq_nosync(core->resource->irq);
|
disable_irq_nosync(core->resource->irq);
|
||||||
core->intr_status = 0;
|
core->intr_status = 0;
|
||||||
|
|
||||||
core->power_enabled = false;
|
msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE, 0, __func__);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -504,9 +504,15 @@ static int __power_on_iris2(struct msm_vidc_core *core)
|
|||||||
u32 freq = 0;
|
u32 freq = 0;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
if (core->power_enabled)
|
if (is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE))
|
||||||
return 0;
|
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 */
|
/* Vote for all hardware resources */
|
||||||
rc = call_res_op(core, set_bw, core, INT_MAX, INT_MAX);
|
rc = call_res_op(core, set_bw, core, INT_MAX, INT_MAX);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
@@ -526,7 +532,9 @@ static int __power_on_iris2(struct msm_vidc_core *core)
|
|||||||
goto fail_power_on_hardware;
|
goto fail_power_on_hardware;
|
||||||
}
|
}
|
||||||
/* video controller and hardware powered on successfully */
|
/* 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_tbl = core->resource->freq_set.freq_tbl;
|
||||||
freq = core->power.clk_freq ? core->power.clk_freq :
|
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;
|
return rc;
|
||||||
|
|
||||||
|
fail_power_on_substate:
|
||||||
|
__power_off_iris2_hardware(core);
|
||||||
fail_power_on_hardware:
|
fail_power_on_hardware:
|
||||||
__power_off_iris2_controller(core);
|
__power_off_iris2_controller(core);
|
||||||
fail_power_on_controller:
|
fail_power_on_controller:
|
||||||
call_res_op(core, set_bw, core, 0, 0);
|
call_res_op(core, set_bw, core, 0, 0);
|
||||||
fail_vote_buses:
|
fail_vote_buses:
|
||||||
core->power_enabled = false;
|
msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE, 0, __func__);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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
|
* Incase hw power control is enabled, for both CPU WD, video
|
||||||
* hw unresponsive cases, check for power status to decide on
|
* hw unresponsive cases, check for power status to decide on
|
||||||
* executing NOC reset sequence before disabling power. If there
|
* 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.
|
* 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);
|
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) {
|
if (pwr_collapsed) {
|
||||||
d_vpr_e("%s: video hw power collapsed %d, %d\n",
|
d_vpr_e("%s: video hw power collapsed %s\n",
|
||||||
__func__, core->cpu_watchdog, core->video_unresponsive);
|
__func__, core->sub_state_name);
|
||||||
goto disable_power;
|
goto disable_power;
|
||||||
} else {
|
} else {
|
||||||
d_vpr_e("%s: video hw is power ON %d, %d\n",
|
d_vpr_e("%s: video hw is power ON %s\n",
|
||||||
__func__, core->cpu_watchdog, core->video_unresponsive);
|
__func__, core->sub_state_name);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!pwr_collapsed)
|
if (!pwr_collapsed)
|
||||||
d_vpr_e("%s: video hw is not power collapsed\n", __func__);
|
d_vpr_e("%s: video hw is not power collapsed\n", __func__);
|
||||||
|
|
||||||
|
d_vpr_h("%s: disabling hw power\n", __func__);
|
||||||
goto disable_power;
|
goto disable_power;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -465,7 +467,7 @@ static int __power_off_iris3(struct msm_vidc_core *core)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!core->power_enabled)
|
if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -490,7 +492,7 @@ static int __power_off_iris3(struct msm_vidc_core *core)
|
|||||||
disable_irq_nosync(core->resource->irq);
|
disable_irq_nosync(core->resource->irq);
|
||||||
core->intr_status = 0;
|
core->intr_status = 0;
|
||||||
|
|
||||||
core->power_enabled = false;
|
msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE, 0, __func__);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -552,9 +554,15 @@ static int __power_on_iris3(struct msm_vidc_core *core)
|
|||||||
u32 freq = 0;
|
u32 freq = 0;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
if (core->power_enabled)
|
if (is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE))
|
||||||
return 0;
|
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 */
|
/* Vote for all hardware resources */
|
||||||
rc = call_res_op(core, set_bw, core, INT_MAX, INT_MAX);
|
rc = call_res_op(core, set_bw, core, INT_MAX, INT_MAX);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
@@ -574,7 +582,9 @@ static int __power_on_iris3(struct msm_vidc_core *core)
|
|||||||
goto fail_power_on_hardware;
|
goto fail_power_on_hardware;
|
||||||
}
|
}
|
||||||
/* video controller and hardware powered on successfully */
|
/* 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_tbl = core->resource->freq_set.freq_tbl;
|
||||||
freq = core->power.clk_freq ? core->power.clk_freq :
|
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;
|
return rc;
|
||||||
|
|
||||||
|
fail_power_on_substate:
|
||||||
|
__power_off_iris3_hardware(core);
|
||||||
fail_power_on_hardware:
|
fail_power_on_hardware:
|
||||||
__power_off_iris3_controller(core);
|
__power_off_iris3_controller(core);
|
||||||
fail_power_on_controller:
|
fail_power_on_controller:
|
||||||
call_res_op(core, set_bw, core, 0, 0);
|
call_res_op(core, set_bw, core, 0, 0);
|
||||||
fail_vote_buses:
|
fail_vote_buses:
|
||||||
core->power_enabled = false;
|
msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE, 0, __func__);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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
|
* Incase hw power control is enabled, for both CPU WD, video
|
||||||
* hw unresponsive cases, check for power status to decide on
|
* hw unresponsive cases, check for power status to decide on
|
||||||
* executing NOC reset sequence before disabling power. If there
|
* 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.
|
* 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);
|
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) {
|
if (pwr_collapsed) {
|
||||||
d_vpr_e("%s: video hw power collapsed %d, %d\n",
|
d_vpr_e("%s: video hw power collapsed %s\n",
|
||||||
__func__, core->cpu_watchdog, core->video_unresponsive);
|
__func__, core->sub_state_name);
|
||||||
goto disable_power;
|
goto disable_power;
|
||||||
} else {
|
} else {
|
||||||
d_vpr_e("%s: video hw is power ON %d, %d\n",
|
d_vpr_e("%s: video hw is power ON %s\n",
|
||||||
__func__, core->cpu_watchdog, core->video_unresponsive);
|
__func__, core->sub_state_name);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!pwr_collapsed)
|
if (!pwr_collapsed)
|
||||||
d_vpr_e("%s: video hw is not power collapsed\n", __func__);
|
d_vpr_e("%s: video hw is not power collapsed\n", __func__);
|
||||||
|
|
||||||
|
d_vpr_h("%s: disabling hw power\n", __func__);
|
||||||
goto disable_power;
|
goto disable_power;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -530,7 +532,7 @@ static int __power_off_iris33(struct msm_vidc_core *core)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!core->power_enabled)
|
if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -555,7 +557,7 @@ static int __power_off_iris33(struct msm_vidc_core *core)
|
|||||||
disable_irq_nosync(core->resource->irq);
|
disable_irq_nosync(core->resource->irq);
|
||||||
core->intr_status = 0;
|
core->intr_status = 0;
|
||||||
|
|
||||||
core->power_enabled = false;
|
msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE, 0, __func__);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -633,9 +635,15 @@ static int __power_on_iris33(struct msm_vidc_core *core)
|
|||||||
u32 freq = 0;
|
u32 freq = 0;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
if (core->power_enabled)
|
if (is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE))
|
||||||
return 0;
|
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 */
|
/* Vote for all hardware resources */
|
||||||
rc = call_res_op(core, set_bw, core, INT_MAX, INT_MAX);
|
rc = call_res_op(core, set_bw, core, INT_MAX, INT_MAX);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
@@ -655,7 +663,9 @@ static int __power_on_iris33(struct msm_vidc_core *core)
|
|||||||
goto fail_power_on_hardware;
|
goto fail_power_on_hardware;
|
||||||
}
|
}
|
||||||
/* video controller and hardware powered on successfully */
|
/* 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_tbl = core->resource->freq_set.freq_tbl;
|
||||||
freq = core->power.clk_freq ? core->power.clk_freq :
|
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;
|
return rc;
|
||||||
|
|
||||||
|
fail_power_on_substate:
|
||||||
|
__power_off_iris33_hardware(core);
|
||||||
fail_power_on_hardware:
|
fail_power_on_hardware:
|
||||||
__power_off_iris33_controller(core);
|
__power_off_iris33_controller(core);
|
||||||
fail_power_on_controller:
|
fail_power_on_controller:
|
||||||
call_res_op(core, set_bw, core, 0, 0);
|
call_res_op(core, set_bw, core, 0, 0);
|
||||||
fail_vote_buses:
|
fail_vote_buses:
|
||||||
core->power_enabled = false;
|
msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE, 0, __func__);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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_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 msm_vidc_core {
|
||||||
struct platform_device *pdev;
|
struct platform_device *pdev;
|
||||||
struct msm_video_device vdev[2];
|
struct msm_video_device vdev[2];
|
||||||
@@ -76,13 +88,14 @@ struct msm_vidc_core {
|
|||||||
struct dentry *debugfs_root;
|
struct dentry *debugfs_root;
|
||||||
char fw_version[MAX_NAME_LENGTH];
|
char fw_version[MAX_NAME_LENGTH];
|
||||||
enum msm_vidc_core_state state;
|
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 mutex lock;
|
||||||
struct msm_vidc_resource *resource;
|
struct msm_vidc_resource *resource;
|
||||||
struct msm_vidc_platform *platform;
|
struct msm_vidc_platform *platform;
|
||||||
u32 intr_status;
|
u32 intr_status;
|
||||||
u32 spur_count;
|
u32 spur_count;
|
||||||
u32 reg_count;
|
u32 reg_count;
|
||||||
bool power_enabled;
|
|
||||||
u32 codecs_count;
|
u32 codecs_count;
|
||||||
struct msm_vidc_core_capability *capabilities;
|
struct msm_vidc_core_capability *capabilities;
|
||||||
struct msm_vidc_inst_capability *inst_caps;
|
struct msm_vidc_inst_capability *inst_caps;
|
||||||
@@ -96,7 +109,6 @@ struct msm_vidc_core {
|
|||||||
struct work_struct ssr_work;
|
struct work_struct ssr_work;
|
||||||
struct msm_vidc_core_power power;
|
struct msm_vidc_core_power power;
|
||||||
struct msm_vidc_ssr ssr;
|
struct msm_vidc_ssr ssr;
|
||||||
bool smmu_fault_handled;
|
|
||||||
u32 skip_pc_count;
|
u32 skip_pc_count;
|
||||||
u32 last_packet_type;
|
u32 last_packet_type;
|
||||||
u8 *packet;
|
u8 *packet;
|
||||||
@@ -117,11 +129,11 @@ struct msm_vidc_core {
|
|||||||
u32 header_id;
|
u32 header_id;
|
||||||
u32 packet_id;
|
u32 packet_id;
|
||||||
u32 sys_init_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_
|
#endif // _MSM_VIDC_CORE_H_
|
||||||
|
@@ -370,6 +370,17 @@ static inline bool is_sub_state(struct msm_vidc_inst *inst,
|
|||||||
return (inst->sub_state & sub_state);
|
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 *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_pixelfmt_name(struct msm_vidc_inst *inst, u32 pixelfmt);
|
||||||
const char *v4l2_type_name(u32 port);
|
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_get_inst_capability(struct msm_vidc_inst *inst);
|
||||||
int msm_vidc_change_core_state(struct msm_vidc_core *core,
|
int msm_vidc_change_core_state(struct msm_vidc_core *core,
|
||||||
enum msm_vidc_core_state request_state, const char *func);
|
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(struct msm_vidc_core *core);
|
||||||
int msm_vidc_core_init_wait(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);
|
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);
|
void msm_vidc_stability_handler(struct work_struct *work);
|
||||||
int cancel_stability_work_sync(struct msm_vidc_inst *inst);
|
int cancel_stability_work_sync(struct msm_vidc_inst *inst);
|
||||||
void msm_vidc_fw_unload_handler(struct work_struct *work);
|
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);
|
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_init(struct msm_vidc_inst *inst);
|
||||||
int msm_vidc_event_queue_deinit(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);
|
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_drain_last_flag(struct msm_vidc_inst *inst);
|
||||||
bool msm_vidc_allow_psc_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_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_streamoff(struct msm_vidc_inst *inst, u32 type);
|
||||||
int msm_vidc_state_change_input_psc(struct msm_vidc_inst *inst);
|
int msm_vidc_state_change_input_psc(struct msm_vidc_inst *inst);
|
||||||
|
@@ -949,7 +949,6 @@ struct msm_vidc_input_timer {
|
|||||||
enum msm_vidc_allow FOREACH_ALLOW(GENERATE_ENUM);
|
enum msm_vidc_allow FOREACH_ALLOW(GENERATE_ENUM);
|
||||||
|
|
||||||
struct msm_vidc_ssr {
|
struct msm_vidc_ssr {
|
||||||
bool trigger;
|
|
||||||
enum msm_vidc_ssr_trigger_type ssr_type;
|
enum msm_vidc_ssr_trigger_type ssr_type;
|
||||||
u32 sub_client_id;
|
u32 sub_client_id;
|
||||||
u32 test_addr;
|
u32 test_addr;
|
||||||
|
@@ -73,6 +73,5 @@ irqreturn_t venus_hfi_isr(int irq, void *data);
|
|||||||
irqreturn_t venus_hfi_isr_handler(int irq, void *data);
|
irqreturn_t venus_hfi_isr_handler(int irq, void *data);
|
||||||
|
|
||||||
int __prepare_pc(struct msm_vidc_core *core);
|
int __prepare_pc(struct msm_vidc_core *core);
|
||||||
bool __core_in_valid_state(struct msm_vidc_core *core);
|
|
||||||
|
|
||||||
#endif // _VENUS_HFI_H_
|
#endif // _VENUS_HFI_H_
|
||||||
|
@@ -146,6 +146,23 @@ exit:
|
|||||||
return name;
|
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)
|
const char *v4l2_type_name(u32 port)
|
||||||
{
|
{
|
||||||
switch (port) {
|
switch (port) {
|
||||||
@@ -304,7 +321,7 @@ static u32 msm_vidc_get_buffer_stats_flag(struct msm_vidc_inst *inst)
|
|||||||
return flags;
|
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;
|
int rc = 0;
|
||||||
|
|
||||||
@@ -1027,6 +1044,53 @@ int msm_vidc_change_core_state(struct msm_vidc_core *core,
|
|||||||
return 0;
|
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,
|
int msm_vidc_change_state(struct msm_vidc_inst *inst,
|
||||||
enum msm_vidc_state request_state, const char *func)
|
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;
|
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 is_hevc_10bit_decode_session(struct msm_vidc_inst *inst)
|
||||||
{
|
{
|
||||||
bool is10bit = false;
|
bool is10bit = false;
|
||||||
@@ -4640,7 +4727,7 @@ int msm_vidc_core_deinit_locked(struct msm_vidc_core *core, bool force)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (core->state == MSM_VIDC_CORE_DEINIT)
|
if (is_core_state(core, MSM_VIDC_CORE_DEINIT))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (force) {
|
if (force) {
|
||||||
@@ -4693,10 +4780,10 @@ int msm_vidc_core_init_wait(struct msm_vidc_core *core)
|
|||||||
}
|
}
|
||||||
|
|
||||||
core_lock(core, __func__);
|
core_lock(core, __func__);
|
||||||
if (core->state == MSM_VIDC_CORE_INIT) {
|
if (is_core_state(core, MSM_VIDC_CORE_INIT)) {
|
||||||
rc = 0;
|
rc = 0;
|
||||||
goto unlock;
|
goto unlock;
|
||||||
} else if (core->state == MSM_VIDC_CORE_DEINIT) {
|
} else if (is_core_state(core, MSM_VIDC_CORE_DEINIT)) {
|
||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
goto unlock;
|
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__,
|
d_vpr_h("%s: state %s, interval %u, count %u, max_tries %u\n", __func__,
|
||||||
core_state_name(core->state), interval, count, max_tries);
|
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__);
|
d_vpr_h("%s: sys init successful\n", __func__);
|
||||||
rc = 0;
|
rc = 0;
|
||||||
goto unlock;
|
goto unlock;
|
||||||
} else {
|
} else {
|
||||||
d_vpr_h("%s: sys init wait timedout. state %s\n",
|
d_vpr_h("%s: sys init wait timedout. state %s\n",
|
||||||
__func__, core_state_name(core->state));
|
__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;
|
rc = -EINVAL;
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
@@ -4743,14 +4832,14 @@ int msm_vidc_core_init(struct msm_vidc_core *core)
|
|||||||
}
|
}
|
||||||
|
|
||||||
core_lock(core, __func__);
|
core_lock(core, __func__);
|
||||||
if (core->state == MSM_VIDC_CORE_INIT ||
|
if (is_core_state(core, MSM_VIDC_CORE_INIT) ||
|
||||||
core->state == MSM_VIDC_CORE_INIT_WAIT)
|
is_core_state(core, MSM_VIDC_CORE_INIT_WAIT))
|
||||||
goto unlock;
|
goto unlock;
|
||||||
|
|
||||||
msm_vidc_change_core_state(core, MSM_VIDC_CORE_INIT_WAIT, __func__);
|
msm_vidc_change_core_state(core, MSM_VIDC_CORE_INIT_WAIT, __func__);
|
||||||
core->smmu_fault_handled = false;
|
/* clear PM suspend from core sub_state */
|
||||||
core->ssr.trigger = false;
|
msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_PM_SUSPEND, 0, __func__);
|
||||||
core->pm_suspended = false;
|
msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_PAGE_FAULT, 0, __func__);
|
||||||
|
|
||||||
rc = venus_hfi_core_init(core);
|
rc = venus_hfi_core_init(core);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
@@ -4798,7 +4887,8 @@ int msm_vidc_inst_timeout(struct msm_vidc_inst *inst)
|
|||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
/* mark video hw unresponsive */
|
/* 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 */
|
/* call core deinit for a valid instance timeout case */
|
||||||
msm_vidc_core_deinit_locked(core, true);
|
msm_vidc_core_deinit_locked(core, true);
|
||||||
@@ -4938,7 +5028,7 @@ int msm_vidc_smmu_fault_handler(struct iommu_domain *domain,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (core->smmu_fault_handled) {
|
if (is_core_sub_state(core, CORE_SUBSTATE_PAGE_FAULT)) {
|
||||||
if (core->capabilities[NON_FATAL_FAULTS].value) {
|
if (core->capabilities[NON_FATAL_FAULTS].value) {
|
||||||
dprintk_ratelimit(VIDC_ERR, "err ",
|
dprintk_ratelimit(VIDC_ERR, "err ",
|
||||||
"%s: non-fatal pagefault address: %lx\n",
|
"%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);
|
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 */
|
/* print noc error log registers */
|
||||||
venus_hfi_noc_error_info(core);
|
venus_hfi_noc_error_info(core);
|
||||||
@@ -5005,20 +5096,17 @@ void msm_vidc_ssr_handler(struct work_struct *work)
|
|||||||
ssr = &core->ssr;
|
ssr = &core->ssr;
|
||||||
|
|
||||||
core_lock(core, __func__);
|
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
|
* In current implementation, user-initiated SSR triggers
|
||||||
* a fatal error from hardware. However, there is no way
|
* a fatal error from hardware. However, there is no way
|
||||||
* to know if fatal error is due to SSR or not. Handle
|
* to know if fatal error is due to SSR or not. Handle
|
||||||
* user SSR as non-fatal.
|
* user SSR as non-fatal.
|
||||||
*/
|
*/
|
||||||
core->ssr.trigger = true;
|
|
||||||
rc = venus_hfi_trigger_ssr(core, ssr->ssr_type,
|
rc = venus_hfi_trigger_ssr(core, ssr->ssr_type,
|
||||||
ssr->sub_client_id, ssr->test_addr);
|
ssr->sub_client_id, ssr->test_addr);
|
||||||
if (rc) {
|
if (rc)
|
||||||
d_vpr_e("%s: trigger_ssr failed\n", __func__);
|
d_vpr_e("%s: trigger_ssr failed\n", __func__);
|
||||||
core->ssr.trigger = false;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
d_vpr_e("%s: video core not initialized\n", __func__);
|
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)
|
void msm_vidc_batch_handler(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct msm_vidc_inst *inst;
|
struct msm_vidc_inst *inst;
|
||||||
@@ -5155,7 +5223,7 @@ void msm_vidc_batch_handler(struct work_struct *work)
|
|||||||
goto exit;
|
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__);
|
i_vpr_h(inst, "%s: device in pm suspend state\n", __func__);
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
@@ -806,6 +806,7 @@ static int msm_vidc_pm_suspend(struct device *dev)
|
|||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
struct msm_vidc_core *core;
|
struct msm_vidc_core *core;
|
||||||
|
bool allow = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Bail out if
|
* Bail out if
|
||||||
@@ -822,15 +823,25 @@ static int msm_vidc_pm_suspend(struct device *dev)
|
|||||||
return -EINVAL;
|
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__);
|
d_vpr_h("%s\n", __func__);
|
||||||
rc = msm_vidc_suspend(core);
|
rc = msm_vidc_suspend_locked(core);
|
||||||
if (rc == -ENOTSUPP)
|
if (rc == -ENOTSUPP)
|
||||||
rc = 0;
|
rc = 0;
|
||||||
else if (rc)
|
else if (rc)
|
||||||
d_vpr_e("Failed to suspend: %d\n", rc);
|
d_vpr_e("Failed to suspend: %d\n", rc);
|
||||||
else
|
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;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -854,7 +865,12 @@ static int msm_vidc_pm_resume(struct device *dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
d_vpr_h("%s\n", __func__);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -16,6 +16,7 @@
|
|||||||
#include "msm_vidc_core.h"
|
#include "msm_vidc_core.h"
|
||||||
#include "msm_vidc_debug.h"
|
#include "msm_vidc_debug.h"
|
||||||
#include "msm_vidc_power.h"
|
#include "msm_vidc_power.h"
|
||||||
|
#include "msm_vidc_driver.h"
|
||||||
#include "msm_vidc_platform.h"
|
#include "msm_vidc_platform.h"
|
||||||
#include "venus_hfi.h"
|
#include "venus_hfi.h"
|
||||||
|
|
||||||
@@ -666,7 +667,9 @@ static int __acquire_regulator(struct msm_vidc_core *core,
|
|||||||
|
|
||||||
if (regulator_get_mode(rinfo->regulator) ==
|
if (regulator_get_mode(rinfo->regulator) ==
|
||||||
REGULATOR_MODE_NORMAL) {
|
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);
|
d_vpr_h("Skip acquire regulator %s\n", rinfo->name);
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
@@ -683,7 +686,9 @@ static int __acquire_regulator(struct msm_vidc_core *core,
|
|||||||
rinfo->name);
|
rinfo->name);
|
||||||
goto exit;
|
goto exit;
|
||||||
} else {
|
} 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",
|
d_vpr_h("Acquired regulator control from HW: %s\n",
|
||||||
rinfo->name);
|
rinfo->name);
|
||||||
|
|
||||||
@@ -729,7 +734,9 @@ static int __hand_off_regulator(struct msm_vidc_core *core,
|
|||||||
rinfo->name);
|
rinfo->name);
|
||||||
return rc;
|
return rc;
|
||||||
} else {
|
} 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",
|
d_vpr_h("Hand off regulator control to HW: %s\n",
|
||||||
rinfo->name);
|
rinfo->name);
|
||||||
}
|
}
|
||||||
@@ -798,7 +805,8 @@ static int __disable_regulator(struct msm_vidc_core *core, const char *reg_name)
|
|||||||
WARN_ON(true);
|
WARN_ON(true);
|
||||||
return rc;
|
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);
|
rc = regulator_disable(rinfo->regulator);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
|
@@ -59,11 +59,6 @@ static int __strict_check(struct msm_vidc_core *core, const char *function)
|
|||||||
return fatal ? -EINVAL : 0;
|
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,
|
static bool __valdiate_session(struct msm_vidc_core *core,
|
||||||
struct msm_vidc_inst *inst, const char *func)
|
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;
|
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",
|
d_vpr_e("%s: skipping as power control hanfoff was not done\n",
|
||||||
__func__);
|
__func__);
|
||||||
return rc;
|
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,
|
rc = hfi_packet_sys_intraframe_powercollapse(core,
|
||||||
core->packet, core->packet_size, enable);
|
core->packet, core->packet_size, enable);
|
||||||
if (rc)
|
if (rc)
|
||||||
@@ -268,7 +269,10 @@ static int __sys_set_power_control(struct msm_vidc_core *core, bool enable)
|
|||||||
if (rc)
|
if (rc)
|
||||||
return 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__);
|
d_vpr_h("%s: set hardware power control successful\n", __func__);
|
||||||
|
|
||||||
return rc;
|
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__);
|
d_vpr_e("%s: invalid params\n", __func__);
|
||||||
return -EINVAL;
|
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__);
|
d_vpr_h("%s: Power already disabled\n", __func__);
|
||||||
goto exit;
|
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__);
|
d_vpr_e("%s: Core not in init state\n", __func__);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@@ -534,7 +538,7 @@ static int __venus_power_off(struct msm_vidc_core* core)
|
|||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
if (!core->power_enabled)
|
if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
rc = call_venus_op(core, power_off, core);
|
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);
|
d_vpr_e("Failed to power off, err: %d\n", rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
core->power_enabled = false;
|
msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE, 0, __func__);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -551,7 +555,7 @@ static int __venus_power_on(struct msm_vidc_core *core)
|
|||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
if (core->power_enabled)
|
if (is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
rc = call_venus_op(core, power_on, core);
|
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);
|
d_vpr_e("Failed to power on, err: %d\n", rc);
|
||||||
return 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;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -571,7 +578,7 @@ static int __suspend(struct msm_vidc_core *core)
|
|||||||
if (!core) {
|
if (!core) {
|
||||||
d_vpr_e("%s: invalid params\n", __func__);
|
d_vpr_e("%s: invalid params\n", __func__);
|
||||||
return -EINVAL;
|
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");
|
d_vpr_h("Power already disabled\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -605,9 +612,9 @@ static int __resume(struct msm_vidc_core *core)
|
|||||||
if (!core) {
|
if (!core) {
|
||||||
d_vpr_e("%s: invalid params\n", __func__);
|
d_vpr_e("%s: invalid params\n", __func__);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
} else if (core->power_enabled) {
|
} else if (is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE)) {
|
||||||
goto exit;
|
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__);
|
d_vpr_e("%s: core not in valid state\n", __func__);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@@ -617,8 +624,14 @@ static int __resume(struct msm_vidc_core *core)
|
|||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
d_vpr_h("Resuming from power collapse\n");
|
d_vpr_h("Resuming from power collapse\n");
|
||||||
core->handoff_done = false;
|
/* reset handoff done from core sub_state */
|
||||||
core->hw_power_control = false;
|
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);
|
rc = __venus_power_on(core);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
@@ -684,10 +697,8 @@ int __load_fw(struct msm_vidc_core *core)
|
|||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
d_vpr_h("%s\n", __func__);
|
d_vpr_h("%s\n", __func__);
|
||||||
core->handoff_done = false;
|
/* clear all substates */
|
||||||
core->hw_power_control = false;
|
msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_MAX - 1, 0, __func__);
|
||||||
core->cpu_watchdog = false;
|
|
||||||
core->video_unresponsive = false;
|
|
||||||
|
|
||||||
trace_msm_v4l2_vidc_fw_load("START");
|
trace_msm_v4l2_vidc_fw_load("START");
|
||||||
rc = __venus_power_on(core);
|
rc = __venus_power_on(core);
|
||||||
@@ -726,8 +737,8 @@ void __unload_fw(struct msm_vidc_core *core)
|
|||||||
fw_unload(core);
|
fw_unload(core);
|
||||||
__venus_power_off(core);
|
__venus_power_off(core);
|
||||||
|
|
||||||
core->cpu_watchdog = false;
|
/* clear all substates */
|
||||||
core->video_unresponsive = false;
|
msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_MAX - 1, 0, __func__);
|
||||||
|
|
||||||
d_vpr_h("%s done\n", __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)) {
|
if (call_venus_op(core, watchdog, core, core->intr_status)) {
|
||||||
struct hfi_packet pkt = {.type = HFI_SYS_ERROR_WD_TIMEOUT};
|
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__);
|
d_vpr_e("%s: CPU WD error received\n", __func__);
|
||||||
|
|
||||||
return handle_system_error(core, &pkt);
|
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",
|
d_vpr_e("Failed to PC for %d times\n",
|
||||||
core->skip_pc_count);
|
core->skip_pc_count);
|
||||||
core->skip_pc_count = 0;
|
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);
|
msm_vidc_core_deinit(core, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
core_lock(core, __func__);
|
core_lock(core, __func__);
|
||||||
/* core already deinited - skip power collapse */
|
/* core already deinited - skip power collapse */
|
||||||
if (core->state == MSM_VIDC_CORE_DEINIT) {
|
if (is_core_state(core, MSM_VIDC_CORE_DEINIT)) {
|
||||||
d_vpr_e("%s: core is already de-inited\n", __func__);
|
d_vpr_e("%s: invalid core state %s\n",
|
||||||
|
__func__, core_state_name(core->state));
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -962,7 +979,7 @@ int venus_hfi_core_deinit(struct msm_vidc_core *core, bool force)
|
|||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
if (core->state == MSM_VIDC_CORE_DEINIT)
|
if (is_core_state(core, MSM_VIDC_CORE_DEINIT))
|
||||||
return 0;
|
return 0;
|
||||||
__resume(core);
|
__resume(core);
|
||||||
__flush_debug_queue(core, (!force ? core->packet : NULL), core->packet_size);
|
__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;
|
return 0;
|
||||||
|
|
||||||
core_lock(core, __func__);
|
core_lock(core, __func__);
|
||||||
if (core->state == MSM_VIDC_CORE_DEINIT)
|
if (is_core_state(core, MSM_VIDC_CORE_DEINIT))
|
||||||
goto unlock;
|
goto unlock;
|
||||||
|
|
||||||
/* resume venus before accessing noc registers */
|
/* resume venus before accessing noc registers */
|
||||||
|
@@ -22,11 +22,6 @@ static int __strict_check(struct msm_vidc_core *core, const char *function)
|
|||||||
return fatal ? -EINVAL : 0;
|
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)
|
static void __set_queue_hdr_defaults(struct hfi_queue_header *q_hdr)
|
||||||
{
|
{
|
||||||
q_hdr->qhdr_status = 0x1;
|
q_hdr->qhdr_status = 0x1;
|
||||||
@@ -290,7 +285,7 @@ static int __iface_cmdq_write_relaxed(struct msm_vidc_core *core,
|
|||||||
if (rc)
|
if (rc)
|
||||||
return 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__);
|
d_vpr_e("%s: fw not in init state\n", __func__);
|
||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
goto err_q_null;
|
goto err_q_null;
|
||||||
@@ -355,7 +350,7 @@ int venus_hfi_queue_msg_read(struct msm_vidc_core *core, void *pkt)
|
|||||||
return -EINVAL;
|
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__);
|
d_vpr_e("%s: fw not in init state\n", __func__);
|
||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
goto read_error_null;
|
goto read_error_null;
|
||||||
|
@@ -495,7 +495,7 @@ static int handle_system_init(struct msm_vidc_core *core,
|
|||||||
{
|
{
|
||||||
if (pkt->flags & HFI_FW_FLAGS_SUCCESS) {
|
if (pkt->flags & HFI_FW_FLAGS_SUCCESS) {
|
||||||
core_lock(core, __func__);
|
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) {
|
pkt->packet_id == core->sys_init_id) {
|
||||||
msm_vidc_change_core_state(core, MSM_VIDC_CORE_INIT, __func__);
|
msm_vidc_change_core_state(core, MSM_VIDC_CORE_INIT, __func__);
|
||||||
d_vpr_h("%s: successful\n", __func__);
|
d_vpr_h("%s: successful\n", __func__);
|
||||||
|
Reference in New Issue
Block a user