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_ */