video: driver: amend xo reset clock as shared resource
Use devm_reset_control_get_exclusive_released() instead of devm_reset_control_get() to get the reset control of video_xo_reset clock as it is shared reset clock between eva and video drivers. Use reset_control_acquire() before assert and reset_control_release() after de-assert video_xo_reset clock to avoid eva driver operating on it in parallel. Change-Id: I4936ed7a4556bb56d4b28546084fc877080308ef Signed-off-by: Deepa Guthyappa Madivalara <quic_dmadival@quicinc.com> Signed-off-by: Darshana Patil <quic_darshana@quicinc.com>
This commit is contained in:
@@ -2314,9 +2314,9 @@ static const struct clk_table anorak_clk_table[] = {
|
|||||||
{ "video_cc_mvs0_clk_src", VIDEO_CC_MVS0_CLK_SRC, 1 },
|
{ "video_cc_mvs0_clk_src", VIDEO_CC_MVS0_CLK_SRC, 1 },
|
||||||
};
|
};
|
||||||
|
|
||||||
/* name */
|
/* name, exclusive_release */
|
||||||
static const struct clk_rst_table anorak_clk_reset_table[] = {
|
static const struct clk_rst_table anorak_clk_reset_table[] = {
|
||||||
{ "video_axi_reset" },
|
{ "video_axi_reset", 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
/* name, llcc_id */
|
/* name, llcc_id */
|
||||||
|
@@ -60,6 +60,7 @@ struct clk_table {
|
|||||||
|
|
||||||
struct clk_rst_table {
|
struct clk_rst_table {
|
||||||
const char *name;
|
const char *name;
|
||||||
|
bool exclusive_release;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct subcache_table {
|
struct subcache_table {
|
||||||
|
@@ -2514,9 +2514,9 @@ static const struct clk_table kalama_clk_table[] = {
|
|||||||
{ "video_cc_mvs0_clk_src", VIDEO_CC_MVS0_CLK_SRC, 1 },
|
{ "video_cc_mvs0_clk_src", VIDEO_CC_MVS0_CLK_SRC, 1 },
|
||||||
};
|
};
|
||||||
|
|
||||||
/* name */
|
/* name, exclusive_release */
|
||||||
static const struct clk_rst_table kalama_clk_reset_table[] = {
|
static const struct clk_rst_table kalama_clk_reset_table[] = {
|
||||||
{ "video_axi_reset" },
|
{ "video_axi_reset", 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
/* name, llcc_id */
|
/* name, llcc_id */
|
||||||
|
@@ -2547,11 +2547,11 @@ static const struct clk_table pineapple_clk_table[] = {
|
|||||||
{ "video_cc_mvs0_clk_src", VIDEO_CC_MVS0_CLK_SRC, 1 },
|
{ "video_cc_mvs0_clk_src", VIDEO_CC_MVS0_CLK_SRC, 1 },
|
||||||
};
|
};
|
||||||
|
|
||||||
/* name */
|
/* name, exclusive_release */
|
||||||
static const struct clk_rst_table pineapple_clk_reset_table[] = {
|
static const struct clk_rst_table pineapple_clk_reset_table[] = {
|
||||||
{ "video_axi_reset" },
|
{ "video_axi_reset", 0 },
|
||||||
{ "video_xo_reset" },
|
{ "video_xo_reset", 1 },
|
||||||
{ "video_mvs0c_reset" },
|
{ "video_mvs0c_reset", 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
/* name, llcc_id */
|
/* name, llcc_id */
|
||||||
|
@@ -2060,10 +2060,10 @@ static const struct clk_table waipio_clk_table[] = {
|
|||||||
{ "video_cc_mvs0_clk_src", VIDEO_CC_MVS0_CLK_SRC, 1 },
|
{ "video_cc_mvs0_clk_src", VIDEO_CC_MVS0_CLK_SRC, 1 },
|
||||||
};
|
};
|
||||||
|
|
||||||
/* name */
|
/* name, exclusive_release */
|
||||||
static const struct clk_rst_table waipio_clk_reset_table[] = {
|
static const struct clk_rst_table waipio_clk_reset_table[] = {
|
||||||
{ "video_axi_reset" },
|
{ "video_axi_reset", 0 },
|
||||||
{ "video_core_reset" },
|
{ "video_core_reset", 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
/* name, llcc_id */
|
/* name, llcc_id */
|
||||||
|
@@ -4,6 +4,7 @@
|
|||||||
* Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
|
* Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/reset.h>
|
||||||
#include "msm_vidc_iris33.h"
|
#include "msm_vidc_iris33.h"
|
||||||
#include "msm_vidc_buffer_iris33.h"
|
#include "msm_vidc_buffer_iris33.h"
|
||||||
#include "msm_vidc_power_iris33.h"
|
#include "msm_vidc_power_iris33.h"
|
||||||
@@ -384,6 +385,7 @@ static int __power_off_iris33_controller(struct msm_vidc_core *core)
|
|||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
int value = 0;
|
int value = 0;
|
||||||
|
u32 count = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* mask fal10_veto QLPAC error since fal10_veto can go 1
|
* mask fal10_veto QLPAC error since fal10_veto can go 1
|
||||||
@@ -467,6 +469,28 @@ static int __power_off_iris33_controller(struct msm_vidc_core *core)
|
|||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* need to acquire "video_xo_reset" before assert and release
|
||||||
|
* after de-assert "video_xo_reset" reset clock to avoid other
|
||||||
|
* drivers (eva driver) operating on this shared reset clock
|
||||||
|
* and AON_WRAPPER_SPARE register in parallel.
|
||||||
|
*/
|
||||||
|
count = 0;
|
||||||
|
do {
|
||||||
|
rc = call_res_op(core, reset_control_acquire, core, "video_xo_reset");
|
||||||
|
if (rc) {
|
||||||
|
d_vpr_e("%s: failed to acquire video_xo_reset control\n", __func__);
|
||||||
|
} else {
|
||||||
|
count++;
|
||||||
|
usleep_range(1000, 1000);
|
||||||
|
}
|
||||||
|
} while (rc && count < 100);
|
||||||
|
|
||||||
|
if (count >= 100) {
|
||||||
|
d_vpr_e("%s: timeout acquiring video_xo_reset\n", __func__);
|
||||||
|
goto skip_video_xo_reset;
|
||||||
|
}
|
||||||
|
|
||||||
/* poll AON spare register bit0 to become zero with 50ms timeout */
|
/* poll AON spare register bit0 to become zero with 50ms timeout */
|
||||||
rc = __read_register_with_poll_timeout(core, AON_WRAPPER_SPARE,
|
rc = __read_register_with_poll_timeout(core, AON_WRAPPER_SPARE,
|
||||||
0x1, 0x0, 1000, 50 * 1000);
|
0x1, 0x0, 1000, 50 * 1000);
|
||||||
@@ -500,6 +524,12 @@ static int __power_off_iris33_controller(struct msm_vidc_core *core)
|
|||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
/* release reset control for other consumers */
|
||||||
|
rc = call_res_op(core, reset_control_release, core, "video_xo_reset");
|
||||||
|
if (rc)
|
||||||
|
d_vpr_e("%s: failed to release video_xo_reset reset\n", __func__);
|
||||||
|
|
||||||
|
skip_video_xo_reset:
|
||||||
/* Enable MVP NoC clock */
|
/* Enable MVP NoC clock */
|
||||||
rc = __write_register_masked(core, AON_WRAPPER_MVP_NOC_CORE_CLK_CONTROL,
|
rc = __write_register_masked(core, AON_WRAPPER_MVP_NOC_CORE_CLK_CONTROL,
|
||||||
0x0, BIT(0));
|
0x0, BIT(0));
|
||||||
|
@@ -136,6 +136,7 @@ struct clock_set {
|
|||||||
struct reset_info {
|
struct reset_info {
|
||||||
struct reset_control *rst;
|
struct reset_control *rst;
|
||||||
const char *name;
|
const char *name;
|
||||||
|
bool exclusive_release;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct reset_set {
|
struct reset_set {
|
||||||
@@ -208,6 +209,10 @@ struct msm_vidc_resources_ops {
|
|||||||
int (*init)(struct msm_vidc_core *core);
|
int (*init)(struct msm_vidc_core *core);
|
||||||
|
|
||||||
int (*reset_bridge)(struct msm_vidc_core *core);
|
int (*reset_bridge)(struct msm_vidc_core *core);
|
||||||
|
int (*reset_control_acquire)(struct msm_vidc_core *core,
|
||||||
|
const char *name);
|
||||||
|
int (*reset_control_release)(struct msm_vidc_core *core,
|
||||||
|
const char *name);
|
||||||
int (*reset_control_assert)(struct msm_vidc_core *core,
|
int (*reset_control_assert)(struct msm_vidc_core *core,
|
||||||
const char *name);
|
const char *name);
|
||||||
int (*reset_control_deassert)(struct msm_vidc_core *core,
|
int (*reset_control_deassert)(struct msm_vidc_core *core,
|
||||||
|
@@ -401,17 +401,24 @@ static int __init_reset_clocks(struct msm_vidc_core *core)
|
|||||||
rsts->count = rst_count;
|
rsts->count = rst_count;
|
||||||
|
|
||||||
/* populate clock field from platform data */
|
/* populate clock field from platform data */
|
||||||
for (cnt = 0; cnt < rsts->count; cnt++)
|
for (cnt = 0; cnt < rsts->count; cnt++) {
|
||||||
rsts->reset_tbl[cnt].name = rst_tbl[cnt].name;
|
rsts->reset_tbl[cnt].name = rst_tbl[cnt].name;
|
||||||
|
rsts->reset_tbl[cnt].exclusive_release = rst_tbl[cnt].exclusive_release;
|
||||||
|
}
|
||||||
|
|
||||||
/* print reset clock fields */
|
/* print reset clock fields */
|
||||||
venus_hfi_for_each_reset_clock(core, rinfo) {
|
venus_hfi_for_each_reset_clock(core, rinfo) {
|
||||||
d_vpr_h("%s: reset clk %s\n", __func__, rinfo->name);
|
d_vpr_h("%s: reset clk %s, exclusive %d\n",
|
||||||
|
__func__, rinfo->name, rinfo->exclusive_release);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get reset clock handle */
|
/* get reset clock handle */
|
||||||
venus_hfi_for_each_reset_clock(core, rinfo) {
|
venus_hfi_for_each_reset_clock(core, rinfo) {
|
||||||
rinfo->rst = devm_reset_control_get(&core->pdev->dev, rinfo->name);
|
if (rinfo->exclusive_release)
|
||||||
|
rinfo->rst = devm_reset_control_get_exclusive_released(
|
||||||
|
&core->pdev->dev, rinfo->name);
|
||||||
|
else
|
||||||
|
rinfo->rst = devm_reset_control_get(&core->pdev->dev, rinfo->name);
|
||||||
if (IS_ERR_OR_NULL(rinfo->rst)) {
|
if (IS_ERR_OR_NULL(rinfo->rst)) {
|
||||||
d_vpr_e("%s: failed to get reset clock: %s\n", __func__, rinfo->name);
|
d_vpr_e("%s: failed to get reset clock: %s\n", __func__, rinfo->name);
|
||||||
rc = PTR_ERR(rinfo->rst) ?
|
rc = PTR_ERR(rinfo->rst) ?
|
||||||
@@ -1323,6 +1330,73 @@ static int __init_resources(struct msm_vidc_core *core)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int __reset_control_acquire_name(struct msm_vidc_core *core,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
struct reset_info *rcinfo = NULL;
|
||||||
|
int rc = 0;
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
venus_hfi_for_each_reset_clock(core, rcinfo) {
|
||||||
|
if (strcmp(rcinfo->name, name))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* this function is valid only for exclusive_release reset clocks*/
|
||||||
|
if (!rcinfo->exclusive_release) {
|
||||||
|
d_vpr_e("%s: unsupported reset control (%s), exclusive %d\n",
|
||||||
|
__func__, name, rcinfo->exclusive_release);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
found = true;
|
||||||
|
rc = reset_control_acquire(rcinfo->rst);
|
||||||
|
if (rc)
|
||||||
|
d_vpr_e("%s: failed to acquire reset control (%s), rc = %d\n",
|
||||||
|
__func__, rcinfo->name, rc);
|
||||||
|
else
|
||||||
|
d_vpr_h("%s: acquire reset control (%s)\n",
|
||||||
|
__func__, rcinfo->name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
d_vpr_e("%s: reset control (%s) not found\n", __func__, name);
|
||||||
|
rc = -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __reset_control_release_name(struct msm_vidc_core *core,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
struct reset_info *rcinfo = NULL;
|
||||||
|
int rc = 0;
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
venus_hfi_for_each_reset_clock(core, rcinfo) {
|
||||||
|
if (strcmp(rcinfo->name, name))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* this function is valid only for exclusive_release reset clocks*/
|
||||||
|
if (!rcinfo->exclusive_release) {
|
||||||
|
d_vpr_e("%s: unsupported reset control (%s), exclusive %d\n",
|
||||||
|
__func__, name, rcinfo->exclusive_release);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
found = true;
|
||||||
|
reset_control_release(rcinfo->rst);
|
||||||
|
d_vpr_h("%s: release reset control (%s)\n", __func__, rcinfo->name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
d_vpr_e("%s: reset control (%s) not found\n", __func__, name);
|
||||||
|
rc = -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
static int __reset_control_assert_name(struct msm_vidc_core *core,
|
static int __reset_control_assert_name(struct msm_vidc_core *core,
|
||||||
const char *name)
|
const char *name)
|
||||||
{
|
{
|
||||||
@@ -1448,6 +1522,8 @@ static int __reset_ahb2axi_bridge(struct msm_vidc_core *core)
|
|||||||
static const struct msm_vidc_resources_ops res_ops = {
|
static const struct msm_vidc_resources_ops res_ops = {
|
||||||
.init = __init_resources,
|
.init = __init_resources,
|
||||||
.reset_bridge = __reset_ahb2axi_bridge,
|
.reset_bridge = __reset_ahb2axi_bridge,
|
||||||
|
.reset_control_acquire = __reset_control_acquire_name,
|
||||||
|
.reset_control_release = __reset_control_release_name,
|
||||||
.reset_control_assert = __reset_control_assert_name,
|
.reset_control_assert = __reset_control_assert_name,
|
||||||
.reset_control_deassert = __reset_control_deassert_name,
|
.reset_control_deassert = __reset_control_deassert_name,
|
||||||
.gdsc_on = __enable_regulator,
|
.gdsc_on = __enable_regulator,
|
||||||
|
Reference in New Issue
Block a user