Merge "msm: camera: isp: Maintain clock rate relation between CSIHPY, CSID and TFE" into camera-kernel.lnx.4.0

This commit is contained in:
Camera Software Integration 2021-01-13 03:16:37 -08:00 • committed by Gerrit - the friendly Code Review server
commit 168408b487
13 changed files with 429 additions and 7 deletions

View file

@ -311,6 +311,31 @@ int cam_context_dump_pf_info(struct cam_context *ctx,
return rc;
}
int cam_context_handle_message(struct cam_context *ctx,
uint32_t msg_type, uint32_t *data)
{
int rc = 0;
if (!ctx->state_machine) {
CAM_ERR(CAM_CORE, "Context is not ready");
return -EINVAL;
}
if ((ctx->state > CAM_CTX_AVAILABLE) &&
(ctx->state < CAM_CTX_STATE_MAX)) {
if (ctx->state_machine[ctx->state].msg_cb_ops) {
rc = ctx->state_machine[ctx->state].msg_cb_ops(
ctx, msg_type, data);
} else {
CAM_WARN(CAM_CORE,
"No message handler for ctx %d, state %d msg_type :%d",
ctx->dev_hdl, ctx->state, msg_type);
}
}
return rc;
}
int cam_context_handle_acquire_dev(struct cam_context *ctx,
struct cam_acquire_dev_cmd *cmd)
{

View file

@ -158,14 +158,17 @@ struct cam_ctx_crm_ops {
* @pagefault_ops: Function to be called on page fault
* @dumpinfo_ops: Function to be invoked for dumping any
* context info
* @msg_cb_ops: Function to be called on any message from
* other subdev notifications
*
*/
struct cam_ctx_ops {
struct cam_ctx_ioctl_ops ioctl_ops;
struct cam_ctx_crm_ops crm_ops;
cam_hw_event_cb_func irq_ops;
cam_hw_pagefault_cb_func pagefault_ops;
cam_ctx_info_dump_cb_func dumpinfo_ops;
struct cam_ctx_ioctl_ops ioctl_ops;
struct cam_ctx_crm_ops crm_ops;
cam_hw_event_cb_func irq_ops;
cam_hw_pagefault_cb_func pagefault_ops;
cam_ctx_info_dump_cb_func dumpinfo_ops;
cam_ctx_message_cb_func msg_cb_ops;
};
/**
@ -367,6 +370,19 @@ int cam_context_handle_crm_dump_req(struct cam_context *ctx,
int cam_context_dump_pf_info(struct cam_context *ctx,
struct cam_smmu_pf_info *pf_info);
/**
* cam_context_handle_message()
*
* @brief: Handle message callback command
*
* @ctx: Object pointer for cam_context
* @msg_type: message type sent from other subdev
* @data: data from other subdev
*
*/
int cam_context_handle_message(struct cam_context *ctx,
uint32_t msg_type, uint32_t *data);
/**
* cam_context_handle_acquire_dev()
*

View file

@ -53,6 +53,9 @@ typedef int (*cam_hw_pagefault_cb_func)(void *context,
typedef int (*cam_ctx_info_dump_cb_func)(void *context,
enum cam_context_dump_id dump_id);
/* message callback function type */
typedef int (*cam_ctx_message_cb_func)(void *context,
uint32_t message_type, uint32_t *data);
/**
* struct cam_hw_update_entry - Entry for hardware config
*

View file

@ -21,6 +21,7 @@
#include "cam_common_util.h"
#include "cam_req_mgr_debug.h"
#include "cam_cpas_api.h"
#include "cam_subdev.h"
static const char isp_dev_name[] = "cam-isp";
@ -33,6 +34,9 @@ static struct cam_isp_ctx_debug isp_ctx_debug;
static int cam_isp_context_dump_requests(void *data,
struct cam_smmu_pf_info *pf_info);
static int cam_isp_context_handle_message(void *context,
uint32_t msg_type, uint32_t *data);
static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx,
struct cam_start_stop_dev_cmd *cmd);
@ -5772,6 +5776,7 @@ static struct cam_ctx_ops
.irq_ops = NULL,
.pagefault_ops = cam_isp_context_dump_requests,
.dumpinfo_ops = cam_isp_context_info_dump,
.msg_cb_ops = cam_isp_context_handle_message,
},
/* Activated */
{
@ -5791,6 +5796,7 @@ static struct cam_ctx_ops
.irq_ops = __cam_isp_ctx_handle_irq_in_activated,
.pagefault_ops = cam_isp_context_dump_requests,
.dumpinfo_ops = cam_isp_context_info_dump,
.msg_cb_ops = cam_isp_context_handle_message,
},
};
@ -5933,6 +5939,34 @@ static int cam_isp_context_dump_requests(void *data,
return rc;
}
static int cam_isp_context_handle_message(void *context,
uint32_t msg_type, uint32_t *data)
{
int rc = 0;
struct cam_hw_cmd_args hw_cmd_args;
struct cam_isp_hw_cmd_args isp_hw_cmd_args;
struct cam_context *ctx = (struct cam_context *)context;
memset(&hw_cmd_args, 0, sizeof(hw_cmd_args));
hw_cmd_args.ctxt_to_hw_map = ctx->ctxt_to_hw_map;
switch (msg_type) {
case CAM_SUBDEV_MESSAGE_CLOCK_UPDATE:
hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_INTERNAL;
isp_hw_cmd_args.cmd_type = CAM_ISP_HW_MGR_CMD_UPDATE_CLOCK;
isp_hw_cmd_args.cmd_data = (void *)data;
hw_cmd_args.u.internal_args = (void *)&isp_hw_cmd_args;
rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv,
&hw_cmd_args);
if (rc)
CAM_ERR(CAM_ISP, "Update clock rate failed rc: %d", rc);
break;
default:
CAM_ERR(CAM_ISP, "Invalid message type %d", msg_type);
}
return rc;
}
static int cam_isp_context_debug_register(void)
{
int rc = 0;

View file

@ -38,6 +38,22 @@ static void cam_isp_dev_iommu_fault_handler(struct cam_smmu_pf_info *pf_info)
cam_context_dump_pf_info(&(node->ctx_list[i]), pf_info);
}
static void cam_isp_subdev_handle_message(
struct v4l2_subdev *sd,
enum cam_subdev_message_type_t message_type,
uint32_t data)
{
int i, rc = 0;
struct cam_node *node = v4l2_get_subdevdata(sd);
CAM_DBG(CAM_ISP, "node name %s", node->name, data);
for (i = 0; i < node->ctx_size; i++) {
rc = cam_context_handle_message(&(node->ctx_list[i]), message_type, &data);
if (rc)
CAM_ERR(CAM_ISP, "Failed to handle message for %s", node->name);
}
}
static const struct of_device_id cam_isp_dt_match[] = {
{
.compatible = "qcom,cam-isp"
@ -113,6 +129,7 @@ static int cam_isp_dev_component_bind(struct device *dev,
} else if (strnstr(compat_str, "tfe", strlen(compat_str))) {
rc = cam_subdev_probe(&g_isp_dev.sd, pdev, CAM_ISP_DEV_NAME,
CAM_TFE_DEVICE_TYPE);
g_isp_dev.sd.msg_cb = cam_isp_subdev_handle_message;
g_isp_dev.isp_device_type = CAM_TFE_DEVICE_TYPE;
g_isp_dev.max_context = CAM_TFE_CTX_MAX;
} else {

View file

@ -306,6 +306,82 @@ err:
return rc;
}
static int cam_tfe_hw_mgr_get_clock_rate(
struct cam_isp_hw_mgr_res *isp_hw_res,
uint32_t *get_clock_rate)
{
int i;
int rc = -EINVAL;
struct cam_hw_intf *hw_intf;
for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
if (!isp_hw_res->hw_res[i])
continue;
hw_intf = isp_hw_res->hw_res[i]->hw_intf;
CAM_DBG(CAM_ISP, "hw type %d hw index:%d",
hw_intf->hw_type, hw_intf->hw_idx);
if (hw_intf && hw_intf->hw_ops.process_cmd) {
rc = hw_intf->hw_ops.process_cmd(
hw_intf->hw_priv,
CAM_ISP_HW_CMD_GET_CLOCK_RATE,
get_clock_rate,
sizeof(uint32_t));
if (rc) {
CAM_ERR(CAM_ISP, "Failed to get Clock rate");
return rc;
}
}
}
return rc;
}
static int cam_tfe_hw_mgr_update_clock_rate(
struct cam_isp_hw_mgr_res *isp_hw_res,
uint32_t *set_clock_rate,
uint32_t *updated_clock_rate)
{
int i;
int rc = 0;
struct cam_hw_intf *hw_intf;
for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
if (!isp_hw_res->hw_res[i])
continue;
hw_intf = isp_hw_res->hw_res[i]->hw_intf;
CAM_DBG(CAM_ISP, "hw type %d hw index:%d",
hw_intf->hw_type, hw_intf->hw_idx);
if (hw_intf && hw_intf->hw_ops.process_cmd) {
rc = hw_intf->hw_ops.process_cmd(
hw_intf->hw_priv,
CAM_ISP_HW_CMD_DYNAMIC_CLOCK_UPDATE,
set_clock_rate,
sizeof(uint32_t));
if (rc) {
CAM_ERR(CAM_ISP, "Failed to get Clock rate");
return rc;
}
}
if (hw_intf && hw_intf->hw_ops.process_cmd) {
rc = hw_intf->hw_ops.process_cmd(
hw_intf->hw_priv,
CAM_ISP_HW_CMD_GET_CLOCK_RATE,
updated_clock_rate,
sizeof(uint32_t));
if (rc) {
CAM_ERR(CAM_ISP, "Failed to get Clock rate");
return rc;
}
}
}
return rc;
}
static int cam_tfe_hw_mgr_start_hw_res(
struct cam_isp_hw_mgr_res *isp_hw_res,
struct cam_tfe_hw_mgr_ctx *ctx)
@ -1824,6 +1900,105 @@ void cam_tfe_cam_cdm_callback(uint32_t handle, void *userdata,
}
}
int cam_tfe_cshiphy_callback(
struct cam_tfe_hw_mgr_ctx *ctx, void *cmd_args)
{
int rc = -EINVAL;
struct cam_isp_hw_mgr_res *hw_mgr_res;
uint32_t *phy_clock_rate;
uint32_t clock_rate = 0;
uint32_t csid_clock_rate = 0, tfe_clock_rate = 0;
uint32_t updated_tfe_clk = 0, updated_csid_clk = 0;
if (!ctx || !cmd_args) {
CAM_ERR(CAM_ISP, "Invalid arguments");
return -EINVAL;
}
phy_clock_rate = (uint32_t *)cmd_args;
CAM_DBG(CAM_ISP, "clk rate csid ... in ctx id:%d",
ctx->ctx_index);
list_for_each_entry(hw_mgr_res, &ctx->res_list_tfe_csid, list) {
rc = cam_tfe_hw_mgr_get_clock_rate(hw_mgr_res,
&clock_rate);
if (rc) {
CAM_ERR(CAM_ISP,
"Can not get CSID clock rate(id :%d)",
hw_mgr_res->res_id);
return rc;
}
if (!csid_clock_rate)
csid_clock_rate = clock_rate;
if (clock_rate < csid_clock_rate)
csid_clock_rate = clock_rate;
CAM_DBG(CAM_ISP, "clk rate csid: %lld %lld",
clock_rate, csid_clock_rate);
}
CAM_DBG(CAM_ISP, "clk rate TFE in resource ctx id:%d",
ctx->ctx_index);
list_for_each_entry(hw_mgr_res, &ctx->res_list_tfe_in, list) {
rc = cam_tfe_hw_mgr_get_clock_rate(hw_mgr_res,
&clock_rate);
if (rc) {
CAM_ERR(CAM_ISP,
"Can not get TFE clock rate (%d)",
hw_mgr_res->res_id);
return rc;
}
if (!tfe_clock_rate)
tfe_clock_rate = clock_rate;
if (clock_rate < tfe_clock_rate)
tfe_clock_rate = clock_rate;
CAM_DBG(CAM_ISP, "clk rate tfe: %lld %lld",
clock_rate, tfe_clock_rate);
}
if (*phy_clock_rate > csid_clock_rate) {
list_for_each_entry(hw_mgr_res,
&ctx->res_list_tfe_csid, list) {
rc = cam_tfe_hw_mgr_update_clock_rate(hw_mgr_res,
phy_clock_rate, &updated_csid_clk);
}
if (updated_csid_clk > tfe_clock_rate) {
list_for_each_entry(hw_mgr_res,
&ctx->res_list_tfe_in, list) {
rc = cam_tfe_hw_mgr_update_clock_rate(hw_mgr_res,
&updated_csid_clk, &updated_tfe_clk);
}
}
goto end;
}
if (csid_clock_rate > tfe_clock_rate) {
list_for_each_entry(hw_mgr_res,
&ctx->res_list_tfe_in, list) {
rc = cam_tfe_hw_mgr_update_clock_rate(hw_mgr_res,
&csid_clock_rate, &updated_tfe_clk);
}
}
end:
/* final check */
if ((*phy_clock_rate > updated_csid_clk) ||
(updated_csid_clk > updated_tfe_clk) ||
(*phy_clock_rate > updated_tfe_clk)) {
CAM_ERR(CAM_ISP,
"improper clock rates, phy:%lld csid:%lld tfe:%lld",
*phy_clock_rate, updated_csid_clk, updated_tfe_clk);
return -EINVAL;
}
return 0;
}
/* entry function: acquire_hw */
static int cam_tfe_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args)
{
@ -4761,6 +4936,9 @@ static int cam_tfe_mgr_cmd(void *hw_mgr_priv, void *cmd_args)
isp_hw_cmd_args->u.last_cdm_done =
ctx->last_cdm_done_req;
break;
case CAM_ISP_HW_MGR_CMD_UPDATE_CLOCK:
rc = cam_tfe_cshiphy_callback(ctx, isp_hw_cmd_args->cmd_data);
break;
default:
CAM_ERR(CAM_ISP, "Invalid HW mgr command:0x%x",
hw_cmd_args->cmd_type);

View file

@ -48,7 +48,6 @@ enum cam_isp_hw_event_type {
CAM_ISP_HW_EVENT_MAX
};
/**
* enum cam_isp_hw_err_type - Collection of the ISP error types for
* ISP hardware event CAM_ISP_HW_EVENT_ERROR
@ -241,6 +240,7 @@ enum cam_isp_hw_mgr_command {
CAM_ISP_HW_MGR_CMD_CTX_TYPE,
CAM_ISP_HW_MGR_GET_PACKET_OPCODE,
CAM_ISP_HW_MGR_GET_LAST_CDM_DONE,
CAM_ISP_HW_MGR_CMD_UPDATE_CLOCK,
CAM_ISP_HW_MGR_CMD_MAX,
};

View file

@ -135,6 +135,8 @@ enum cam_isp_hw_cmd_type {
CAM_ISP_HW_CMD_CSID_CHANGE_HALT_MODE,
CAM_ISP_HW_CMD_SET_SFE_DEBUG_CFG,
CAM_ISP_HW_CMD_QUERY_BUS_CAP,
CAM_ISP_HW_CMD_GET_CLOCK_RATE,
CAM_ISP_HW_CMD_DYNAMIC_CLOCK_UPDATE,
CAM_ISP_HW_CMD_MAX,
};

View file

@ -2404,6 +2404,52 @@ static int cam_tfe_csid_set_csid_clock(
return 0;
}
static int cam_tfe_csid_get_csid_clock(
struct cam_tfe_csid_hw *csid_hw, void *cmd_args)
{
struct cam_hw_soc_info *soc_info;
uint32_t *curr_clk_rate;
int src_clk_idx;
int rc = 0;
if (!csid_hw)
return -EINVAL;
soc_info = &csid_hw->hw_info->soc_info;
src_clk_idx = soc_info->src_clk_idx;
curr_clk_rate = (uint32_t *)cmd_args;
rc = cam_soc_util_get_clk_rate(soc_info->clk[src_clk_idx],
soc_info->clk_name[src_clk_idx], curr_clk_rate);
CAM_DBG(CAM_ISP, "CSID clock rate %llu", *curr_clk_rate);
return rc;
}
static int cam_tfe_csid_set_csid_clock_dynamically(
struct cam_tfe_csid_hw *csid_hw, void *cmd_args)
{
struct cam_hw_soc_info *soc_info;
uint32_t *clk_rate;
int rc = 0;
soc_info = &csid_hw->hw_info->soc_info;
clk_rate = (uint32_t *)cmd_args;
CAM_DBG(CAM_ISP, "CSID clock rate %lld", *clk_rate);
rc = cam_soc_util_set_src_clk_rate(soc_info, *clk_rate);
if (rc) {
CAM_ERR(CAM_ISP,
"unable to set clock dynamically rate:%lld", *clk_rate);
return rc;
}
return rc;
}
static int cam_tfe_csid_get_regdump(struct cam_tfe_csid_hw *csid_hw,
void *cmd_args)
{
@ -2676,6 +2722,12 @@ static int cam_tfe_csid_process_cmd(void *hw_priv,
case CAM_TFE_CSID_LOG_ACQUIRE_DATA:
rc = cam_tfe_csid_log_acquire_data(csid_hw, cmd_args);
break;
case CAM_ISP_HW_CMD_GET_CLOCK_RATE:
rc = cam_tfe_csid_get_csid_clock(csid_hw, cmd_args);
break;
case CAM_ISP_HW_CMD_DYNAMIC_CLOCK_UPDATE:
rc = cam_tfe_csid_set_csid_clock_dynamically(csid_hw, cmd_args);
break;
default:
CAM_ERR(CAM_ISP, "CSID:%d unsupported cmd:%d",
csid_hw->hw_intf->hw_idx, cmd_type);

View file

@ -969,6 +969,62 @@ static int cam_tfe_top_set_hw_clk_rate(
return rc;
}
static int cam_tfe_top_get_hw_clk_rate(
struct cam_tfe_top_priv *top_priv,
void *cmd_args,
uint32_t arg_size)
{
struct cam_hw_soc_info *soc_info;
uint32_t *curr_clk_rate;
int src_clk_idx;
int rc = 0;
if (!top_priv) {
CAM_ERR(CAM_ISP, "Error top_private NULL");
return -EINVAL;
}
soc_info = top_priv->common_data.soc_info;
src_clk_idx = soc_info->src_clk_idx;
curr_clk_rate = (uint32_t *)cmd_args;
rc = cam_soc_util_get_clk_rate(soc_info->clk[src_clk_idx],
soc_info->clk_name[src_clk_idx], curr_clk_rate);
CAM_DBG(CAM_ISP, "TFE clock rate %llu", *curr_clk_rate);
return rc;
}
static int cam_tfe_top_dynamic_clock_update(
struct cam_tfe_top_priv *top_priv,
void *cmd_args,
uint32_t arg_size)
{
struct cam_hw_soc_info *soc_info;
int src_clk_idx;
uint32_t *clk_rate;
int rc = 0;
soc_info = top_priv->common_data.soc_info;
src_clk_idx = soc_info->src_clk_idx;
clk_rate = (uint32_t *)cmd_args;
CAM_DBG(CAM_ISP, "TFE clock rate %lld", *clk_rate);
rc = cam_soc_util_set_src_clk_rate(soc_info, *clk_rate);
if (rc) {
CAM_ERR(CAM_ISP,
"unable to set clock dynamically rate:%lld",
*clk_rate);
return rc;
}
return rc;
}
static struct cam_axi_vote *cam_tfe_top_delay_bw_reduction(
struct cam_tfe_top_priv *top_priv,
uint64_t *to_be_applied_bw)
@ -2881,6 +2937,14 @@ int cam_tfe_process_cmd(void *hw_priv, uint32_t cmd_type,
rc = cam_tfe_set_top_debug(core_info, cmd_args,
arg_size);
break;
case CAM_ISP_HW_CMD_GET_CLOCK_RATE:
rc = cam_tfe_top_get_hw_clk_rate(core_info->top_priv, cmd_args,
arg_size);
break;
case CAM_ISP_HW_CMD_DYNAMIC_CLOCK_UPDATE:
rc = cam_tfe_top_dynamic_clock_update(core_info->top_priv, cmd_args,
arg_size);
break;
case CAM_ISP_HW_CMD_GET_BUF_UPDATE:
case CAM_ISP_HW_CMD_GET_HFR_UPDATE:
case CAM_ISP_HW_CMD_STRIPE_UPDATE:

View file

@ -17,7 +17,8 @@
#define CAM_SUBDEVICE_EVENT_MAX 30
enum cam_subdev_message_type_t {
CAM_SUBDEV_MESSAGE_IRQ_ERR = 0x1
CAM_SUBDEV_MESSAGE_IRQ_ERR = 0x1,
CAM_SUBDEV_MESSAGE_CLOCK_UPDATE
};
/**

View file

@ -346,6 +346,23 @@ int cam_soc_util_irq_disable(struct cam_hw_soc_info *soc_info)
return 0;
}
int cam_soc_util_get_clk_rate(struct clk *clk, const char *clk_name,
uint32_t *clk_rate)
{
uint32_t clk_rate_round;
clk_rate_round = clk_get_rate(clk);
if (clk_rate_round < 0) {
CAM_ERR(CAM_UTIL, "get_rate failed on %s", clk_name);
return clk_rate_round;
}
*clk_rate = clk_rate_round;
CAM_DBG(CAM_UTIL, "get rate %lld on %s", *clk_rate, clk_name);
return 0;
}
long cam_soc_util_get_clk_round_rate(struct cam_hw_soc_info *soc_info,
uint32_t clk_index, unsigned long clk_rate)
{

View file

@ -405,6 +405,19 @@ int cam_soc_util_disable_platform_resource(struct cam_hw_soc_info *soc_info,
long cam_soc_util_get_clk_round_rate(struct cam_hw_soc_info *soc_info,
uint32_t clk_index, unsigned long clk_rate);
/**
* cam_soc_util_get_clk_rate()
*
* @brief: Get the rate on the source clock.
* @clk: Src clock reference pointer to get clock rate
* @clk_name: Name of src clock
* @clk_rate: Clock rate associated with the src clk
*
* @return: success or failure
*/
int cam_soc_util_get_clk_rate(struct clk *clk, const char *clk_name,
uint32_t *clk_rate);
/**
* cam_soc_util_set_src_clk_rate()
*