From 2e6a2419b48aa05c31d58680df1bb370d25aa99d Mon Sep 17 00:00:00 2001 From: Mukund Madhusudan Atre Date: Mon, 6 Apr 2020 12:52:45 -0700 Subject: [PATCH] msm: camera: common: Add sysfs support for bw override To simulate bus overflow recovery in camera, cpas needs sysfs to take input from shell and vote the final value as given, instead of consolidated values from cpas clients. Add initial support for sysfs to add nodes for all drivers. Add sysfs based debug node to maintain and update all settings. Add cpas settings to override final bw voted to camnoc and mnoc ports. Usage: adb shell "echo #= > /sys/devices/platform/soc/soc:qcom,cam-req-mgr/debug_node" Example:i adb shell "echo cpas#camnoc_bw=100 > /sys/devices/platform/soc/soc:qcom,cam-req-mgr/debug_node" Input format for updating settings is strict. CRs-Fixed: 2646825 Change-Id: I8d6063240f9685474bf4b2899e8dfb3f74cbdb75 Signed-off-by: Mukund Madhusudan Atre --- drivers/cam_cpas/cam_cpas_hw.c | 84 +++++++++++++++++++++ drivers/cam_req_mgr/cam_req_mgr_dev.c | 13 ++++ drivers/cam_utils/cam_debug_util.c | 103 ++++++++++++++++++++++++++ drivers/cam_utils/cam_debug_util.h | 41 ++++++++++ 4 files changed, 241 insertions(+) diff --git a/drivers/cam_cpas/cam_cpas_hw.c b/drivers/cam_cpas/cam_cpas_hw.c index 8fd153169d89..49ebdb3f9324 100644 --- a/drivers/cam_cpas/cam_cpas_hw.c +++ b/drivers/cam_cpas/cam_cpas_hw.c @@ -13,10 +13,63 @@ #include "cam_cpas_hw.h" #include "cam_cpas_hw_intf.h" #include "cam_cpas_soc.h" +#include "cam_req_mgr_dev.h" static uint cam_min_camnoc_ib_bw; module_param(cam_min_camnoc_ib_bw, uint, 0644); +static void cam_cpas_process_bw_overrides( + struct cam_cpas_bus_client *bus_client, uint64_t *ab, uint64_t *ib, + const struct cam_cpas_debug_settings *cpas_settings) +{ + uint64_t curr_ab = *ab; + uint64_t curr_ib = *ib; + size_t name_len = strlen(bus_client->common_data.name); + + if (!cpas_settings) { + CAM_ERR(CAM_CPAS, "Invalid cpas debug settings"); + return; + } + + if (strnstr(bus_client->common_data.name, "cam_hf_0", name_len)) { + if (cpas_settings->mnoc_hf_0_ab_bw) + *ab = cpas_settings->mnoc_hf_0_ab_bw; + if (cpas_settings->mnoc_hf_0_ib_bw) + *ib = cpas_settings->mnoc_hf_0_ib_bw; + } else if (strnstr(bus_client->common_data.name, "cam_hf_1", + name_len)) { + if (cpas_settings->mnoc_hf_1_ab_bw) + *ab = cpas_settings->mnoc_hf_1_ab_bw; + if (cpas_settings->mnoc_hf_0_ib_bw) + *ib = cpas_settings->mnoc_hf_1_ib_bw; + } else if (strnstr(bus_client->common_data.name, "cam_sf_0", + name_len)) { + if (cpas_settings->mnoc_sf_0_ab_bw) + *ab = cpas_settings->mnoc_sf_0_ab_bw; + if (cpas_settings->mnoc_sf_0_ib_bw) + *ib = cpas_settings->mnoc_sf_0_ib_bw; + } else if (strnstr(bus_client->common_data.name, "cam_sf_1", + name_len)) { + if (cpas_settings->mnoc_sf_1_ab_bw) + *ab = cpas_settings->mnoc_sf_1_ab_bw; + if (cpas_settings->mnoc_sf_1_ib_bw) + *ib = cpas_settings->mnoc_sf_1_ib_bw; + } else if (strnstr(bus_client->common_data.name, "cam_sf_icp", + name_len)) { + if (cpas_settings->mnoc_sf_icp_ab_bw) + *ab = cpas_settings->mnoc_sf_icp_ab_bw; + if (cpas_settings->mnoc_sf_icp_ib_bw) + *ib = cpas_settings->mnoc_sf_icp_ib_bw; + } else { + CAM_ERR(CAM_CPAS, "unknown mnoc port: %s, bw override failed", + bus_client->common_data.name); + return; + } + + CAM_INFO(CAM_CPAS, + "Overriding mnoc bw for: %s with ab: %llu, ib: %llu, curr_ab: %llu, curr_ib: %llu", + bus_client->common_data.name, *ab, *ib, curr_ab, curr_ib); +} int cam_cpas_util_reg_update(struct cam_hw_info *cpas_hw, enum cam_cpas_reg_base reg_base, struct cam_cpas_reg *reg_info) @@ -85,6 +138,7 @@ static int cam_cpas_util_vote_bus_client_bw( { int rc = 0; uint64_t min_camnoc_ib_bw = CAM_CPAS_AXI_MIN_CAMNOC_IB_BW; + const struct camera_debug_settings *cam_debug = NULL; if (!bus_client->valid) { CAM_ERR(CAM_CPAS, "bus client: %s not valid", @@ -116,6 +170,21 @@ static int cam_cpas_util_vote_bus_client_bw( ib = CAM_CPAS_AXI_MIN_MNOC_IB_BW; } + cam_debug = cam_debug_get_settings(); + + if (cam_debug && (cam_debug->cpas_settings.mnoc_hf_0_ab_bw || + cam_debug->cpas_settings.mnoc_hf_0_ib_bw || + cam_debug->cpas_settings.mnoc_hf_1_ab_bw || + cam_debug->cpas_settings.mnoc_hf_1_ib_bw || + cam_debug->cpas_settings.mnoc_sf_0_ab_bw || + cam_debug->cpas_settings.mnoc_sf_0_ib_bw || + cam_debug->cpas_settings.mnoc_sf_1_ab_bw || + cam_debug->cpas_settings.mnoc_sf_1_ib_bw || + cam_debug->cpas_settings.mnoc_sf_icp_ab_bw || + cam_debug->cpas_settings.mnoc_sf_icp_ib_bw)) + cam_cpas_process_bw_overrides(bus_client, &ab, &ib, + &cam_debug->cpas_settings); + rc = cam_soc_bus_client_update_bw(bus_client->soc_bus_client, ab, ib); if (rc) { CAM_ERR(CAM_CPAS, @@ -376,6 +445,8 @@ static int cam_cpas_util_set_camnoc_axi_clk_rate( struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; struct cam_cpas_tree_node *tree_node = NULL; int rc = 0, i = 0; + const struct camera_debug_settings *cam_debug = NULL; + CAM_DBG(CAM_CPAS, "control_camnoc_axi_clk=%d", soc_private->control_camnoc_axi_clk); @@ -415,6 +486,19 @@ static int cam_cpas_util_set_camnoc_axi_clk_rate( soc_private->camnoc_axi_min_ib_bw)) required_camnoc_bw = soc_private->camnoc_axi_min_ib_bw; + cam_debug = cam_debug_get_settings(); + if (cam_debug && cam_debug->cpas_settings.camnoc_bw) { + if (cam_debug->cpas_settings.camnoc_bw < + soc_private->camnoc_bus_width) + required_camnoc_bw = + soc_private->camnoc_bus_width; + else + required_camnoc_bw = + cam_debug->cpas_settings.camnoc_bw; + CAM_INFO(CAM_CPAS, "Overriding camnoc bw: %llu", + required_camnoc_bw); + } + intermediate_result = required_camnoc_bw; do_div(intermediate_result, soc_private->camnoc_bus_width); clk_rate = intermediate_result; diff --git a/drivers/cam_req_mgr/cam_req_mgr_dev.c b/drivers/cam_req_mgr/cam_req_mgr_dev.c index ad85d89953c8..55d08da9ffd7 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_dev.c +++ b/drivers/cam_req_mgr/cam_req_mgr_dev.c @@ -25,12 +25,16 @@ #include "cam_debug_util.h" #include "cam_common_util.h" #include "cam_compat.h" +#include "cam_cpas_hw.h" #define CAM_REQ_MGR_EVENT_MAX 30 static struct cam_req_mgr_device g_dev; struct kmem_cache *g_cam_req_mgr_timer_cachep; +static struct device_attribute camera_debug_sysfs_attr = + __ATTR(debug_node, 0600, NULL, cam_debug_sysfs_node_store); + static int cam_media_device_setup(struct device *dev) { int rc; @@ -810,9 +814,17 @@ static int cam_req_mgr_component_master_bind(struct device *dev) } CAM_INFO(CAM_CRM, "All camera components bound successfully"); + rc = sysfs_create_file(&dev->kobj, &camera_debug_sysfs_attr.attr); + if (rc < 0) { + CAM_ERR(CAM_CPAS, + "Failed to create debug attribute, rc=%d\n", rc); + goto sysfs_fail; + } return rc; +sysfs_fail: + sysfs_remove_file(&dev->kobj, &camera_debug_sysfs_attr.attr); req_mgr_device_deinit: cam_req_mgr_core_device_deinit(); req_mgr_core_fail: @@ -835,6 +847,7 @@ static void cam_req_mgr_component_master_unbind(struct device *dev) component_unbind_all(dev, NULL); /* Now proceed with unbinding master */ + sysfs_remove_file(&dev->kobj, &camera_debug_sysfs_attr.attr); cam_req_mgr_core_device_deinit(); cam_req_mgr_util_deinit(); cam_media_device_cleanup(); diff --git a/drivers/cam_utils/cam_debug_util.c b/drivers/cam_utils/cam_debug_util.c index c5e1dc7b671f..96d466008cf2 100644 --- a/drivers/cam_utils/cam_debug_util.c +++ b/drivers/cam_utils/cam_debug_util.c @@ -4,12 +4,115 @@ */ #include +#include #include #include "cam_debug_util.h" static uint debug_mdl; module_param(debug_mdl, uint, 0644); +struct camera_debug_settings cam_debug; + +const struct camera_debug_settings *cam_debug_get_settings() +{ + return &cam_debug; +} + +static int cam_debug_parse_cpas_settings(const char *setting, u64 value) +{ + if (!strcmp(setting, "camnoc_bw")) { + cam_debug.cpas_settings.camnoc_bw = value; + } else if (!strcmp(setting, "mnoc_hf_0_ab_bw")) { + cam_debug.cpas_settings.mnoc_hf_0_ab_bw = value; + } else if (!strcmp(setting, "mnoc_hf_0_ib_bw")) { + cam_debug.cpas_settings.mnoc_hf_0_ib_bw = value; + } else if (!strcmp(setting, "mnoc_hf_1_ab_bw")) { + cam_debug.cpas_settings.mnoc_hf_1_ab_bw = value; + } else if (!strcmp(setting, "mnoc_hf_1_ib_bw")) { + cam_debug.cpas_settings.mnoc_hf_1_ib_bw = value; + } else if (!strcmp(setting, "mnoc_sf_0_ab_bw")) { + cam_debug.cpas_settings.mnoc_sf_0_ab_bw = value; + } else if (!strcmp(setting, "mnoc_sf_0_ib_bw")) { + cam_debug.cpas_settings.mnoc_sf_0_ib_bw = value; + } else if (!strcmp(setting, "mnoc_sf_1_ab_bw")) { + cam_debug.cpas_settings.mnoc_sf_1_ab_bw = value; + } else if (!strcmp(setting, "mnoc_sf_1_ib_bw")) { + cam_debug.cpas_settings.mnoc_sf_1_ib_bw = value; + } else if (!strcmp(setting, "mnoc_sf_icp_ab_bw")) { + cam_debug.cpas_settings.mnoc_sf_icp_ab_bw = value; + } else if (!strcmp(setting, "mnoc_sf_icp_ib_bw")) { + cam_debug.cpas_settings.mnoc_sf_icp_ib_bw = value; + } else { + CAM_ERR(CAM_UTIL, "Unsupported cpas sysfs entry"); + return -EINVAL; + } + + return 0; +} + +ssize_t cam_debug_sysfs_node_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int rc = 0; + char *local_buf = NULL, *local_buf_temp = NULL; + char *driver; + char *setting = NULL; + char *value_str = NULL; + u64 value; + + CAM_INFO(CAM_UTIL, "Sysfs debug attr name:[%s] buf:[%s] bytes:[%d]", + attr->attr.name, buf, count); + local_buf = kmemdup(buf, (count + sizeof(char)), GFP_KERNEL); + local_buf_temp = local_buf; + driver = strsep(&local_buf, "#"); + if (!driver) { + CAM_ERR(CAM_UTIL, + "Invalid input driver name buf:[%s], count:%d", + buf, count); + goto error; + } + + setting = strsep(&local_buf, "="); + if (!setting) { + CAM_ERR(CAM_UTIL, "Invalid input setting buf:[%s], count:%d", + buf, count); + goto error; + } + + value_str = strsep(&local_buf, "="); + if (!value_str) { + CAM_ERR(CAM_UTIL, "Invalid input value buf:[%s], count:%d", + buf, count); + goto error; + } + + rc = kstrtou64(value_str, 0, &value); + if (rc < 0) { + CAM_ERR(CAM_UTIL, "Error converting value:[%s], buf:[%s]", + value_str, buf); + goto error; + } + + CAM_INFO(CAM_UTIL, + "Processing sysfs store for driver:[%s], setting:[%s], value:[%llu]", + driver, setting, value); + + if (!strcmp(driver, "cpas")) { + rc = cam_debug_parse_cpas_settings(setting, value); + if (rc) + goto error; + } else { + CAM_ERR(CAM_UTIL, "Unsupported driver in camera debug node"); + goto error; + } + + kfree(local_buf_temp); + return count; + +error: + kfree(local_buf_temp); + return -EPERM; +} const char *cam_get_module_name(unsigned int module_id) { diff --git a/drivers/cam_utils/cam_debug_util.h b/drivers/cam_utils/cam_debug_util.h index 5537b2d8db5f..3a53aa9ce566 100644 --- a/drivers/cam_utils/cam_debug_util.h +++ b/drivers/cam_utils/cam_debug_util.h @@ -6,6 +6,8 @@ #ifndef _CAM_DEBUG_UTIL_H_ #define _CAM_DEBUG_UTIL_H_ +#include + #define CAM_CDM (1 << 0) #define CAM_CORE (1 << 1) #define CAM_CPAS (1 << 2) @@ -44,6 +46,32 @@ #define STR_BUFFER_MAX_LENGTH 1024 +/** + * struct cam_cpas_debug_settings - Sysfs debug settings for cpas driver + */ +struct cam_cpas_debug_settings { + uint64_t mnoc_hf_0_ab_bw; + uint64_t mnoc_hf_0_ib_bw; + uint64_t mnoc_hf_1_ab_bw; + uint64_t mnoc_hf_1_ib_bw; + uint64_t mnoc_sf_0_ab_bw; + uint64_t mnoc_sf_0_ib_bw; + uint64_t mnoc_sf_1_ab_bw; + uint64_t mnoc_sf_1_ib_bw; + uint64_t mnoc_sf_icp_ab_bw; + uint64_t mnoc_sf_icp_ib_bw; + uint64_t camnoc_bw; +}; + +/** + * struct camera_debug_settings - Sysfs debug settings for camera + * + * @cpas_settings: Debug settings for cpas driver. + */ +struct camera_debug_settings { + struct cam_cpas_debug_settings cpas_settings; +}; + /* * cam_debug_log() * @@ -211,4 +239,17 @@ const char *cam_get_module_name(unsigned int module_id); __LINE__, ##args); \ }) +/** + * @brief : API to get camera debug settings + * @return const struct camera_debug_settings pointer. + */ +const struct camera_debug_settings *cam_debug_get_settings(void); + +/** + * @brief : API to parse and store input from sysfs debug node + * @return Number of bytes read from buffer on success, or -EPERM on error. + */ +ssize_t cam_debug_sysfs_node_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); + #endif /* _CAM_DEBUG_UTIL_H_ */