From b2def29ddc4c5fb1634343cc2bb57bcbdf554a20 Mon Sep 17 00:00:00 2001 From: Mukund Madhusudan Atre Date: Wed, 19 Oct 2022 12:46:50 -0700 Subject: [PATCH] msm: camera: common: Add support for cesta based clk scaling On chipsets having cesta hw block support, for cesta supported clks clk frequency can be changed during veritcal blanking based on CSID DRV events. For this to happen, camera clients need to setup high and low clock votes through hw clients. Use corresponding clk, crm APIs to setup high, low clk frquencies and do channel switch to apply newly set rates. Clients can also set clk frequency through sw client which will set the floor. This feature helps in saving power for usecases where vertical blanking is high such as Fast Shutter usecase. CRs-Fixed: 3294948 Change-Id: I1bcf650b439991a23b2a0f0f9a5162bdcd60dc64 Signed-off-by: Mukund Madhusudan Atre Signed-off-by: Pavan Kumar Chilamkurthi --- drivers/cam_cdm/cam_cdm_hw_core.c | 13 +- drivers/cam_cpas/cam_cpas_hw.c | 833 ++++++++++++------ drivers/cam_cpas/cam_cpas_hw.h | 28 +- drivers/cam_cpas/cam_cpas_intf.c | 26 +- drivers/cam_cpas/cam_cpas_soc.c | 191 +++- drivers/cam_cpas/cam_cpas_soc.h | 10 +- drivers/cam_cpas/cpas_top/cam_cpastop_hw.c | 7 +- drivers/cam_cpas/include/cam_cpas_api.h | 29 +- .../cam_cre/cam_cre_hw_mgr/cre_hw/cre_core.c | 5 +- .../cam_cre/cam_cre_hw_mgr/cre_hw/cre_soc.c | 7 +- .../cam_custom_hw1/cam_custom_sub_mod_soc.c | 5 +- .../cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c | 7 +- drivers/cam_icp/icp_hw/bps_hw/bps_soc.c | 11 +- .../icp_proc/icp_common/cam_icp_soc_common.c | 6 +- drivers/cam_icp/icp_hw/ipe_hw/ipe_soc.c | 11 +- drivers/cam_icp/icp_hw/ofe_hw/ofe_soc.c | 10 +- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 76 +- drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h | 4 + .../isp_hw/ife_csid_hw/cam_ife_csid_hw_ver1.c | 10 +- .../isp_hw/ife_csid_hw/cam_ife_csid_hw_ver2.c | 189 +++- .../isp_hw/ife_csid_hw/cam_ife_csid_hw_ver2.h | 2 + .../isp_hw/ife_csid_hw/cam_ife_csid_soc.c | 18 +- .../isp_hw/include/cam_ife_csid_hw_intf.h | 4 + .../isp_hw_mgr/isp_hw/include/cam_isp_hw.h | 4 + .../isp_hw/include/cam_sfe_hw_intf.h | 2 + .../isp_hw/include/cam_vfe_hw_intf.h | 2 + .../isp_hw/ppi_hw/cam_csid_ppi_core.c | 7 +- .../isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_soc.c | 16 +- .../isp_hw/sfe_hw/sfe_top/cam_sfe_top.c | 154 ++-- .../isp_hw/tfe_csid_hw/cam_tfe_csid_soc.c | 5 +- .../isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.c | 2 +- .../isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_soc.c | 11 +- .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c | 21 +- .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c | 2 +- .../vfe_hw/vfe_top/cam_vfe_top_common.c | 115 ++- .../vfe_hw/vfe_top/cam_vfe_top_common.h | 3 +- .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c | 3 +- .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c | 3 +- .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver4.c | 19 +- .../jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.c | 5 +- .../jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.c | 5 +- .../lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.c | 7 +- drivers/cam_ope/ope_hw_mgr/ope_hw/ope_core.c | 4 +- drivers/cam_ope/ope_hw_mgr/ope_hw/ope_soc.c | 11 +- drivers/cam_req_mgr/cam_subdev.h | 61 ++ .../cam_sensor_module/cam_cci/cam_cci_soc.c | 6 +- .../cam_csiphy/cam_csiphy_core.c | 181 +++- .../cam_csiphy/cam_csiphy_dev.c | 124 +++ .../cam_csiphy/cam_csiphy_dev.h | 6 + .../cam_csiphy/cam_csiphy_soc.c | 68 +- .../cam_csiphy/cam_csiphy_soc.h | 2 +- .../cam_sensor_utils/cam_sensor_util.c | 8 +- .../cam_sensor_module/cam_tpg/tpg_hw/tpg_hw.c | 8 +- drivers/cam_utils/cam_common_util.c | 3 +- drivers/cam_utils/cam_soc_util.c | 498 ++++++++--- drivers/cam_utils/cam_soc_util.h | 131 ++- 56 files changed, 2253 insertions(+), 746 deletions(-) diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index e37bf855f5..2a3e9ba1ca 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -1908,7 +1908,7 @@ int cam_hw_cdm_get_cdm_config(struct cam_hw_info *cdm_hw) core = (struct cam_cdm *)cdm_hw->core_info; soc_info = &cdm_hw->soc_info; - rc = cam_soc_util_enable_platform_resource(soc_info, true, + rc = cam_soc_util_enable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDX, true, CAM_SVS_VOTE, true); if (rc) { CAM_ERR(CAM_CDM, "Enable platform failed for dev %s", @@ -1983,8 +1983,7 @@ int cam_hw_cdm_get_cdm_config(struct cam_hw_info *cdm_hw) } disable_platform_resource: - ret = cam_soc_util_disable_platform_resource(soc_info, true, true); - + ret = cam_soc_util_disable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDX, true, true); if (ret) { CAM_ERR(CAM_CDM, "disable platform failed for dev %s", soc_info->dev_name); @@ -2012,7 +2011,7 @@ int cam_hw_cdm_init(void *hw_priv, soc_info = &cdm_hw->soc_info; cdm_core = (struct cam_cdm *)cdm_hw->core_info; - rc = cam_soc_util_enable_platform_resource(soc_info, true, + rc = cam_soc_util_enable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDX, true, CAM_SVS_VOTE, true); if (rc) { CAM_ERR(CAM_CDM, "Enable platform failed for %s%d", @@ -2054,7 +2053,7 @@ disable_return: flags = cam_hw_util_hw_lock_irqsave(cdm_hw); cdm_hw->hw_state = CAM_HW_STATE_POWER_DOWN; cam_hw_util_hw_unlock_irqrestore(cdm_hw, flags); - cam_soc_util_disable_platform_resource(soc_info, true, true); + cam_soc_util_disable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDX, true, true); end: return rc; } @@ -2102,7 +2101,7 @@ int cam_hw_cdm_pf_deinit(void *hw_priv, cdm_hw->hw_state = CAM_HW_STATE_POWER_DOWN; cam_hw_util_hw_unlock_irqrestore(cdm_hw, flags); - rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + rc = cam_soc_util_disable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDX, true, true); if (rc) CAM_ERR(CAM_CDM, "disable platform failed for %s%u", soc_info->label_name, soc_info->index); @@ -2178,7 +2177,7 @@ int cam_hw_cdm_deinit(void *hw_priv, flags = cam_hw_util_hw_lock_irqsave(cdm_hw); cdm_hw->hw_state = CAM_HW_STATE_POWER_DOWN; cam_hw_util_hw_unlock_irqrestore(cdm_hw, flags); - rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + rc = cam_soc_util_disable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDX, true, true); if (rc) { CAM_ERR(CAM_CDM, "disable platform failed for %s%u", soc_info->label_name, soc_info->index); diff --git a/drivers/cam_cpas/cam_cpas_hw.c b/drivers/cam_cpas/cam_cpas_hw.c index d1379958d9..db7da9481d 100644 --- a/drivers/cam_cpas/cam_cpas_hw.c +++ b/drivers/cam_cpas/cam_cpas_hw.c @@ -31,6 +31,7 @@ static void cam_cpas_update_monitor_array(struct cam_hw_info *cpas_hw, const char *identifier_string, int32_t identifier_value); static void cam_cpas_dump_monitor_array( struct cam_hw_info *cpas_hw); +static int cam_cpas_log_vote(struct cam_hw_info *cpas_hw, bool ddr_only); static void cam_cpas_process_drv_bw_overrides( struct cam_cpas_bus_client *bus_client, uint64_t *high_ab, uint64_t *high_ib, @@ -764,7 +765,7 @@ static bool cam_cpas_calculate_smart_qos( struct cam_cpas_tree_node *niu_node; uint8_t i; bool needs_update = false; - uint64_t bw_per_kb, max_bw_per_kb = 0, remainder, ramp_val; + uint64_t bw_per_kb, total_camnoc_bw, max_bw_per_kb = 0, remainder, ramp_val; uint64_t total_bw_per_kb = 0, total_bw_ramp_val = 0; int8_t pos; uint64_t priority; @@ -773,7 +774,17 @@ static bool cam_cpas_calculate_smart_qos( for (i = 0; i < soc_private->smart_qos_info->num_rt_wr_nius; i++) { niu_node = soc_private->smart_qos_info->rt_wr_niu_node[i]; - bw_per_kb = niu_node->camnoc_bw; + bw_per_kb = niu_node->bw_info[CAM_CPAS_PORT_HLOS_DRV].hlos_vote.camnoc; + + if (soc_private->enable_cam_clk_drv) + bw_per_kb += niu_node->bw_info[CAM_CPAS_PORT_DRV_0].drv_vote.high.camnoc + + niu_node->bw_info[CAM_CPAS_PORT_DRV_0].drv_vote.low.camnoc + + niu_node->bw_info[CAM_CPAS_PORT_DRV_1].drv_vote.high.camnoc + + niu_node->bw_info[CAM_CPAS_PORT_DRV_1].drv_vote.low.camnoc + + niu_node->bw_info[CAM_CPAS_PORT_DRV_2].drv_vote.high.camnoc + + niu_node->bw_info[CAM_CPAS_PORT_DRV_2].drv_vote.low.camnoc; + + total_camnoc_bw = bw_per_kb; remainder = do_div(bw_per_kb, niu_node->niu_size); total_bw_per_kb += bw_per_kb; @@ -781,8 +792,8 @@ static bool cam_cpas_calculate_smart_qos( max_bw_per_kb = bw_per_kb; CAM_DBG(CAM_PERF, - "NIU[%d][%s]camnoc_bw %llu, niu_size %u, bw_per_kb %lld, remainder %lld, max_bw_per_kb %lld, total_bw_per_kb %lld", - i, niu_node->node_name, niu_node->camnoc_bw, niu_node->niu_size, + "NIU[%d][%s]camnoc_bw %llu, niu_size %u, init_bw_per_kb %lld, remainder %lld, max_bw_per_kb %lld, total_bw_per_kb %lld", + i, niu_node->node_name, total_camnoc_bw, niu_node->niu_size, bw_per_kb, remainder, max_bw_per_kb, total_bw_per_kb); } @@ -794,7 +805,16 @@ static bool cam_cpas_calculate_smart_qos( for (i = 0; i < soc_private->smart_qos_info->num_rt_wr_nius; i++) { niu_node = soc_private->smart_qos_info->rt_wr_niu_node[i]; - bw_per_kb = niu_node->camnoc_bw; + bw_per_kb = niu_node->bw_info[CAM_CPAS_PORT_HLOS_DRV].hlos_vote.camnoc; + + if (soc_private->enable_cam_clk_drv) + bw_per_kb += niu_node->bw_info[CAM_CPAS_PORT_DRV_0].drv_vote.high.camnoc + + niu_node->bw_info[CAM_CPAS_PORT_DRV_0].drv_vote.low.camnoc + + niu_node->bw_info[CAM_CPAS_PORT_DRV_1].drv_vote.high.camnoc + + niu_node->bw_info[CAM_CPAS_PORT_DRV_1].drv_vote.low.camnoc + + niu_node->bw_info[CAM_CPAS_PORT_DRV_2].drv_vote.high.camnoc + + niu_node->bw_info[CAM_CPAS_PORT_DRV_2].drv_vote.low.camnoc; + remainder = do_div(bw_per_kb, niu_node->niu_size); // --> dropping remainder if ((bw_per_kb * CAM_CPAS_MAX_STRESS_INDICATOR) > @@ -897,11 +917,24 @@ static bool cam_cpas_calculate_smart_qos( } if (cpas_core->smart_qos_dump && needs_update) { + uint64_t total_camnoc; for (i = 0; i < soc_private->smart_qos_info->num_rt_wr_nius; i++) { niu_node = soc_private->smart_qos_info->rt_wr_niu_node[i]; + + total_camnoc = niu_node->bw_info[CAM_CPAS_PORT_HLOS_DRV].hlos_vote.camnoc; + + if (soc_private->enable_cam_clk_drv) + total_camnoc += + niu_node->bw_info[CAM_CPAS_PORT_DRV_0].drv_vote.high.camnoc + + niu_node->bw_info[CAM_CPAS_PORT_DRV_0].drv_vote.low.camnoc + + niu_node->bw_info[CAM_CPAS_PORT_DRV_1].drv_vote.high.camnoc + + niu_node->bw_info[CAM_CPAS_PORT_DRV_1].drv_vote.low.camnoc + + niu_node->bw_info[CAM_CPAS_PORT_DRV_2].drv_vote.high.camnoc + + niu_node->bw_info[CAM_CPAS_PORT_DRV_2].drv_vote.low.camnoc; + CAM_INFO(CAM_PERF, - "Node[%d][%s]camnoc_bw=%lld, niu_size=%d, offset high 0x%x, low 0x%x, Priority new high 0x%x low 0x%x, applied high 0x%x low 0x%x", - i, niu_node->node_name, niu_node->camnoc_bw, niu_node->niu_size, + "Node[%d][%s] camnoc_bw=%lld, niu_size=%d, offset high 0x%x, low 0x%x, Priority new high 0x%x low 0x%x, applied high 0x%x low 0x%x", + i, niu_node->node_name, total_camnoc, niu_node->niu_size, niu_node->pri_lut_high_offset, niu_node->pri_lut_low_offset, niu_node->curr_priority_high, niu_node->curr_priority_low, niu_node->applied_priority_high, niu_node->applied_priority_low); @@ -955,93 +988,251 @@ static int cam_cpas_apply_smart_qos( return 0; } -static int cam_cpas_util_set_camnoc_axi_clk_rate( - struct cam_hw_info *cpas_hw) +static int cam_cpas_util_camnoc_drv_idx_to_cesta_hw_client_idx(int camnoc_drv_idx) +{ + int hw_client = -1; + + switch (camnoc_drv_idx) { + case CAM_CPAS_PORT_HLOS_DRV: + hw_client = -1; + break; + case CAM_CPAS_PORT_DRV_0: + hw_client = 0; + break; + case CAM_CPAS_PORT_DRV_1: + hw_client = 1; + break; + case CAM_CPAS_PORT_DRV_2: + hw_client = 2; + break; + default: + CAM_WARN(CAM_CPAS, "Invalid drv idx %d", camnoc_drv_idx); + break; + } + + return hw_client; +} + +static int cam_cpas_util_set_camnoc_axi_drv_clk_rate(struct cam_hw_soc_info *soc_info, + struct cam_cpas_private_soc *soc_private, struct cam_cpas *cpas_core, int cesta_drv_idx) +{ + struct cam_cpas_tree_node *tree_node = NULL; + uint64_t req_drv_high_camnoc_bw = 0, intermediate_drv_high_result = 0, + req_drv_low_camnoc_bw = 0, intermediate_drv_low_result = 0; + int64_t drv_high_clk_rate = 0, drv_low_clk_rate = 0; + int i, rc = 0; + + if (!soc_private->enable_cam_clk_drv) { + CAM_ERR(CAM_CPAS, "Clk DRV not enabled, can't set clk rates through cesta APIs"); + return -EINVAL; + } + + for (i = 0; i < CAM_CPAS_MAX_TREE_NODES; i++) { + tree_node = soc_private->tree_node[i]; + if (!tree_node || + !tree_node->camnoc_max_needed) + continue; + + if (req_drv_high_camnoc_bw < + (tree_node->bw_info[cesta_drv_idx].drv_vote.high.camnoc * + tree_node->bus_width_factor)) + req_drv_high_camnoc_bw = + (tree_node->bw_info[cesta_drv_idx].drv_vote.high.camnoc * + tree_node->bus_width_factor); + + if (req_drv_low_camnoc_bw < + (tree_node->bw_info[cesta_drv_idx].drv_vote.low.camnoc * + tree_node->bus_width_factor)) + req_drv_low_camnoc_bw = + (tree_node->bw_info[cesta_drv_idx].drv_vote.low.camnoc * + tree_node->bus_width_factor); + } + + intermediate_drv_high_result = req_drv_high_camnoc_bw * + soc_private->camnoc_axi_clk_bw_margin; + intermediate_drv_low_result = req_drv_low_camnoc_bw * + soc_private->camnoc_axi_clk_bw_margin; + do_div(intermediate_drv_high_result, 100); + do_div(intermediate_drv_low_result, 100); + req_drv_high_camnoc_bw += intermediate_drv_high_result; + req_drv_low_camnoc_bw += intermediate_drv_low_result; + + /* + * Since all low votes are considered as part of high votes as well, add low camnoc bw + * to final requested high camnoc bw value. + */ + req_drv_high_camnoc_bw += req_drv_low_camnoc_bw; + + intermediate_drv_high_result = req_drv_high_camnoc_bw; + intermediate_drv_low_result = req_drv_low_camnoc_bw; + do_div(intermediate_drv_high_result, soc_private->camnoc_bus_width); + do_div(intermediate_drv_low_result, soc_private->camnoc_bus_width); + drv_high_clk_rate = intermediate_drv_high_result; + drv_low_clk_rate = intermediate_drv_low_result; + + if (cpas_core->streamon_clients) { + int hw_client_idx; + + /* + * cesta_drv_idx is based on enum we set in dtsi properties which is +1 of actual + * corresponding hw client index + */ + hw_client_idx = cam_cpas_util_camnoc_drv_idx_to_cesta_hw_client_idx(cesta_drv_idx); + if (hw_client_idx == -1) { + CAM_ERR(CAM_CPAS, "Invalid hw client idx %d, cesta_drv_idx %d", + hw_client_idx, cesta_drv_idx); + return rc; + } + + if (debug_drv) + CAM_INFO(CAM_PERF, + "Setting camnoc axi cesta clk rate[BW Clk] : High [%llu %lld] Low [%llu %lld] cesta/hw_client_idx:[%d][%d]", + req_drv_high_camnoc_bw, drv_high_clk_rate, req_drv_low_camnoc_bw, + drv_low_clk_rate, cesta_drv_idx, hw_client_idx); + else + CAM_DBG(CAM_PERF, + "Setting camnoc axi cesta clk rate[BW Clk] : High [%llu %lld] Low [%llu %lld] cesta/hw_client_idx:[%d][%d]", + req_drv_high_camnoc_bw, drv_high_clk_rate, req_drv_low_camnoc_bw, + drv_low_clk_rate, cesta_drv_idx, hw_client_idx); + + rc = cam_soc_util_set_src_clk_rate(soc_info, hw_client_idx, + drv_high_clk_rate, drv_low_clk_rate); + if (rc) { + CAM_ERR(CAM_CPAS, + "Failed in setting camnoc cesta clk rates[high low]:[%ld %ld] client_idx:%d rc:%d", + drv_high_clk_rate, drv_low_clk_rate, hw_client_idx, + rc); + return rc; + } + + cpas_core->applied_camnoc_axi_rate.hw_client[hw_client_idx].high = + drv_high_clk_rate; + cpas_core->applied_camnoc_axi_rate.hw_client[hw_client_idx].low = + drv_low_clk_rate; + + if (debug_drv) + CAM_INFO(CAM_PERF, "Triggering channel switch for cesta client %d", + hw_client_idx); + else + CAM_DBG(CAM_PERF, "Triggering channel switch for cesta client %d", + hw_client_idx); + + rc = cam_soc_util_cesta_channel_switch(hw_client_idx, "cpas_update"); + if (rc) { + CAM_ERR(CAM_CPAS, "Failed to apply power states for cesta client:%d rc:%d", + hw_client_idx, rc); + return rc; + } + } + + return rc; +} + +static int cam_cpas_util_set_camnoc_axi_hlos_clk_rate(struct cam_hw_soc_info *soc_info, + struct cam_cpas_private_soc *soc_private, struct cam_cpas *cpas_core) +{ + struct cam_cpas_tree_node *tree_node = NULL; + uint64_t req_hlos_camnoc_bw = 0, intermediate_hlos_result = 0; + int64_t hlos_clk_rate = 0; + int i, rc = 0; + const struct camera_debug_settings *cam_debug = NULL; + + for (i = 0; i < CAM_CPAS_MAX_TREE_NODES; i++) { + tree_node = soc_private->tree_node[i]; + if (!tree_node || !tree_node->camnoc_max_needed) + continue; + + if (req_hlos_camnoc_bw < + (tree_node->bw_info[CAM_CPAS_PORT_HLOS_DRV].hlos_vote.camnoc * + tree_node->bus_width_factor)) { + req_hlos_camnoc_bw = + (tree_node->bw_info[CAM_CPAS_PORT_HLOS_DRV].hlos_vote.camnoc * + tree_node->bus_width_factor); + } + } + + intermediate_hlos_result = req_hlos_camnoc_bw * soc_private->camnoc_axi_clk_bw_margin; + do_div(intermediate_hlos_result, 100); + req_hlos_camnoc_bw += intermediate_hlos_result; + + if (cpas_core->streamon_clients && (req_hlos_camnoc_bw == 0)) { + CAM_DBG(CAM_CPAS, + "Set min vote if streamon_clients is non-zero : streamon_clients=%d", + cpas_core->streamon_clients); + req_hlos_camnoc_bw = CAM_CPAS_DEFAULT_AXI_BW; + } + + if ((req_hlos_camnoc_bw > 0) && (req_hlos_camnoc_bw < soc_private->camnoc_axi_min_ib_bw)) + req_hlos_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) + req_hlos_camnoc_bw = soc_private->camnoc_bus_width; + + else + req_hlos_camnoc_bw = cam_debug->cpas_settings.camnoc_bw; + CAM_INFO(CAM_CPAS, "Overriding camnoc bw: %llu", req_hlos_camnoc_bw); + } + + intermediate_hlos_result = req_hlos_camnoc_bw; + do_div(intermediate_hlos_result, soc_private->camnoc_bus_width); + hlos_clk_rate = intermediate_hlos_result; + + CAM_DBG(CAM_PERF, "Setting camnoc axi HLOS clk rate[BW Clk] : [%llu %lld]", + req_hlos_camnoc_bw, hlos_clk_rate); + + /* + * CPAS hw is not powered on for the first client. + * Also, clk_rate will be overwritten with default + * value while power on. So, skipping this for first + * client. + */ + if (cpas_core->streamon_clients) { + rc = cam_soc_util_set_src_clk_rate(soc_info, CAM_CLK_SW_CLIENT_IDX, + hlos_clk_rate, 0); + if (rc) + CAM_ERR(CAM_CPAS, + "Failed in setting camnoc axi clk [BW Clk]:[%llu %lld] rc:%d", + req_hlos_camnoc_bw, hlos_clk_rate, rc); + + cpas_core->applied_camnoc_axi_rate.sw_client = hlos_clk_rate; + } + + return rc; +} + +static int cam_cpas_util_set_camnoc_axi_clk_rate(struct cam_hw_info *cpas_hw, + int cesta_drv_idx) { struct cam_cpas_private_soc *soc_private = (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; 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; + struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info; + int rc = 0; + CAM_DBG(CAM_CPAS, "control_camnoc_axi_clk=%d", soc_private->control_camnoc_axi_clk); - CAM_DBG(CAM_CPAS, "control_camnoc_axi_clk=%d", - soc_private->control_camnoc_axi_clk); - - if (soc_private->control_camnoc_axi_clk) { - struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info; - uint64_t required_camnoc_bw = 0, intermediate_result = 0; - int64_t clk_rate = 0; - - for (i = 0; i < CAM_CPAS_MAX_TREE_NODES; i++) { - tree_node = soc_private->tree_node[i]; - if (!tree_node || - !tree_node->camnoc_max_needed) - continue; - - if (required_camnoc_bw < (tree_node->camnoc_bw * - tree_node->bus_width_factor)) { - required_camnoc_bw = tree_node->camnoc_bw * - tree_node->bus_width_factor; - } + if (cesta_drv_idx == CAM_CPAS_PORT_HLOS_DRV) { + rc = cam_cpas_util_set_camnoc_axi_hlos_clk_rate(soc_info, + soc_private, cpas_core); + if (rc) { + CAM_ERR(CAM_CPAS, "Failed in setting hlos clk rate rc: %d", + rc); + goto end; } - - intermediate_result = required_camnoc_bw * - soc_private->camnoc_axi_clk_bw_margin; - do_div(intermediate_result, 100); - required_camnoc_bw += intermediate_result; - - if (cpas_core->streamon_clients && (required_camnoc_bw == 0)) { - CAM_DBG(CAM_CPAS, - "Set min vote if streamon_clients is non-zero : streamon_clients=%d", - cpas_core->streamon_clients); - required_camnoc_bw = CAM_CPAS_DEFAULT_AXI_BW; - } - - if ((required_camnoc_bw > 0) && - (required_camnoc_bw < - 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; - - CAM_DBG(CAM_CPAS, - "Setting camnoc axi clk rate[BW Clk] : [%llu %lld]", - required_camnoc_bw, clk_rate); - - /* - * CPAS hw is not powered on for the first client. - * Also, clk_rate will be overwritten with default - * value while power on. So, skipping this for first - * client. - */ - if (cpas_core->streamon_clients) { - rc = cam_soc_util_set_src_clk_rate(soc_info, clk_rate); - if (rc) - CAM_ERR(CAM_CPAS, - "Failed in setting camnoc axi clk %llu %lld %d", - required_camnoc_bw, clk_rate, rc); - - cpas_core->applied_camnoc_axi_rate = clk_rate; + } else { + rc = cam_cpas_util_set_camnoc_axi_drv_clk_rate(soc_info, + soc_private, cpas_core, cesta_drv_idx); + if (rc) { + CAM_ERR(CAM_CPAS, + "Failed in setting drv clk rate drv_idx:%d rc: %d", + cesta_drv_idx, rc); + goto end; } } +end: return rc; } @@ -1169,76 +1360,63 @@ static int cam_cpas_axi_consolidate_path_votes( static int cam_cpas_update_axi_vote_bw( struct cam_hw_info *cpas_hw, struct cam_cpas_tree_node *cpas_tree_node, - int drv_voting_idx, + int ddr_drv_idx, int cesta_drv_idx, bool *mnoc_axi_port_updated, bool *camnoc_axi_port_updated) { - int i, axi_port_idx = -1; + int axi_port_idx = -1; struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; struct cam_cpas_private_soc *soc_private = (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; - bool is_mnoc_updated = false; - for (i = 0; i < CAM_CPAS_MAX_DRV_PORTS; i++) { - axi_port_idx = cpas_tree_node->axi_port_idx_arr[i]; - if ((axi_port_idx < 0) || (i != drv_voting_idx)) - continue; + axi_port_idx = cpas_tree_node->axi_port_idx_arr[ddr_drv_idx]; - if (axi_port_idx >= CAM_CPAS_MAX_AXI_PORTS) { - CAM_ERR(CAM_CPAS, "Invalid axi_port_idx: %d drv_idx: %d", axi_port_idx, i); - return -EINVAL; - } - - memcpy(&cpas_core->axi_port[axi_port_idx].curr_bw, &cpas_tree_node->bw_info[i], - sizeof(struct cam_cpas_axi_bw_info)); - - /* Add low value to high for drv */ - if (i > CAM_CPAS_PORT_HLOS_DRV) { - cpas_core->axi_port[axi_port_idx].curr_bw.drv_vote.high.ab += - cpas_core->axi_port[axi_port_idx].curr_bw.drv_vote.low.ab; - cpas_core->axi_port[axi_port_idx].curr_bw.drv_vote.high.ib += - cpas_core->axi_port[axi_port_idx].curr_bw.drv_vote.low.ib; - } - - mnoc_axi_port_updated[axi_port_idx] = true; - is_mnoc_updated = true; - } - - if (!is_mnoc_updated) { - CAM_ERR(CAM_CPAS, "No mnoc port was updated"); + if ((axi_port_idx < 0) || (axi_port_idx >= CAM_CPAS_MAX_AXI_PORTS)) { + CAM_ERR(CAM_CPAS, "Invalid axi_port_idx: %d drv_idx: %d", axi_port_idx, + ddr_drv_idx); return -EINVAL; } + memcpy(&cpas_core->axi_port[axi_port_idx].curr_bw, &cpas_tree_node->bw_info[ddr_drv_idx], + sizeof(struct cam_cpas_axi_bw_info)); + + /* Add low value to high for drv */ + if (ddr_drv_idx > CAM_CPAS_PORT_HLOS_DRV) { + cpas_core->axi_port[axi_port_idx].curr_bw.drv_vote.high.ab += + cpas_core->axi_port[axi_port_idx].curr_bw.drv_vote.low.ab; + cpas_core->axi_port[axi_port_idx].curr_bw.drv_vote.high.ib += + cpas_core->axi_port[axi_port_idx].curr_bw.drv_vote.low.ib; + } + + mnoc_axi_port_updated[axi_port_idx] = true; + if (soc_private->control_camnoc_axi_clk) return 0; - cpas_core->camnoc_axi_port[cpas_tree_node->axi_port_idx_arr[CAM_CPAS_PORT_HLOS_DRV]] - .camnoc_bw = cpas_tree_node->camnoc_bw; + if (cesta_drv_idx > CAM_CPAS_PORT_HLOS_DRV) + cpas_core->camnoc_axi_port[cpas_tree_node->axi_port_idx_arr[CAM_CPAS_PORT_HLOS_DRV]] + .curr_bw.hlos_vote.camnoc = + cpas_tree_node->bw_info[cesta_drv_idx].drv_vote.high.camnoc + + cpas_tree_node->bw_info[cesta_drv_idx].drv_vote.low.camnoc; + else + cpas_core->camnoc_axi_port[cpas_tree_node->axi_port_idx_arr[CAM_CPAS_PORT_HLOS_DRV]] + .curr_bw.hlos_vote.camnoc = + cpas_tree_node->bw_info[cesta_drv_idx].hlos_vote.camnoc; + camnoc_axi_port_updated[cpas_tree_node->camnoc_axi_port_idx] = true; return 0; } -static int cam_cpas_camnoc_set_vote_axi_clk_rate( - struct cam_hw_info *cpas_hw, +static int cam_cpas_camnoc_set_bw_vote(struct cam_hw_info *cpas_hw, bool *camnoc_axi_port_updated) { struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; - struct cam_cpas_private_soc *soc_private = - (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; int i; int rc = 0; struct cam_cpas_axi_port *camnoc_axi_port = NULL; uint64_t camnoc_bw; uint64_t applied_ab = 0, applied_ib = 0; - if (soc_private->control_camnoc_axi_clk) { - rc = cam_cpas_util_set_camnoc_axi_clk_rate(cpas_hw); - if (rc) - CAM_ERR(CAM_CPAS, - "Failed in setting axi clk rate rc=%d", rc); - return rc; - } - /* Below code is executed if we just vote and do not set the clk rate * for camnoc */ @@ -1257,10 +1435,10 @@ static int cam_cpas_camnoc_set_vote_axi_clk_rate( CAM_DBG(CAM_PERF, "Port[%s] : camnoc_bw=%lld", camnoc_axi_port->axi_port_name, - camnoc_axi_port->camnoc_bw); + camnoc_axi_port->curr_bw.hlos_vote.camnoc); - if (camnoc_axi_port->camnoc_bw) - camnoc_bw = camnoc_axi_port->camnoc_bw; + if (camnoc_axi_port->curr_bw.hlos_vote.camnoc) + camnoc_bw = camnoc_axi_port->curr_bw.hlos_vote.camnoc; else if (camnoc_axi_port->additional_bw) camnoc_bw = camnoc_axi_port->additional_bw; else if (cpas_core->streamon_clients) @@ -1304,13 +1482,14 @@ static int cam_cpas_util_apply_client_axi_vote( uint32_t path_data_type; bool mnoc_axi_port_updated[CAM_CPAS_MAX_AXI_PORTS] = {false}; bool camnoc_axi_port_updated[CAM_CPAS_MAX_AXI_PORTS] = {false}; - uint64_t curr_camnoc_old = 0, par_camnoc_old = 0; - struct cam_cpas_axi_bw_info curr_mnoc_old = {0}, par_mnoc_old = {0}, curr_port_bw = {0}, - applied_port_bw = {0}; - int rc = 0, i = 0, drv_voting_idx; + struct cam_cpas_axi_bw_info curr_mnoc_old = {0}, par_mnoc_old = {0}, curr_camnoc_old = {0}, + par_camnoc_old = {0}, curr_port_bw = {0}, applied_port_bw = {0}; + int rc = 0, i = 0, ddr_drv_idx, merge_type_factor = 1; bool apply_smart_qos = false; bool rt_bw_updated = false; bool camnoc_unchanged; + int cesta_drv_idx = CAM_CPAS_PORT_HLOS_DRV; + int first_ddr_drv_idx = -1, first_cesta_drv_idx = -1; mutex_lock(&cpas_core->tree_lock); if (!cpas_client->tree_node_valid) { @@ -1362,6 +1541,7 @@ static int cam_cpas_util_apply_client_axi_vote( con_axi_vote = &cpas_client->axi_vote; cam_cpas_dump_axi_vote_info(cpas_client, "Consolidated Vote", con_axi_vote); + cam_cpas_dump_full_tree_state(cpas_hw, "BeforeClientVoteUpdate"); /* Traverse through node tree and update bw vote values */ for (i = 0; i < con_axi_vote->num_paths; i++) { @@ -1369,131 +1549,213 @@ static int cam_cpas_util_apply_client_axi_vote( path_data_type = con_axi_vote->axi_path[i].path_data_type; transac_type = con_axi_vote->axi_path[i].transac_type; curr_tree_node = cpas_client->tree_node[path_data_type][transac_type]; - drv_voting_idx = curr_tree_node->drv_voting_idx; + ddr_drv_idx = curr_tree_node->drv_voting_idx; + cesta_drv_idx = curr_tree_node->drv_voting_idx; - if (cpas_core->force_hlos_drv) - drv_voting_idx = CAM_CPAS_PORT_HLOS_DRV; + if (!soc_private->enable_cam_ddr_drv || cpas_core->force_hlos_drv) { + ddr_drv_idx = CAM_CPAS_PORT_HLOS_DRV; + cesta_drv_idx = CAM_CPAS_PORT_HLOS_DRV; + } else if (!soc_private->enable_cam_clk_drv || cpas_core->force_cesta_sw_client) { + cesta_drv_idx = CAM_CPAS_PORT_HLOS_DRV; + } - if (curr_tree_node->camnoc_bw == con_axi_vote->axi_path[i].camnoc_bw) - camnoc_unchanged = true; + if ((ddr_drv_idx < 0) || (ddr_drv_idx > CAM_CPAS_PORT_DRV_2) || + (cesta_drv_idx < 0) || (cesta_drv_idx > CAM_CPAS_PORT_DRV_2)) { + CAM_ERR(CAM_CPAS, "Invalid drv idx : ddr_drv_idx=%d, cesta_drv_idx=%d", + ddr_drv_idx, cesta_drv_idx); + goto unlock_tree; + } - curr_camnoc_old = curr_tree_node->camnoc_bw; - memcpy(&curr_mnoc_old, &curr_tree_node->bw_info[drv_voting_idx], + if (i == 0) { + first_ddr_drv_idx = ddr_drv_idx; + first_cesta_drv_idx = cesta_drv_idx; + } else if ((first_ddr_drv_idx != ddr_drv_idx) || + (first_cesta_drv_idx != cesta_drv_idx)) { + /* + * drv indices won't change for a given client for different paths in a + * given axi vote update + */ + CAM_WARN(CAM_CPAS, "DRV indices different : DDR: %d, %d, CESTA %d %d", + first_ddr_drv_idx, ddr_drv_idx, first_cesta_drv_idx, cesta_drv_idx); + } + + memcpy(&curr_camnoc_old, &curr_tree_node->bw_info[cesta_drv_idx], + sizeof(struct cam_cpas_axi_bw_info)); + memcpy(&curr_mnoc_old, &curr_tree_node->bw_info[ddr_drv_idx], sizeof(struct cam_cpas_axi_bw_info)); + cam_cpas_dump_tree_vote_info(cpas_hw, curr_tree_node, "Level0 before update", + ddr_drv_idx, cesta_drv_idx); - cam_cpas_dump_tree_vote_info(curr_tree_node, "Level0 before update", - drv_voting_idx); + /* Check and update camnoc bw first */ + if (con_axi_vote->axi_path[i].vote_level == CAM_CPAS_VOTE_LEVEL_HIGH) { + if ((apply_type != CAM_CPAS_APPLY_TYPE_STOP) && + (curr_tree_node->bw_info[cesta_drv_idx].drv_vote.high.camnoc == + con_axi_vote->axi_path[i].camnoc_bw)) { + camnoc_unchanged = true; + goto update_l0_mnoc; + } - if (soc_private->enable_cam_ddr_drv && (con_axi_vote->axi_path[i].vote_level == - CAM_CPAS_VOTE_LEVEL_HIGH)) { + curr_tree_node->bw_info[cesta_drv_idx].drv_vote.high.camnoc = + con_axi_vote->axi_path[i].camnoc_bw; + curr_tree_node->bw_info[cesta_drv_idx].drv_vote.low.camnoc = 0; + } else { + if (cesta_drv_idx > CAM_CPAS_PORT_HLOS_DRV) { + if ((apply_type != CAM_CPAS_APPLY_TYPE_STOP) && + (curr_tree_node->bw_info[cesta_drv_idx].drv_vote.low.camnoc + == con_axi_vote->axi_path[i].camnoc_bw)) { + camnoc_unchanged = true; + goto update_l0_mnoc; + } + + curr_tree_node->bw_info[cesta_drv_idx].drv_vote.low.camnoc = + con_axi_vote->axi_path[i].camnoc_bw; + curr_tree_node->bw_info[cesta_drv_idx].drv_vote.high.camnoc = 0; + } else { + if (curr_tree_node->bw_info[cesta_drv_idx].hlos_vote.camnoc == + con_axi_vote->axi_path[i].camnoc_bw) { + camnoc_unchanged = true; + goto update_l0_mnoc; + } + + curr_tree_node->bw_info[cesta_drv_idx].hlos_vote.camnoc = + con_axi_vote->axi_path[i].camnoc_bw; + } + } + +update_l0_mnoc: + /* Check and update mnoc ab and ib */ + if (con_axi_vote->axi_path[i].vote_level == CAM_CPAS_VOTE_LEVEL_HIGH) { if ((apply_type != CAM_CPAS_APPLY_TYPE_STOP) && camnoc_unchanged && - (curr_tree_node->bw_info[drv_voting_idx].drv_vote.high.ab == + (curr_tree_node->bw_info[ddr_drv_idx].drv_vote.high.ab == con_axi_vote->axi_path[i].mnoc_ab_bw) && - (curr_tree_node->bw_info[drv_voting_idx].drv_vote.high.ib == + (curr_tree_node->bw_info[ddr_drv_idx].drv_vote.high.ib == con_axi_vote->axi_path[i].mnoc_ib_bw)) continue; - curr_tree_node->bw_info[drv_voting_idx].drv_vote.high.ab = + curr_tree_node->bw_info[ddr_drv_idx].drv_vote.high.ab = con_axi_vote->axi_path[i].mnoc_ab_bw; - curr_tree_node->bw_info[drv_voting_idx].drv_vote.high.ib = + curr_tree_node->bw_info[ddr_drv_idx].drv_vote.high.ib = con_axi_vote->axi_path[i].mnoc_ib_bw; - curr_tree_node->bw_info[drv_voting_idx].drv_vote.low.ab = 0; - curr_tree_node->bw_info[drv_voting_idx].drv_vote.low.ib = 0; + curr_tree_node->bw_info[ddr_drv_idx].drv_vote.low.ab = 0; + curr_tree_node->bw_info[ddr_drv_idx].drv_vote.low.ib = 0; } else { - if ((drv_voting_idx > CAM_CPAS_PORT_HLOS_DRV) && - !cpas_core->force_hlos_drv) { + if (ddr_drv_idx > CAM_CPAS_PORT_HLOS_DRV) { if ((apply_type != CAM_CPAS_APPLY_TYPE_STOP) && camnoc_unchanged && - (curr_tree_node->bw_info[drv_voting_idx].drv_vote.low.ab == + (curr_tree_node->bw_info[ddr_drv_idx].drv_vote.low.ab == con_axi_vote->axi_path[i].mnoc_ab_bw) && - (curr_tree_node->bw_info[drv_voting_idx].drv_vote.low.ib == + (curr_tree_node->bw_info[ddr_drv_idx].drv_vote.low.ib == con_axi_vote->axi_path[i].mnoc_ib_bw)) continue; - curr_tree_node->bw_info[drv_voting_idx].drv_vote.low.ab = + curr_tree_node->bw_info[ddr_drv_idx].drv_vote.low.ab = con_axi_vote->axi_path[i].mnoc_ab_bw; - curr_tree_node->bw_info[drv_voting_idx].drv_vote.low.ib = + curr_tree_node->bw_info[ddr_drv_idx].drv_vote.low.ib = con_axi_vote->axi_path[i].mnoc_ib_bw; - curr_tree_node->bw_info[drv_voting_idx].drv_vote.high.ab = 0; - curr_tree_node->bw_info[drv_voting_idx].drv_vote.high.ib = 0; + curr_tree_node->bw_info[ddr_drv_idx].drv_vote.high.ab = 0; + curr_tree_node->bw_info[ddr_drv_idx].drv_vote.high.ib = 0; } else { if (camnoc_unchanged && - (curr_tree_node->bw_info[drv_voting_idx].hlos_vote.ab == + (curr_tree_node->bw_info[ddr_drv_idx].hlos_vote.ab == con_axi_vote->axi_path[i].mnoc_ab_bw) && - (curr_tree_node->bw_info[drv_voting_idx].hlos_vote.ib == + (curr_tree_node->bw_info[ddr_drv_idx].hlos_vote.ib == con_axi_vote->axi_path[i].mnoc_ib_bw)) continue; - curr_tree_node->bw_info[drv_voting_idx].hlos_vote.ab = + curr_tree_node->bw_info[ddr_drv_idx].hlos_vote.ab = con_axi_vote->axi_path[i].mnoc_ab_bw; - curr_tree_node->bw_info[drv_voting_idx].hlos_vote.ib = + curr_tree_node->bw_info[ddr_drv_idx].hlos_vote.ib = con_axi_vote->axi_path[i].mnoc_ib_bw; } } - curr_tree_node->camnoc_bw = con_axi_vote->axi_path[i].camnoc_bw; - cam_cpas_dump_tree_vote_info(curr_tree_node, "Level0 after update", drv_voting_idx); + cam_cpas_dump_tree_vote_info(cpas_hw, curr_tree_node, "Level0 after update", + ddr_drv_idx, cesta_drv_idx); while (curr_tree_node->parent_node) { par_tree_node = curr_tree_node->parent_node; - par_camnoc_old = par_tree_node->camnoc_bw; - memcpy(&par_mnoc_old, &par_tree_node->bw_info[drv_voting_idx], + memcpy(&par_camnoc_old, &par_tree_node->bw_info[cesta_drv_idx], sizeof(struct cam_cpas_axi_bw_info)); - cam_cpas_dump_tree_vote_info(par_tree_node, "Parent before update", - drv_voting_idx); - - /* - * Remove contribution of current node old bw from parent, - * then add new bw of current level to the parent - */ - if (drv_voting_idx > CAM_CPAS_PORT_HLOS_DRV) { - par_tree_node->bw_info[drv_voting_idx].drv_vote.high.ab -= - curr_mnoc_old.drv_vote.high.ab; - par_tree_node->bw_info[drv_voting_idx].drv_vote.high.ib -= - curr_mnoc_old.drv_vote.high.ib; - par_tree_node->bw_info[drv_voting_idx].drv_vote.low.ab -= - curr_mnoc_old.drv_vote.low.ab; - par_tree_node->bw_info[drv_voting_idx].drv_vote.low.ib -= - curr_mnoc_old.drv_vote.low.ib; - - par_tree_node->bw_info[drv_voting_idx].drv_vote.high.ab += - curr_tree_node->bw_info[drv_voting_idx].drv_vote.high.ab; - par_tree_node->bw_info[drv_voting_idx].drv_vote.high.ib += - curr_tree_node->bw_info[drv_voting_idx].drv_vote.high.ib; - par_tree_node->bw_info[drv_voting_idx].drv_vote.low.ab += - curr_tree_node->bw_info[drv_voting_idx].drv_vote.low.ab; - par_tree_node->bw_info[drv_voting_idx].drv_vote.low.ib += - curr_tree_node->bw_info[drv_voting_idx].drv_vote.low.ib; - } else { - par_tree_node->bw_info[drv_voting_idx].hlos_vote.ab -= - curr_mnoc_old.hlos_vote.ab; - par_tree_node->bw_info[drv_voting_idx].hlos_vote.ib -= - curr_mnoc_old.hlos_vote.ib; - - par_tree_node->bw_info[drv_voting_idx].hlos_vote.ab += - curr_tree_node->bw_info[drv_voting_idx].hlos_vote.ab; - par_tree_node->bw_info[drv_voting_idx].hlos_vote.ib += - curr_tree_node->bw_info[drv_voting_idx].hlos_vote.ib; - } + memcpy(&par_mnoc_old, &par_tree_node->bw_info[ddr_drv_idx], + sizeof(struct cam_cpas_axi_bw_info)); + cam_cpas_dump_tree_vote_info(cpas_hw, par_tree_node, "Parent before update", + ddr_drv_idx, cesta_drv_idx); if (par_tree_node->merge_type == CAM_CPAS_TRAFFIC_MERGE_SUM) { - par_tree_node->camnoc_bw -= curr_camnoc_old; - par_tree_node->camnoc_bw += curr_tree_node->camnoc_bw; + merge_type_factor = 1; } else if (par_tree_node->merge_type == CAM_CPAS_TRAFFIC_MERGE_SUM_INTERLEAVE) { - par_tree_node->camnoc_bw -= (curr_camnoc_old / 2); - par_tree_node->camnoc_bw += (curr_tree_node->camnoc_bw / 2); + merge_type_factor = 2; } else { CAM_ERR(CAM_CPAS, "Invalid Merge type"); rc = -EINVAL; goto unlock_tree; } - cam_cpas_dump_tree_vote_info(par_tree_node, "Parent after update", - drv_voting_idx); + /* + * Remove contribution of current node old camnoc bw from parent, + * then add new camnoc bw of current level to the parent + */ + if (cesta_drv_idx > CAM_CPAS_PORT_HLOS_DRV) { + par_tree_node->bw_info[cesta_drv_idx].drv_vote.high.camnoc -= + (curr_camnoc_old.drv_vote.high.camnoc/merge_type_factor); + par_tree_node->bw_info[cesta_drv_idx].drv_vote.low.camnoc -= + (curr_camnoc_old.drv_vote.low.camnoc/merge_type_factor); + + par_tree_node->bw_info[cesta_drv_idx].drv_vote.high.camnoc += + (curr_tree_node->bw_info[cesta_drv_idx].drv_vote.high.camnoc/ + merge_type_factor); + par_tree_node->bw_info[cesta_drv_idx].drv_vote.low.camnoc += + (curr_tree_node->bw_info[cesta_drv_idx].drv_vote.low.camnoc/ + merge_type_factor); + } else { + par_tree_node->bw_info[cesta_drv_idx].hlos_vote.camnoc -= + (curr_camnoc_old.hlos_vote.camnoc/merge_type_factor); + + par_tree_node->bw_info[cesta_drv_idx].hlos_vote.camnoc += + (curr_tree_node->bw_info[cesta_drv_idx].hlos_vote.camnoc/ + merge_type_factor); + } + + /* + * Remove contribution of current node old mnoc bw from parent, + * then add new mnoc bw of current level to the parent + */ + if (ddr_drv_idx > CAM_CPAS_PORT_HLOS_DRV) { + par_tree_node->bw_info[ddr_drv_idx].drv_vote.high.ab -= + curr_mnoc_old.drv_vote.high.ab; + par_tree_node->bw_info[ddr_drv_idx].drv_vote.high.ib -= + curr_mnoc_old.drv_vote.high.ib; + par_tree_node->bw_info[ddr_drv_idx].drv_vote.low.ab -= + curr_mnoc_old.drv_vote.low.ab; + par_tree_node->bw_info[ddr_drv_idx].drv_vote.low.ib -= + curr_mnoc_old.drv_vote.low.ib; + + par_tree_node->bw_info[ddr_drv_idx].drv_vote.high.ab += + curr_tree_node->bw_info[ddr_drv_idx].drv_vote.high.ab; + par_tree_node->bw_info[ddr_drv_idx].drv_vote.high.ib += + curr_tree_node->bw_info[ddr_drv_idx].drv_vote.high.ib; + par_tree_node->bw_info[ddr_drv_idx].drv_vote.low.ab += + curr_tree_node->bw_info[ddr_drv_idx].drv_vote.low.ab; + par_tree_node->bw_info[ddr_drv_idx].drv_vote.low.ib += + curr_tree_node->bw_info[ddr_drv_idx].drv_vote.low.ib; + } else { + par_tree_node->bw_info[ddr_drv_idx].hlos_vote.ab -= + curr_mnoc_old.hlos_vote.ab; + par_tree_node->bw_info[ddr_drv_idx].hlos_vote.ib -= + curr_mnoc_old.hlos_vote.ib; + + par_tree_node->bw_info[ddr_drv_idx].hlos_vote.ab += + curr_tree_node->bw_info[ddr_drv_idx].hlos_vote.ab; + par_tree_node->bw_info[ddr_drv_idx].hlos_vote.ib += + curr_tree_node->bw_info[ddr_drv_idx].hlos_vote.ib; + } + + cam_cpas_dump_tree_vote_info(cpas_hw, par_tree_node, "Parent after update", + ddr_drv_idx, cesta_drv_idx); if (!par_tree_node->parent_node) { rc = cam_cpas_update_axi_vote_bw(cpas_hw, par_tree_node, - drv_voting_idx, mnoc_axi_port_updated, + ddr_drv_idx, cesta_drv_idx, mnoc_axi_port_updated, camnoc_axi_port_updated); if (rc) { CAM_ERR(CAM_CPAS, "Update Vote failed"); @@ -1502,11 +1764,14 @@ static int cam_cpas_util_apply_client_axi_vote( } curr_tree_node = par_tree_node; - curr_camnoc_old = par_camnoc_old; + memcpy(&curr_camnoc_old, &par_camnoc_old, + sizeof(struct cam_cpas_axi_bw_info)); memcpy(&curr_mnoc_old, &par_mnoc_old, sizeof(struct cam_cpas_axi_bw_info)); } } + cam_cpas_dump_full_tree_state(cpas_hw, "AfterClientVoteUpdate"); + if (!par_tree_node) { CAM_DBG(CAM_CPAS, "No change in BW for all paths"); rc = 0; @@ -1675,10 +1940,18 @@ vote_start_clients: sizeof(struct cam_cpas_axi_bw_info)); } - rc = cam_cpas_camnoc_set_vote_axi_clk_rate(cpas_hw, camnoc_axi_port_updated); - if (rc) { - CAM_ERR(CAM_CPAS, "Failed in setting axi clk rate rc=%d", rc); - goto unlock_tree; + if (soc_private->control_camnoc_axi_clk) { + rc = cam_cpas_util_set_camnoc_axi_clk_rate(cpas_hw, cesta_drv_idx); + if (rc) { + CAM_ERR(CAM_CPAS, "Failed in setting axi clk rate rc=%d", rc); + goto unlock_tree; + } + } else { + rc = cam_cpas_camnoc_set_bw_vote(cpas_hw, camnoc_axi_port_updated); + if (rc) { + CAM_ERR(CAM_CPAS, "Failed in setting camnoc bw vote rc=%d", rc); + goto unlock_tree; + } } if (soc_private->enable_smart_qos && apply_smart_qos) { @@ -1900,8 +2173,8 @@ static int cam_cpas_util_apply_client_ahb_vote(struct cam_hw_info *cpas_hw, } if (cpas_core->streamon_clients) { - rc = cam_soc_util_set_clk_rate_level(&cpas_hw->soc_info, - highest_level, true); + rc = cam_soc_util_set_clk_rate_level(&cpas_hw->soc_info, CAM_CLK_SW_CLIENT_IDX, + highest_level, 0, true); if (rc) { CAM_ERR(CAM_CPAS, "Failed in scaling clock rate level %d for AHB", @@ -2129,12 +2402,18 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, cam_cpas_dump_axi_vote_info(cpas_client, "CPAS Start Translated Vote", &axi_vote); if (cpas_core->streamon_clients == 0) { - if (cpas_core->force_hlos_drv) + if (cpas_core->force_hlos_drv) { soc_private->enable_cam_ddr_drv = false; + soc_private->enable_cam_clk_drv = false; + } + + if (cpas_core->force_cesta_sw_client) + soc_private->enable_cam_clk_drv = false; if (debug_drv) - CAM_INFO(CAM_CPAS, "DDR DRV enable:%s", - CAM_BOOL_TO_YESNO(soc_private->enable_cam_ddr_drv)); + CAM_INFO(CAM_CPAS, "DRV enable[DDR CLK]:[%s %s]", + CAM_BOOL_TO_YESNO(soc_private->enable_cam_ddr_drv), + CAM_BOOL_TO_YESNO(soc_private->enable_cam_clk_drv)); rc = cam_cpas_util_apply_default_axi_vote(cpas_hw, true); if (rc) @@ -2184,8 +2463,7 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, goto remove_ahb_vote; } } - CAM_DBG(CAM_CPAS, "irq_count=%d\n", - atomic_read(&cpas_core->irq_count)); + CAM_DBG(CAM_CPAS, "irq_count=%d\n", atomic_read(&cpas_core->irq_count)); if (soc_private->enable_smart_qos) cam_cpas_reset_niu_priorities(cpas_hw); @@ -2206,6 +2484,11 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, cpas_client->started = true; cpas_core->streamon_clients++; + if (debug_drv && (cpas_core->streamon_clients == 1)) { + cam_cpas_log_vote(cpas_hw, false); + cam_cpas_dump_full_tree_state(cpas_hw, "StartFirstClient"); + } + CAM_DBG(CAM_CPAS, "client=[%d][%s][%d] streamon_clients=%d", client_indx, cpas_client->data.identifier, cpas_client->data.cell_index, cpas_core->streamon_clients); @@ -2341,6 +2624,12 @@ static int cam_cpas_hw_stop(void *hw_priv, void *stop_args, goto done; cpas_client->started = false; + + if (debug_drv && (cpas_core->streamon_clients == 1)) { + cam_cpas_log_vote(cpas_hw, false); + cam_cpas_dump_full_tree_state(cpas_hw, "StopLastClient"); + } + cpas_core->streamon_clients--; if (cpas_core->streamon_clients == 0) { @@ -2613,7 +2902,6 @@ static int cam_cpas_log_vote(struct cam_hw_info *cpas_hw, bool ddr_only) struct cam_cpas_private_soc *soc_private = (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; uint32_t i; - struct cam_cpas_tree_node *curr_node; struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info; if ((cpas_core->streamon_clients > 0) && soc_private->enable_smart_qos && !ddr_only) @@ -2690,8 +2978,18 @@ static int cam_cpas_log_vote(struct cam_hw_info *cpas_hw, bool ddr_only) } if (soc_private->control_camnoc_axi_clk) { - CAM_INFO(CAM_CPAS, "applied camnoc axi clk[%lld]", - cpas_core->applied_camnoc_axi_rate); + CAM_INFO(CAM_CPAS, "applied camnoc axi clk sw_client[%lld]", + cpas_core->applied_camnoc_axi_rate.sw_client); + + if (soc_private->enable_cam_clk_drv) + CAM_INFO(CAM_CPAS, + "applied camnoc axi clk hw_client[high low] cesta_idx0:[%lld %lld] cesta_idx1:[%lld %lld] cesta_idx2:[%lld %lld]", + cpas_core->applied_camnoc_axi_rate.hw_client[0].high, + cpas_core->applied_camnoc_axi_rate.hw_client[0].low, + cpas_core->applied_camnoc_axi_rate.hw_client[1].high, + cpas_core->applied_camnoc_axi_rate.hw_client[1].low, + cpas_core->applied_camnoc_axi_rate.hw_client[2].high, + cpas_core->applied_camnoc_axi_rate.hw_client[2].low); } else { for (i = 0; i < cpas_core->num_camnoc_axi_ports; i++) { CAM_INFO(CAM_CPAS, @@ -2713,47 +3011,8 @@ static int cam_cpas_log_vote(struct cam_hw_info *cpas_hw, bool ddr_only) return 0; } - /* This will traverse through all nodes in the tree and print stats*/ - for (i = 0; i < CAM_CPAS_MAX_TREE_NODES; i++) { - if (!soc_private->tree_node[i]) - continue; - - curr_node = soc_private->tree_node[i]; - - CAM_INFO(CAM_CPAS, - "[%s] Cell[%d] level[%d] PortIdx[%d][%d] camnoc_bw[%d %d %lld %lld] mnoc_bw[%lld %lld]", - curr_node->node_name, curr_node->cell_idx, - curr_node->level_idx, - curr_node->axi_port_idx_arr[CAM_CPAS_PORT_HLOS_DRV], - curr_node->camnoc_axi_port_idx, - curr_node->camnoc_max_needed, - curr_node->bus_width_factor, - curr_node->camnoc_bw, - curr_node->camnoc_bw * curr_node->bus_width_factor, - curr_node->bw_info[CAM_CPAS_PORT_HLOS_DRV].hlos_vote.ab, - curr_node->bw_info[CAM_CPAS_PORT_HLOS_DRV].hlos_vote.ib); - - if (!soc_private->enable_cam_ddr_drv) - continue; - - CAM_INFO(CAM_CPAS, - "DRV PortIdx[%d][%d][%d] mnoc_bw DRV_0: [high[%lld %lld] low[%lld %lld]] DRV_1: [high[%lld %lld] low[%lld %lld]] DRV_2: [high[%lld %lld] low[%lld %lld]]", - curr_node->axi_port_idx_arr[CAM_CPAS_PORT_DRV_0], - curr_node->axi_port_idx_arr[CAM_CPAS_PORT_DRV_1], - curr_node->axi_port_idx_arr[CAM_CPAS_PORT_DRV_2], - curr_node->bw_info[CAM_CPAS_PORT_DRV_0].drv_vote.high.ab, - curr_node->bw_info[CAM_CPAS_PORT_DRV_0].drv_vote.high.ib, - curr_node->bw_info[CAM_CPAS_PORT_DRV_0].drv_vote.low.ab, - curr_node->bw_info[CAM_CPAS_PORT_DRV_0].drv_vote.low.ib, - curr_node->bw_info[CAM_CPAS_PORT_DRV_1].drv_vote.high.ab, - curr_node->bw_info[CAM_CPAS_PORT_DRV_1].drv_vote.high.ib, - curr_node->bw_info[CAM_CPAS_PORT_DRV_1].drv_vote.low.ab, - curr_node->bw_info[CAM_CPAS_PORT_DRV_1].drv_vote.low.ib, - curr_node->bw_info[CAM_CPAS_PORT_DRV_2].drv_vote.high.ab, - curr_node->bw_info[CAM_CPAS_PORT_DRV_2].drv_vote.high.ib, - curr_node->bw_info[CAM_CPAS_PORT_DRV_2].drv_vote.low.ab, - curr_node->bw_info[CAM_CPAS_PORT_DRV_2].drv_vote.low.ib); - } + /* This will traverse through all nodes in the tree and print stats */ + cam_cpas_dump_full_tree_state(cpas_hw, "state_dump_on_error"); cam_cpas_dump_monitor_array(cpas_hw); @@ -2800,13 +3059,16 @@ static void cam_cpas_update_monitor_array(struct cam_hw_info *cpas_hw, entry->axi_info[i].axi_port_name = cpas_core->axi_port[i].axi_port_name; memcpy(&entry->axi_info[i].curr_bw, &cpas_core->axi_port[i].curr_bw, sizeof(struct cam_cpas_axi_bw_info)); - entry->axi_info[i].camnoc_bw = cpas_core->axi_port[i].camnoc_bw; + + /* camnoc bw value not applicable for mnoc ports */ + entry->axi_info[i].camnoc_bw = 0; memcpy(&entry->axi_info[i].applied_bw, &cpas_core->axi_port[i].applied_bw, sizeof(struct cam_cpas_axi_bw_info)); entry->axi_info[i].is_drv_started = cpas_core->axi_port[i].is_drv_started; } - entry->applied_camnoc_clk = cpas_core->applied_camnoc_axi_rate; + memcpy(&entry->applied_camnoc_clk, &cpas_core->applied_camnoc_axi_rate, + sizeof(struct cam_soc_util_clk_rates)); entry->applied_ahb_level = cpas_core->ahb_bus_client.curr_vote_level; if ((cpas_core->streamon_clients > 0) && @@ -2933,32 +3195,37 @@ static void cam_cpas_dump_monitor_array( len = 0; CAM_INFO(CAM_CPAS, - "**** %llu:%llu:%llu.%llu : Index[%d] Identifier[%s][%d] camnoc=%lld, ahb=%d", + "**** %llu:%llu:%llu.%llu : Index[%d] Identifier[%s][%d] camnoc=sw : %ld, hw clients [%ld %ld][%ld %ld][%ld %ld], ahb=%d", hrs, min, sec, ms, index, entry->identifier_string, entry->identifier_value, - entry->applied_camnoc_clk, entry->applied_ahb_level); + entry->applied_camnoc_clk.sw_client, + entry->applied_camnoc_clk.hw_client[0].high, + entry->applied_camnoc_clk.hw_client[0].low, + entry->applied_camnoc_clk.hw_client[1].high, + entry->applied_camnoc_clk.hw_client[1].low, + entry->applied_camnoc_clk.hw_client[2].high, + entry->applied_camnoc_clk.hw_client[2].low, + entry->applied_ahb_level); for (j = 0; j < cpas_core->num_axi_ports; j++) { if ((entry->axi_info[j].applied_bw.vote_type == CAM_CPAS_VOTE_TYPE_DRV) && !cpas_core->force_hlos_drv) CAM_INFO(CAM_CPAS, - "BW [%s] : DRV started:%s high=[%lld %lld], low=[%lld %lld], camnoc=%lld", + "BW [%s] : DRV started:%s high=[%lld %lld], low=[%lld %lld]", entry->axi_info[j].axi_port_name, CAM_BOOL_TO_YESNO(entry->axi_info[j].is_drv_started), entry->axi_info[j].applied_bw.drv_vote.high.ab, entry->axi_info[j].applied_bw.drv_vote.high.ib, entry->axi_info[j].applied_bw.drv_vote.low.ab, - entry->axi_info[j].applied_bw.drv_vote.low.ib, - entry->axi_info[j].camnoc_bw); + entry->axi_info[j].applied_bw.drv_vote.low.ib); else CAM_INFO(CAM_CPAS, - "BW [%s] : HLOS ab=%lld, ib=%lld, DRV high_ab=%lld, high_ib=%lld, low_ab=%lld, low_ib=%lld, camnoc=%lld", + "BW [%s] : HLOS ab=%lld, ib=%lld, DRV high_ab=%lld, high_ib=%lld, low_ab=%lld, low_ib=%lld", entry->axi_info[j].axi_port_name, entry->axi_info[j].applied_bw.hlos_vote.ab, - entry->axi_info[j].applied_bw.hlos_vote.ib, - entry->axi_info[j].camnoc_bw); + entry->axi_info[j].applied_bw.hlos_vote.ib); } if (cpas_core->regbase_index[CAM_CPAS_REG_RPMH] != -1) { @@ -3237,8 +3504,8 @@ static int cam_cpas_hw_enable_domain_id_clks(struct cam_hw_info *cpas_hw, if (enable) { for (i = 0; i < domain_id_clks->number_clks; i++) { - rc = cam_soc_util_clk_enable(&cpas_hw->soc_info, true, - domain_id_clks->clk_idx[i], 0, NULL); + rc = cam_soc_util_clk_enable(&cpas_hw->soc_info, CAM_CLK_SW_CLIENT_IDX, + true, domain_id_clks->clk_idx[i], 0); if (rc) { CAM_ERR(CAM_CPAS, "Domain-id clk %s enable failed, rc: %d", domain_id_clks->clk_names[i], i); @@ -3248,8 +3515,8 @@ static int cam_cpas_hw_enable_domain_id_clks(struct cam_hw_info *cpas_hw, CAM_DBG(CAM_CPAS, "Domain-id clks enable success"); } else { for (i = 0; i < domain_id_clks->number_clks; i++) { - rc = cam_soc_util_clk_disable(&cpas_hw->soc_info, true, - domain_id_clks->clk_idx[i]); + rc = cam_soc_util_clk_disable(&cpas_hw->soc_info, CAM_CLK_SW_CLIENT_IDX, + true, domain_id_clks->clk_idx[i]); if (rc) CAM_WARN(CAM_CPAS, "Domain-id clk %s disable failed, rc: %d", domain_id_clks->clk_names[i], rc); @@ -3262,7 +3529,7 @@ static int cam_cpas_hw_enable_domain_id_clks(struct cam_hw_info *cpas_hw, clean_up: for (--i; i >= 0; i--) - cam_soc_util_clk_disable(&cpas_hw->soc_info, true, + cam_soc_util_clk_disable(&cpas_hw->soc_info, CAM_CLK_SW_CLIENT_IDX, true, domain_id_clks->clk_idx[i]); return rc; @@ -3636,6 +3903,10 @@ static int cam_cpas_util_create_debugfs(struct cam_cpas *cpas_core) debugfs_create_bool("force_hlos_drv", 0644, cpas_core->dentry, &cpas_core->force_hlos_drv); + + debugfs_create_bool("force_cesta_sw_client", 0644, + cpas_core->dentry, &cpas_core->force_cesta_sw_client); + end: return rc; } diff --git a/drivers/cam_cpas/cam_cpas_hw.h b/drivers/cam_cpas/cam_cpas_hw.h index b3f89501b1..495c1f8387 100644 --- a/drivers/cam_cpas/cam_cpas_hw.h +++ b/drivers/cam_cpas/cam_cpas_hw.h @@ -68,14 +68,6 @@ enum cam_cpas_access_type { CAM_REG_TYPE_READ_WRITE, }; -/** - * enum cam_cpas_vote_type - Enum for cpas vote type - */ -enum cam_cpas_vote_type { - CAM_CPAS_VOTE_TYPE_HLOS, - CAM_CPAS_VOTE_TYPE_DRV, -}; - /** * struct cam_cpas_vdd_ahb_mapping : Voltage to ahb level mapping * @@ -91,13 +83,15 @@ struct cam_cpas_vdd_ahb_mapping { /** * struct cam_cpas_bw_vote : AXI bw vote * - * @ab: AB bw value - * @ib: IB bw value + * @ab: AB bw value + * @ib: IB bw value + * @camnoc: CAMNOC bw value * */ struct cam_cpas_bw_vote { uint64_t ab; uint64_t ib; + uint64_t camnoc; }; /** @@ -237,7 +231,6 @@ struct cam_cpas_bus_client { * @cam_rsc_dev: Cam RSC device for DRV * @is_drv_started: Indicates if DRV started for RSC device corresponding to port * @curr_bw: Current voted bw after cpas consolidation - * @camnoc_bw: CAMNOC bw value for this port * @additional_bw: Additional bandwidth to cover non-hw cpas clients * @applied_bw: Actual applied bw to port */ @@ -251,7 +244,6 @@ struct cam_cpas_axi_port { const struct device *cam_rsc_dev; bool is_drv_started; struct cam_cpas_axi_bw_info curr_bw; - uint64_t camnoc_bw; uint64_t additional_bw; struct cam_cpas_axi_bw_info applied_bw; }; @@ -277,10 +269,10 @@ struct cam_cpas_axi_port_debug_info { * struct cam_cpas_monitor : CPAS monitor array * * @timestamp: Timestamp at which this monitor entry is saved - * @axi_info: AXI port information * @identifier_string: String passed by caller * @identifier_value: Identifier value passed by caller - * @applied_camnoc_clk: Applied camnoc axi clock rate + * @axi_info: AXI port information + * @applied_camnoc_clk: Applied camnoc axi clock rate with sw, hw clients * @applied_ahb_level: Applied camcc ahb level * @fe_ddr: RPMH DDR BCM FE (front-end) status register value. * This indicates requested clock plan @@ -304,7 +296,7 @@ struct cam_cpas_monitor { char identifier_string[128]; int32_t identifier_value; struct cam_cpas_axi_port_debug_info axi_info[CAM_CPAS_MAX_AXI_PORTS]; - uint64_t applied_camnoc_clk; + struct cam_soc_util_clk_rates applied_camnoc_clk; unsigned int applied_ahb_level; uint32_t fe_ddr; uint32_t be_ddr; @@ -343,7 +335,7 @@ struct cam_cpas_monitor { * @irq_count_wq: wait variable to ensure all irq's are handled * @dentry: debugfs file entry * @ahb_bus_scaling_disable: ahb scaling based on src clk corner for bus - * @applied_camnoc_axi_rate: applied camnoc axi clock rate + * @applied_camnoc_axi_rate: applied camnoc axi clock rate through sw, hw clients * @monitor_head: Monitor array head * @monitor_entries: cpas monitor array * @camnoc_info: Pointer to camnoc header info @@ -353,6 +345,7 @@ struct cam_cpas_monitor { * config issues * @smmu_fault_handled: Handled address decode error, on fault at SMMU * @force_hlos_drv: Whether to force disable DRV voting + * @force_cesta_sw_client: Whether to force voting through cesta sw client */ struct cam_cpas { struct cam_cpas_hw_caps hw_caps; @@ -375,7 +368,7 @@ struct cam_cpas { wait_queue_head_t irq_count_wq; struct dentry *dentry; bool ahb_bus_scaling_disable; - uint64_t applied_camnoc_axi_rate; + struct cam_soc_util_clk_rates applied_camnoc_axi_rate; atomic64_t monitor_head; struct cam_cpas_monitor monitor_entries[CAM_CPAS_MONITOR_MAX_ENTRIES]; void *camnoc_info; @@ -384,6 +377,7 @@ struct cam_cpas { bool slave_err_irq_en; bool smmu_fault_handled; bool force_hlos_drv; + bool force_cesta_sw_client; }; int cam_camsstop_get_internal_ops(struct cam_cpas_internal_ops *internal_ops); diff --git a/drivers/cam_cpas/cam_cpas_intf.c b/drivers/cam_cpas/cam_cpas_intf.c index e0a42db9f9..8de9601e4d 100644 --- a/drivers/cam_cpas/cam_cpas_intf.c +++ b/drivers/cam_cpas/cam_cpas_intf.c @@ -158,7 +158,20 @@ const char *cam_cpas_axi_util_drv_vote_lvl_to_string( } EXPORT_SYMBOL(cam_cpas_axi_util_drv_vote_lvl_to_string); -int cam_cpas_query_drv_enable(bool *is_drv_enabled) +const char *cam_cpas_util_vote_type_to_string(enum cam_cpas_vote_type vote_type) +{ + switch (vote_type) { + case CAM_CPAS_VOTE_TYPE_HLOS: + return "VOTE_TYPE_HLOS"; + case CAM_CPAS_VOTE_TYPE_DRV: + return "VOTE_TYPE_DRV"; + default: + return "VOTE_TYPE_INVALID"; + } +} +EXPORT_SYMBOL(cam_cpas_util_vote_type_to_string); + +int cam_cpas_query_drv_enable(bool *is_ddr_drv_enabled, bool *is_clk_drv_enabled) { struct cam_hw_info *cpas_hw = NULL; struct cam_cpas_private_soc *soc_private = NULL; @@ -168,15 +181,20 @@ int cam_cpas_query_drv_enable(bool *is_drv_enabled) return -ENODEV; } - if (!is_drv_enabled) { - CAM_ERR(CAM_CPAS, "invalid input %pK", is_drv_enabled); + if (!is_ddr_drv_enabled && !is_clk_drv_enabled) { + CAM_ERR(CAM_CPAS, "invalid input ddr: %pK clk: %pK", is_ddr_drv_enabled, + is_clk_drv_enabled); return -EINVAL; } cpas_hw = (struct cam_hw_info *) g_cpas_intf->hw_intf->hw_priv; soc_private = (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; - *is_drv_enabled = soc_private->enable_cam_ddr_drv; + if (is_ddr_drv_enabled) + *is_ddr_drv_enabled = soc_private->enable_cam_ddr_drv; + + if (is_clk_drv_enabled) + *is_clk_drv_enabled = soc_private->enable_cam_clk_drv; return 0; } diff --git a/drivers/cam_cpas/cam_cpas_soc.c b/drivers/cam_cpas/cam_cpas_soc.c index a976e642be..42d7729e42 100644 --- a/drivers/cam_cpas/cam_cpas_soc.c +++ b/drivers/cam_cpas/cam_cpas_soc.c @@ -24,27 +24,147 @@ module_param(cpas_dump, uint, 0644); #define CAM_ICP_CLK_NAME "cam_icp_clk" -void cam_cpas_dump_tree_vote_info(const struct cam_cpas_tree_node *tree_node, - const char *identifier, int drv_voting_idx) +void cam_cpas_dump_tree_vote_info(struct cam_hw_info *cpas_hw, + const struct cam_cpas_tree_node *tree_node, + const char *identifier, int ddr_drv_idx, int cesta_drv_idx) { - if (!cpas_dump) + struct cam_cpas_private_soc *soc_private = + (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; + + if ((cpas_dump & BIT(0)) == 0) return; - if (tree_node->bw_info[drv_voting_idx].vote_type == CAM_CPAS_VOTE_TYPE_DRV) + if (cesta_drv_idx > CAM_CPAS_PORT_HLOS_DRV) CAM_INFO(CAM_PERF, - "%s node:%s lvl:%d drv_idx:%d DRV BW camnoc[%llu] ab[%llu %llu] ib[%llu %llu]", - identifier, tree_node->node_name, tree_node->level_idx, drv_voting_idx, - tree_node->camnoc_bw, tree_node->bw_info[drv_voting_idx].drv_vote.high.ab, - tree_node->bw_info[drv_voting_idx].drv_vote.low.ab, - tree_node->bw_info[drv_voting_idx].drv_vote.high.ib, - tree_node->bw_info[drv_voting_idx].drv_vote.low.ib); + "%s node:%s lvl:%d cesta_drv_idx:%d DRV BW camnoc[%llu %llu]", + identifier, tree_node->node_name, tree_node->level_idx, cesta_drv_idx, + tree_node->bw_info[cesta_drv_idx].drv_vote.high.camnoc, + tree_node->bw_info[cesta_drv_idx].drv_vote.low.camnoc); else CAM_INFO(CAM_PERF, - "%s node:%s lvl:%d drv_idx:%d HLOS BW camnoc[%llu] ab[%llu] ib[%llu]", - identifier, tree_node->node_name, tree_node->level_idx, drv_voting_idx, - tree_node->camnoc_bw, tree_node->bw_info[drv_voting_idx].hlos_vote.ab, - tree_node->bw_info[drv_voting_idx].hlos_vote.ib); + "%s node:%s lvl:%d cesta_drv_idx:%d HLOS BW camnoc[%llu]", + identifier, tree_node->node_name, tree_node->level_idx, cesta_drv_idx, + tree_node->bw_info[cesta_drv_idx].hlos_vote.camnoc); + if (ddr_drv_idx > CAM_CPAS_PORT_HLOS_DRV) + CAM_INFO(CAM_PERF, + "%s node:%s lvl:%d ddr_drv_idx:%d DRV BW ab[%llu %llu] ib[%llu %llu]", + identifier, tree_node->node_name, tree_node->level_idx, ddr_drv_idx, + tree_node->bw_info[ddr_drv_idx].drv_vote.high.ab, + tree_node->bw_info[ddr_drv_idx].drv_vote.low.ab, + tree_node->bw_info[ddr_drv_idx].drv_vote.high.ib, + tree_node->bw_info[ddr_drv_idx].drv_vote.low.ib); + else + CAM_INFO(CAM_PERF, + "%s node:%s lvl:%d ddr_drv_idx:%d HLOS BW ab[%llu] ib[%llu]", + identifier, tree_node->node_name, tree_node->level_idx, ddr_drv_idx, + tree_node->bw_info[ddr_drv_idx].hlos_vote.ab, + tree_node->bw_info[ddr_drv_idx].hlos_vote.ib); + + if (soc_private->enable_cam_ddr_drv) { + int i; + + CAM_INFO(CAM_PERF, + "%s node:%s lvl:%d drv_idx:%d cesta_drv_idx:%d ==== printing full node state", + identifier, tree_node->node_name, tree_node->level_idx, + ddr_drv_idx, cesta_drv_idx); + + for (i = 0; i < CAM_CPAS_MAX_DRV_PORTS; i++) { + + if (i == CAM_CPAS_PORT_HLOS_DRV) + CAM_INFO(CAM_PERF, + "idx[%d] HLOS camnoc[%llu], DDR ab[%llu] ib[%llu]", + i, + tree_node->bw_info[i].hlos_vote.camnoc, + tree_node->bw_info[i].hlos_vote.ab, + tree_node->bw_info[i].hlos_vote.ib); + else + CAM_INFO(CAM_PERF, + "idx[%d] DRV camnoc[%llu %llu], DDR ab[%llu %llu] ib[%llu %llu]", + i, + tree_node->bw_info[i].drv_vote.high.camnoc, + tree_node->bw_info[i].drv_vote.low.camnoc, + tree_node->bw_info[i].drv_vote.high.ab, + tree_node->bw_info[i].drv_vote.low.ab, + tree_node->bw_info[i].drv_vote.high.ib, + tree_node->bw_info[i].drv_vote.low.ib); + } + } + +} + +void cam_cpas_dump_full_tree_state(struct cam_hw_info *cpas_hw, const char *identifier) +{ + int j; + struct cam_cpas_private_soc *soc_private = + (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; + struct cam_cpas_tree_node *curr_node; + + if ((cpas_dump & BIT(1)) == 0) + return; + + CAM_INFO(CAM_CPAS, "Dumping cpas tree full state start ============== %s", identifier); + + /* This will traverse through all nodes in the tree and print stats*/ + for (j = 0; j < CAM_CPAS_MAX_TREE_NODES; j++) { + if (!soc_private->tree_node[j]) + continue; + + curr_node = soc_private->tree_node[j]; + + if (soc_private->enable_cam_ddr_drv) { + int i; + + CAM_INFO(CAM_PERF, + "Identifier[%s] node:[%s] cell:%d lvl:%d PortIdx mnoc[%d %d %d %d] camnoc[%d] camnoc_max %d, bus_width:%d, drv_idx:%d", + identifier, curr_node->node_name, curr_node->cell_idx, + curr_node->level_idx, + curr_node->axi_port_idx_arr[CAM_CPAS_PORT_HLOS_DRV], + curr_node->axi_port_idx_arr[CAM_CPAS_PORT_DRV_0], + curr_node->axi_port_idx_arr[CAM_CPAS_PORT_DRV_1], + curr_node->axi_port_idx_arr[CAM_CPAS_PORT_DRV_2], + curr_node->camnoc_axi_port_idx, + curr_node->camnoc_max_needed, + curr_node->bus_width_factor, + curr_node->drv_voting_idx); + + for (i = 0; i < CAM_CPAS_MAX_DRV_PORTS; i++) { + if (i == CAM_CPAS_PORT_HLOS_DRV) + CAM_INFO(CAM_PERF, + " idx[%d] HLOS camnoc[%llu], DDR ab[%llu] ib[%llu]", + i, + curr_node->bw_info[i].hlos_vote.camnoc, + curr_node->bw_info[i].hlos_vote.ab, + curr_node->bw_info[i].hlos_vote.ib); + else + CAM_INFO(CAM_PERF, + " idx[%d] DRV camnoc[%llu %llu], DDR ab[%llu %llu] ib[%llu %llu]", + i, + curr_node->bw_info[i].drv_vote.high.camnoc, + curr_node->bw_info[i].drv_vote.low.camnoc, + curr_node->bw_info[i].drv_vote.high.ab, + curr_node->bw_info[i].drv_vote.low.ab, + curr_node->bw_info[i].drv_vote.high.ib, + curr_node->bw_info[i].drv_vote.low.ib); + } + } else { + CAM_INFO(CAM_CPAS, + "[%s] Cell[%d] level[%d] PortIdx[%d][%d] camnoc_bw[%d %d %lld %lld] mnoc_bw[%lld %lld]", + curr_node->node_name, curr_node->cell_idx, + curr_node->level_idx, + curr_node->axi_port_idx_arr[CAM_CPAS_PORT_HLOS_DRV], + curr_node->camnoc_axi_port_idx, + curr_node->camnoc_max_needed, + curr_node->bus_width_factor, + curr_node->bw_info[CAM_CPAS_PORT_HLOS_DRV].hlos_vote.camnoc, + curr_node->bw_info[CAM_CPAS_PORT_HLOS_DRV].hlos_vote.camnoc * + curr_node->bus_width_factor, + curr_node->bw_info[CAM_CPAS_PORT_HLOS_DRV].hlos_vote.ab, + curr_node->bw_info[CAM_CPAS_PORT_HLOS_DRV].hlos_vote.ib); + } + } + + CAM_INFO(CAM_CPAS, "Dumping cpas tree full state end ============== %s", identifier); } void cam_cpas_dump_axi_vote_info( @@ -54,7 +174,7 @@ void cam_cpas_dump_axi_vote_info( { int i; - if (!cpas_dump) + if ((cpas_dump & BIT(0)) == 0) return; if (!axi_vote || (axi_vote->num_paths > @@ -85,7 +205,7 @@ void cam_cpas_util_debug_parse_data( int i, j; struct cam_cpas_tree_node *curr_node = NULL; - if (!cpas_dump) + if ((cpas_dump & BIT(0)) == 0) return; for (i = 0; i < CAM_CPAS_MAX_TREE_NODES; i++) { @@ -110,8 +230,8 @@ void cam_cpas_util_debug_parse_data( curr_node->path_trans_type), curr_node->drv_voting_idx); for (j = 0; j < CAM_CPAS_PATH_DATA_MAX; j++) { - CAM_INFO(CAM_CPAS, "Constituent path: %d", - curr_node->constituent_paths[j] ? j : -1); + if (curr_node->constituent_paths[j]) + CAM_INFO(CAM_CPAS, "Constituent path: %d", j); } } @@ -609,9 +729,11 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core, client_name, curr_node_ptr->drv_voting_idx); } - CAM_DBG(CAM_CPAS, "Client Node Added: %d %d %s %d", + CAM_DBG(CAM_CPAS, + "Node Added: Client[%s] DataType[%d] TransType[%d] DRV idx[%d]", + client_name, curr_node_ptr->path_data_type, - curr_node_ptr->path_trans_type, client_name, + curr_node_ptr->path_trans_type, curr_node_ptr->drv_voting_idx); } @@ -1462,6 +1584,25 @@ int cam_cpas_get_custom_dt_info(struct cam_hw_info *cpas_hw, if (cam_drv_en_mask_val & CAM_DDR_DRV) soc_private->enable_cam_ddr_drv = true; + if (cam_drv_en_mask_val & CAM_CLK_DRV) { + if (!soc_private->enable_cam_ddr_drv) { + CAM_ERR(CAM_CPAS, "DDR DRV needs to be enabled for Clock DRV"); + rc = -EPERM; + goto cleanup_clients; + } + + soc_private->enable_cam_clk_drv = true; + rc = cam_soc_util_cesta_populate_crm_device(); + if (rc) { + CAM_ERR(CAM_CPAS, "Failed to populate camera cesta crm device rc: %d", rc); + goto cleanup_clients; + } + } + + CAM_DBG(CAM_CPAS, "enable_cam_ddr_drv %d enable_cam_clk_drv %d cam_drv_en_mask_val %d", + soc_private->enable_cam_ddr_drv, soc_private->enable_cam_clk_drv, + cam_drv_en_mask_val); + rc = cam_cpas_parse_node_tree(cpas_core, of_node, soc_private); if (rc) { CAM_ERR(CAM_CPAS, "Node tree parsing failed rc: %d", rc); @@ -1593,6 +1734,8 @@ int cam_cpas_soc_init_resources(struct cam_hw_soc_info *soc_info, soc_private = (struct cam_cpas_private_soc *)soc_info->soc_private; + soc_info->is_clk_drv_en = soc_private->enable_cam_clk_drv; + rc = cam_soc_util_get_option_clk_by_name(soc_info, CAM_ICP_CLK_NAME, &soc_private->icp_clk_index); if (rc) { @@ -1653,9 +1796,13 @@ int cam_cpas_soc_deinit_resources(struct cam_hw_soc_info *soc_info) int cam_cpas_soc_enable_resources(struct cam_hw_soc_info *soc_info, enum cam_vote_level default_level) { + struct cam_cpas_private_soc *soc_private = soc_info->soc_private; int rc = 0; - rc = cam_soc_util_enable_platform_resource(soc_info, true, + /* set this everytime in order to support debugfs to disable clk drv between runs */ + soc_info->is_clk_drv_en = soc_private->enable_cam_clk_drv; + + rc = cam_soc_util_enable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDX, true, default_level, true); if (rc) CAM_ERR(CAM_CPAS, "enable platform resource failed, rc=%d", rc); @@ -1668,7 +1815,7 @@ int cam_cpas_soc_disable_resources(struct cam_hw_soc_info *soc_info, { int rc = 0; - rc = cam_soc_util_disable_platform_resource(soc_info, + rc = cam_soc_util_disable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDX, disable_clocks, disable_irq); if (rc) CAM_ERR(CAM_CPAS, "disable platform failed, rc=%d", rc); diff --git a/drivers/cam_cpas/cam_cpas_soc.h b/drivers/cam_cpas/cam_cpas_soc.h index b5c283bce5..677b33b306 100644 --- a/drivers/cam_cpas/cam_cpas_soc.h +++ b/drivers/cam_cpas/cam_cpas_soc.h @@ -28,7 +28,6 @@ * @path_trans_type: Transaction type info from device tree (rd, wr) * @merge_type: Traffic merge type (calculation info) from device tree * @bus_width_factor: Factor for accounting bus width in CAMNOC bw calculation - * @camnoc_bw: CAMNOC bw value at current node * @bw_info: AXI BW info for all drv ports * @camnoc_max_needed: If node is needed for CAMNOC BW calculation then true * @constituent_paths: Constituent paths presence info from device tree @@ -60,7 +59,6 @@ struct cam_cpas_tree_node { uint32_t path_trans_type; uint32_t merge_type; uint32_t bus_width_factor; - uint64_t camnoc_bw; struct cam_cpas_axi_bw_info *bw_info; bool camnoc_max_needed; bool constituent_paths[CAM_CPAS_PATH_DATA_MAX]; @@ -210,6 +208,7 @@ struct cam_cpas_domain_id_support_clks { * @llcc_info: Cache info * @enable_smart_qos: Whether to enable Smart QoS mechanism on current chipset * @enable_cam_ddr_drv: Whether to enable Camera DDR DRV on current chipset + * @enable_cam_clk_drv: Whether to enable Camera Clk DRV on current chipset * @smart_qos_info: Pointer to smart qos info * @icp_clk_index: Index of optional icp clk * @domain_id_info: Stores all information related to domain id support @@ -238,14 +237,17 @@ struct cam_cpas_private_soc { struct cam_sys_cache_info *llcc_info; bool enable_smart_qos; bool enable_cam_ddr_drv; + bool enable_cam_clk_drv; struct cam_cpas_smart_qos_info *smart_qos_info; int32_t icp_clk_index; struct cam_cpas_domain_id_info domain_id_info; struct cam_cpas_domain_id_support_clks *domain_id_clks; }; -void cam_cpas_dump_tree_vote_info(const struct cam_cpas_tree_node *tree_node, - const char *identifier, int drv_voting_idx); +void cam_cpas_dump_tree_vote_info(struct cam_hw_info *cpas_hw, + const struct cam_cpas_tree_node *tree_node, + const char *identifier, int ddr_drv_idx, int cesta_drv_idx); +void cam_cpas_dump_full_tree_state(struct cam_hw_info *cpas_hw, const char *identifier); void cam_cpas_util_debug_parse_data(struct cam_cpas_private_soc *soc_private); void cam_cpas_dump_axi_vote_info( diff --git a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c index 2867e6b67a..24709d33b4 100644 --- a/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c +++ b/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c @@ -957,8 +957,8 @@ static int cam_cpastop_qchannel_handshake(struct cam_hw_info *cpas_hw, CAM_ERR(CAM_CPAS, "ICP clock not added as optional clk, qchannel handshake will fail"); } else { - ret = cam_soc_util_clk_enable(soc_info, true, soc_private->icp_clk_index, - -1, NULL); + ret = cam_soc_util_clk_enable(soc_info, CAM_CLK_SW_CLIENT_IDX, true, + soc_private->icp_clk_index, -1); if (ret) CAM_ERR(CAM_CPAS, "Error enable icp clk failed rc=%d", ret); else @@ -1010,7 +1010,8 @@ static int cam_cpastop_qchannel_handshake(struct cam_hw_info *cpas_hw, rc = -EBUSY; if (icp_clk_enabled) { - ret = cam_soc_util_clk_disable(soc_info, true, soc_private->icp_clk_index); + ret = cam_soc_util_clk_disable(soc_info, CAM_CLK_SW_CLIENT_IDX, true, + soc_private->icp_clk_index); if (ret) CAM_ERR(CAM_CPAS, "Error disable icp clk failed rc=%d", rc); } diff --git a/drivers/cam_cpas/include/cam_cpas_api.h b/drivers/cam_cpas/include/cam_cpas_api.h index 549c63a57a..86efa7ce64 100644 --- a/drivers/cam_cpas/include/cam_cpas_api.h +++ b/drivers/cam_cpas/include/cam_cpas_api.h @@ -24,10 +24,22 @@ #define CAM_CPAS_MAX_PATHS_PER_CLIENT 15 #define CAM_CPAS_API_PATH_DATA_STD_START 512 +#define CAM_CPAS_VOTE_LEVEL_NONE 0 +#define CAM_CPAS_VOTE_LEVEL_MAX 3 + /* Qos Selection mask */ #define CAM_CPAS_QOS_DEFAULT_SETTINGS_MASK 0x1 #define CAM_CPAS_QOS_CUSTOM_SETTINGS_MASK 0x2 +/** + * enum cam_cpas_vote_type - Enum for cpas vote type + */ +enum cam_cpas_vote_type { + CAM_CPAS_VOTE_TYPE_HLOS, + CAM_CPAS_VOTE_TYPE_DRV, + CAM_CPAS_VOTE_TYPE_MAX, +}; + /** * enum cam_cpas_reg_base - Enum for register base identifier. These * are the identifiers used in generic register @@ -773,6 +785,18 @@ const char *cam_cpas_axi_util_trans_type_to_string( const char *cam_cpas_axi_util_drv_vote_lvl_to_string( uint32_t vote_lvl); +/** + * cam_cpas_util_vote_type_to_string() + * + * @brief: API to get string for given vote type + * + * @vote_type : DRV vote level + * + * @return string. + * + */ +const char *cam_cpas_util_vote_type_to_string(enum cam_cpas_vote_type vote_type); + /** * cam_cpas_log_votes() * @@ -892,12 +916,13 @@ int cam_cpas_csid_process_resume(uint32_t csid_idx); * cam_cpas_query_drv_enable() * * @brief: API to indicate DRV enabled on hw or not - * @is_drv_enabled: Indication to be set by the API + * @is_ddr_drv_enabled: If DDR DRV enabled + * @is_clk_drv_enabled: If Clock Cesta DRV enabled * * @return 0 on success * */ -int cam_cpas_query_drv_enable(bool *is_drv_enabled); +int cam_cpas_query_drv_enable(bool *is_ddr_drv_enabled, bool *is_clk_drv_enabled); /** * cam_cpas_query_domain_id_security_support() diff --git a/drivers/cam_cre/cam_cre_hw_mgr/cre_hw/cre_core.c b/drivers/cam_cre/cam_cre_hw_mgr/cre_hw/cre_core.c index c27c8d1b9c..49a8ac3b86 100644 --- a/drivers/cam_cre/cam_cre_hw_mgr/cre_hw/cre_core.c +++ b/drivers/cam_cre/cam_cre_hw_mgr/cre_hw/cre_core.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -478,7 +479,7 @@ int cam_cre_process_cmd(void *device_priv, uint32_t cmd_type, (struct cam_cre_dev_clk_update *)cmd_args; if (!core_info->clk_enable) { - rc = cam_soc_util_clk_enable_default(soc_info, + rc = cam_soc_util_clk_enable_default(soc_info, CAM_CLK_SW_CLIENT_IDX, CAM_SVS_VOTE); if (rc) { CAM_ERR(CAM_CRE, "Clock enable is failed"); @@ -494,7 +495,7 @@ int cam_cre_process_cmd(void *device_priv, uint32_t cmd_type, break; case CRE_HW_CLK_DISABLE: { if (core_info->clk_enable) - cam_soc_util_clk_disable_default(soc_info); + cam_soc_util_clk_disable_default(soc_info, CAM_CLK_SW_CLIENT_IDX); core_info->clk_enable = false; } diff --git a/drivers/cam_cre/cam_cre_hw_mgr/cre_hw/cre_soc.c b/drivers/cam_cre/cam_cre_hw_mgr/cre_hw/cre_soc.c index 1bc171d221..fa0c68cd3d 100644 --- a/drivers/cam_cre/cam_cre_hw_mgr/cre_hw/cre_soc.c +++ b/drivers/cam_cre/cam_cre_hw_mgr/cre_hw/cre_soc.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -35,7 +36,7 @@ int cam_cre_enable_soc_resources(struct cam_hw_soc_info *soc_info) { int rc; - rc = cam_soc_util_enable_platform_resource(soc_info, true, + rc = cam_soc_util_enable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDX, true, CAM_SVS_VOTE, true); if (rc) CAM_ERR(CAM_CRE, "enable platform failed %d", rc); @@ -47,7 +48,7 @@ int cam_cre_disable_soc_resources(struct cam_hw_soc_info *soc_info) { int rc; - rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + rc = cam_soc_util_disable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDX, true, true); if (rc) CAM_ERR(CAM_CRE, "disable platform failed %d", rc); @@ -79,5 +80,5 @@ int cam_cre_update_clk_rate(struct cam_hw_soc_info *soc_info, CAM_DBG(CAM_CRE, "clk_rate = %u src_clk_index = %d", clk_rate, src_clk_idx); - return cam_soc_util_set_src_clk_rate(soc_info, clk_rate); + return cam_soc_util_set_src_clk_rate(soc_info, CAM_CLK_SW_CLIENT_IDX, clk_rate, 0); } diff --git a/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_soc.c b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_soc.c index 1a8b08227c..a03ee982d1 100644 --- a/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_soc.c +++ b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_soc.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -130,7 +131,7 @@ int cam_custom_hw_sub_mod_enable_soc_resources(struct cam_hw_soc_info *soc_info) goto end; } - rc = cam_soc_util_enable_platform_resource(soc_info, true, + rc = cam_soc_util_enable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDX, true, CAM_LOWSVS_VOTE, true); if (rc) { CAM_ERR(CAM_CUSTOM, "Error! enable platform failed rc=%d", rc); @@ -158,7 +159,7 @@ int cam_custom_hw_sub_mod_disable_soc_resources( } soc_private = soc_info->soc_private; - rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + rc = cam_soc_util_disable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDX, true, true); if (rc) { CAM_ERR(CAM_CUSTOM, "Disable platform failed rc=%d", rc); return rc; diff --git a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c index c3d5a68c69..2456cf4e5d 100644 --- a/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c +++ b/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -130,8 +131,8 @@ int cam_fd_soc_enable_resources(struct cam_hw_soc_info *soc_info) return -EFAULT; } - rc = cam_soc_util_enable_platform_resource(soc_info, true, CAM_SVS_VOTE, - true); + rc = cam_soc_util_enable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDX, true, + CAM_SVS_VOTE, true); if (rc) { CAM_ERR(CAM_FD, "Error enable platform failed, rc=%d", rc); goto stop_cpas; @@ -158,7 +159,7 @@ int cam_fd_soc_disable_resources(struct cam_hw_soc_info *soc_info) } soc_private = soc_info->soc_private; - rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + rc = cam_soc_util_disable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDX, true, true); if (rc) { CAM_ERR(CAM_FD, "disable platform resources failed, rc=%d", rc); return rc; diff --git a/drivers/cam_icp/icp_hw/bps_hw/bps_soc.c b/drivers/cam_icp/icp_hw/bps_hw/bps_soc.c index d1a97de5c0..20aa1de5b9 100644 --- a/drivers/cam_icp/icp_hw/bps_hw/bps_soc.c +++ b/drivers/cam_icp/icp_hw/bps_hw/bps_soc.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -65,7 +66,7 @@ int cam_bps_enable_soc_resources(struct cam_hw_soc_info *soc_info) { int rc = 0; - rc = cam_soc_util_enable_platform_resource(soc_info, true, + rc = cam_soc_util_enable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDX, true, CAM_SVS_VOTE, false); if (rc) CAM_ERR(CAM_ICP, "enable platform failed"); @@ -78,7 +79,7 @@ int cam_bps_disable_soc_resources(struct cam_hw_soc_info *soc_info, { int rc = 0; - rc = cam_soc_util_disable_platform_resource(soc_info, disable_clk, + rc = cam_soc_util_disable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDX, disable_clk, false); if (rc) CAM_ERR(CAM_ICP, "disable platform failed"); @@ -155,7 +156,7 @@ int cam_bps_update_clk_rate(struct cam_hw_soc_info *soc_info, clk_rate = soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx]; } - return cam_soc_util_set_src_clk_rate(soc_info, clk_rate); + return cam_soc_util_set_src_clk_rate(soc_info, CAM_CLK_SW_CLIENT_IDX, clk_rate, 0); } int cam_bps_toggle_clk(struct cam_hw_soc_info *soc_info, bool clk_enable) @@ -163,9 +164,9 @@ int cam_bps_toggle_clk(struct cam_hw_soc_info *soc_info, bool clk_enable) int rc = 0; if (clk_enable) - rc = cam_soc_util_clk_enable_default(soc_info, CAM_SVS_VOTE); + rc = cam_soc_util_clk_enable_default(soc_info, CAM_CLK_SW_CLIENT_IDX, CAM_SVS_VOTE); else - cam_soc_util_clk_disable_default(soc_info); + cam_soc_util_clk_disable_default(soc_info, CAM_CLK_SW_CLIENT_IDX); return rc; } diff --git a/drivers/cam_icp/icp_hw/icp_proc/icp_common/cam_icp_soc_common.c b/drivers/cam_icp/icp_hw/icp_proc/icp_common/cam_icp_soc_common.c index f5a3350e35..bf837c9083 100644 --- a/drivers/cam_icp/icp_hw/icp_proc/icp_common/cam_icp_soc_common.c +++ b/drivers/cam_icp/icp_hw/icp_proc/icp_common/cam_icp_soc_common.c @@ -181,7 +181,7 @@ int cam_icp_soc_resources_enable(struct cam_hw_soc_info *soc_info) { int rc = 0; - rc = cam_soc_util_enable_platform_resource(soc_info, true, + rc = cam_soc_util_enable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDX, true, CAM_SVS_VOTE, true); if (rc) CAM_ERR(CAM_ICP, "failed to enable soc resources rc=%d", rc); @@ -193,7 +193,7 @@ int cam_icp_soc_resources_disable(struct cam_hw_soc_info *soc_info) { int rc = 0; - rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + rc = cam_soc_util_disable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDX, true, true); if (rc) CAM_ERR(CAM_ICP, "failed to disable soc resources rc=%d", rc); @@ -242,7 +242,7 @@ int cam_icp_soc_update_clk_rate(struct cam_hw_soc_info *soc_info, clk_rate = soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx]; } - rc = cam_soc_util_set_src_clk_rate(soc_info, clk_rate); + rc = cam_soc_util_set_src_clk_rate(soc_info, CAM_CLK_SW_CLIENT_IDX, clk_rate, 0); if (rc) return rc; diff --git a/drivers/cam_icp/icp_hw/ipe_hw/ipe_soc.c b/drivers/cam_icp/icp_hw/ipe_hw/ipe_soc.c index 656f4e1ce4..02426d97b3 100644 --- a/drivers/cam_icp/icp_hw/ipe_hw/ipe_soc.c +++ b/drivers/cam_icp/icp_hw/ipe_hw/ipe_soc.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -116,7 +117,7 @@ int cam_ipe_enable_soc_resources(struct cam_hw_soc_info *soc_info) { int rc = 0; - rc = cam_soc_util_enable_platform_resource(soc_info, true, + rc = cam_soc_util_enable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDX, true, CAM_SVS_VOTE, false); if (rc) { CAM_ERR(CAM_ICP, "enable platform failed"); @@ -131,7 +132,7 @@ int cam_ipe_disable_soc_resources(struct cam_hw_soc_info *soc_info, { int rc = 0; - rc = cam_soc_util_disable_platform_resource(soc_info, disable_clk, + rc = cam_soc_util_disable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDX, disable_clk, false); if (rc) CAM_ERR(CAM_ICP, "enable platform failed"); @@ -158,7 +159,7 @@ int cam_ipe_update_clk_rate(struct cam_hw_soc_info *soc_info, *clk_rate = soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx]; } - return cam_soc_util_set_src_clk_rate(soc_info, *clk_rate); + return cam_soc_util_set_src_clk_rate(soc_info, CAM_CLK_SW_CLIENT_IDX, *clk_rate, 0); } int cam_ipe_toggle_clk(struct cam_hw_soc_info *soc_info, bool clk_enable) @@ -166,9 +167,9 @@ int cam_ipe_toggle_clk(struct cam_hw_soc_info *soc_info, bool clk_enable) int rc = 0; if (clk_enable) - rc = cam_soc_util_clk_enable_default(soc_info, CAM_SVS_VOTE); + rc = cam_soc_util_clk_enable_default(soc_info, CAM_CLK_SW_CLIENT_IDX, CAM_SVS_VOTE); else - cam_soc_util_clk_disable_default(soc_info); + cam_soc_util_clk_disable_default(soc_info, CAM_CLK_SW_CLIENT_IDX); return rc; } diff --git a/drivers/cam_icp/icp_hw/ofe_hw/ofe_soc.c b/drivers/cam_icp/icp_hw/ofe_hw/ofe_soc.c index 3f1603c793..cd04c34493 100644 --- a/drivers/cam_icp/icp_hw/ofe_hw/ofe_soc.c +++ b/drivers/cam_icp/icp_hw/ofe_hw/ofe_soc.c @@ -66,7 +66,7 @@ int cam_ofe_enable_soc_resources(struct cam_hw_soc_info *soc_info) { int rc = 0; - rc = cam_soc_util_enable_platform_resource(soc_info, + rc = cam_soc_util_enable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDX, true, CAM_SVS_VOTE, false); if (rc) CAM_ERR(CAM_ICP, "enable platform failed"); @@ -79,7 +79,7 @@ int cam_ofe_disable_soc_resources(struct cam_hw_soc_info *soc_info, { int rc = 0; - rc = cam_soc_util_disable_platform_resource(soc_info, + rc = cam_soc_util_disable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDX, disable_clk, false); if (rc) CAM_ERR(CAM_ICP, "disable platform failed"); @@ -141,7 +141,7 @@ int cam_ofe_update_clk_rate(struct cam_hw_soc_info *soc_info, clk_rate = soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx]; } - return cam_soc_util_set_src_clk_rate(soc_info, clk_rate); + return cam_soc_util_set_src_clk_rate(soc_info, CAM_CLK_SW_CLIENT_IDX, clk_rate, 0); } int cam_ofe_toggle_clk(struct cam_hw_soc_info *soc_info, bool clk_enable) @@ -149,9 +149,9 @@ int cam_ofe_toggle_clk(struct cam_hw_soc_info *soc_info, bool clk_enable) int rc = 0; if (clk_enable) - rc = cam_soc_util_clk_enable_default(soc_info, CAM_SVS_VOTE); + rc = cam_soc_util_clk_enable_default(soc_info, CAM_CLK_SW_CLIENT_IDX, CAM_SVS_VOTE); else - cam_soc_util_clk_disable_default(soc_info); + cam_soc_util_clk_disable_default(soc_info, CAM_CLK_SW_CLIENT_IDX); return rc; } diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index ad64ea6f7f..f9e3630094 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -167,6 +167,10 @@ static int cam_isp_blob_drv_config(struct cam_ife_hw_mgr_ctx *ctx, drv_config_args.drv_en = drv_config->drv_en; drv_config_args.path_idle_en = drv_config->path_idle_en; drv_config_args.timeout_val = drv_config->timeout_val; + + if (drv_config->drv_en) + ctx->drv_path_idle_en = drv_config->path_idle_en; + for (i = 0; i < ctx->num_base; i++) { if (ctx->base[i].hw_type != CAM_ISP_HW_TYPE_CSID) continue; @@ -207,11 +211,15 @@ static int cam_ife_mgr_finish_clk_bw_update( { int i, rc = 0; struct cam_isp_apply_clk_bw_args clk_bw_args; + bool cesta_idx_updated[CAM_CESTA_MAX_CLIENTS] = {0}; clk_bw_args.request_id = request_id; clk_bw_args.skip_clk_data_rst = skip_clk_data_rst; + clk_bw_args.is_drv_config_en = (bool) (ctx->drv_path_idle_en & CAM_ISP_PXL_PATH); + for (i = 0; i < ctx->num_base; i++) { clk_bw_args.hw_intf = NULL; + clk_bw_args.clock_updated = false; CAM_DBG(CAM_PERF, "Clock/BW Update for req_id:%d i:%d num_vfe_out:%d num_sfe_out:%d in_rd:%d", request_id, i, ctx->num_acq_vfe_out, ctx->num_acq_sfe_out, @@ -226,8 +234,9 @@ static int cam_ife_mgr_finish_clk_bw_update( continue; CAM_DBG(CAM_PERF, - "Apply Clock/BW for req_id:%d i:%d hw_idx=%d hw_type:%d num_vfe_out:%d num_sfe_out:%d in_rd:%d", + "Apply Clock/BW for req_id:%d i:%d hw_idx=%d hw_type:%d inline:%s num_vfe_out:%d num_sfe_out:%d in_rd:%d", request_id, i, clk_bw_args.hw_intf->hw_idx, clk_bw_args.hw_intf->hw_type, + CAM_BOOL_TO_YESNO(clk_bw_args.is_drv_config_en), ctx->num_acq_vfe_out, ctx->num_acq_sfe_out, !list_empty(&ctx->res_list_ife_in_rd)); rc = clk_bw_args.hw_intf->hw_ops.process_cmd(clk_bw_args.hw_intf->hw_priv, @@ -239,8 +248,38 @@ static int cam_ife_mgr_finish_clk_bw_update( request_id, i, ctx->base[i].idx, ctx->base[i].hw_type, rc); break; } + + CAM_DBG(CAM_ISP, "clock_updated=%d, hw_idx=%d", + clk_bw_args.clock_updated, clk_bw_args.hw_intf->hw_idx); + + if ((clk_bw_args.clock_updated) && + (clk_bw_args.hw_intf->hw_idx < CAM_CESTA_MAX_CLIENTS)) + cesta_idx_updated[clk_bw_args.hw_intf->hw_idx] = true; } + if (g_ife_hw_mgr.cam_clk_drv_support) { + CAM_DBG(CAM_ISP, "Channel switch for [0]=%s, [1]=%s, [2]=%s", + CAM_BOOL_TO_YESNO(cesta_idx_updated[0]), + CAM_BOOL_TO_YESNO(cesta_idx_updated[1]), + CAM_BOOL_TO_YESNO(cesta_idx_updated[2])); + + for (i = 0; i < CAM_CESTA_MAX_CLIENTS; i++) { + if (!cesta_idx_updated[i]) + continue; + + rc = cam_soc_util_cesta_channel_switch(i, "ife_hw_mgr_update"); + if (rc) { + CAM_ERR(CAM_CSIPHY, + "Failed to apply power states for cesta client:%d rc:%d", + i, rc); + return rc; + } + } + } + + CAM_DBG(CAM_ISP, "Clk, BW update done for Req=%lld, skip_clk_data_rst=%d", + request_id, skip_clk_data_rst); + return rc; } @@ -901,7 +940,8 @@ err: static int cam_ife_mgr_csid_start_hw( struct cam_ife_hw_mgr_ctx *ctx, uint32_t primary_rdi_csid_res, - bool is_internal_start) + bool is_internal_start, + bool start_only) { struct cam_isp_hw_mgr_res *hw_mgr_res; struct cam_isp_resource_node *isp_res; @@ -963,6 +1003,8 @@ static int cam_ife_mgr_csid_start_hw( start_args.cdm_hw_idx = ctx->cdm_hw_idx; start_args.is_secure = is_secure; start_args.is_internal_start = is_internal_start; + start_args.start_only = start_only; + start_args.is_drv_config_en = (bool) ctx->drv_path_idle_en; hw_intf->hw_ops.start(hw_intf->hw_priv, &start_args, sizeof(start_args)); } @@ -5197,6 +5239,7 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) ife_ctx->common.sec_pf_evt_cb = acquire_args->sec_pf_evt_cb; ife_ctx->try_recovery_cnt = 0; ife_ctx->recovery_req_id = 0; + ife_ctx->drv_path_idle_en = 0; acquire_hw_info = (struct cam_isp_acquire_hw_info *)acquire_args->acquire_info; @@ -6945,7 +6988,7 @@ static int cam_ife_mgr_restart_hw(void *start_hw_args) CAM_DBG(CAM_ISP, "START CSID HW ... in ctx id:%d", ctx->ctx_index); /* Start the IFE CSID HW devices */ - rc = cam_ife_mgr_csid_start_hw(ctx, CAM_IFE_PIX_PATH_RES_MAX, false); + rc = cam_ife_mgr_csid_start_hw(ctx, CAM_IFE_PIX_PATH_RES_MAX, false, false); if (rc) { CAM_ERR(CAM_ISP, "Error in starting CSID HW in ctx id:%d", ctx->ctx_index); goto err; @@ -7110,6 +7153,13 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args) CAM_DBG(CAM_ISP, "Enter... ctx id:%d", ctx->ctx_index); + rc = cam_cpas_query_drv_enable(&g_ife_hw_mgr.cam_ddr_drv_support, + &g_ife_hw_mgr.cam_clk_drv_support); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to query DRV enable rc: %d", rc); + return -EINVAL; + } + /* update Bandwidth should be done at the hw layer */ cam_tasklet_start(ctx->common.tasklet_info); @@ -7219,12 +7269,6 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args) goto safe_disable; } - rc = cam_cpas_query_drv_enable(&g_ife_hw_mgr.cam_ddr_drv_support); - if (rc) { - CAM_ERR(CAM_ISP, "Failed to query DRV enable rc: %d", rc); - goto cdm_streamoff; - } - start_only: atomic_set(&ctx->overflow_pending, 0); @@ -7343,7 +7387,7 @@ start_only: ctx->ctx_index); /* Start the IFE CSID HW devices */ rc = cam_ife_mgr_csid_start_hw(ctx, primary_rdi_csid_res, - start_isp->is_internal_start); + start_isp->is_internal_start, start_isp->start_only); if (rc) goto err; @@ -7497,6 +7541,7 @@ static int cam_ife_mgr_release_hw(void *hw_mgr_priv, ctx->scratch_buf_info.ife_scratch_config = NULL; ctx->try_recovery_cnt = 0; ctx->recovery_req_id = 0; + ctx->drv_path_idle_en = 0; memset(&ctx->flags, 0, sizeof(struct cam_ife_hw_mgr_ctx_flags)); atomic_set(&ctx->overflow_pending, 0); @@ -8800,13 +8845,11 @@ static int cam_isp_blob_ife_clock_update( camif_r_clk_updated = true; } - } else if ((hw_mgr_res->res_id >= - CAM_ISP_HW_VFE_IN_RD) && (hw_mgr_res->res_id - <= CAM_ISP_HW_VFE_IN_RDI3)) + } else if ((hw_mgr_res->res_id >= CAM_ISP_HW_VFE_IN_RD) && + (hw_mgr_res->res_id <= CAM_ISP_HW_VFE_IN_RDI3)) { for (j = 0; j < clock_config->num_rdi; j++) - clk_rate = max(clock_config->rdi_hz[j], - clk_rate); - else + clk_rate = max(clock_config->rdi_hz[j], clk_rate); + } else { if (hw_mgr_res->res_id != CAM_ISP_HW_VFE_IN_LCR && hw_mgr_res->hw_res[i]) { CAM_ERR(CAM_ISP, "Invalid res_id %u", @@ -8814,6 +8857,7 @@ static int cam_isp_blob_ife_clock_update( rc = -EINVAL; return rc; } + } hw_intf = hw_mgr_res->hw_res[i]->hw_intf; if (hw_intf && hw_intf->hw_ops.process_cmd) { diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h index 1c003b9487..19b58fd7b1 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h @@ -289,6 +289,7 @@ struct cam_ife_cdm_user_data { * @curr_num_exp: Current num of exposures * @try_recovery_cnt: Retry count for overflow recovery * @recovery_req_id: The request id on which overflow recovery happens + * @drv_path_idle_en: Path idle enable value for DRV * */ struct cam_ife_hw_mgr_ctx { @@ -348,6 +349,7 @@ struct cam_ife_hw_mgr_ctx { uint32_t curr_num_exp; uint32_t try_recovery_cnt; uint64_t recovery_req_id; + uint32_t drv_path_idle_en; }; /** @@ -427,6 +429,7 @@ struct cam_isp_sfe_cache_info { * @csid_global_reset_en CSID global reset enable * @csid_camif_irq_support CSID camif IRQ support * @cam_ddr_drv_support DDR DRV support + * @cam_clk_drv_support CLK DRV support * @isp_caps Capability of underlying SFE/IFE HW * @path_port_map Mapping of outport to IFE mux * @num_caches_found Number of caches supported @@ -457,6 +460,7 @@ struct cam_ife_hw_mgr { bool csid_global_reset_en; bool csid_camif_irq_support; bool cam_ddr_drv_support; + bool cam_clk_drv_support; struct cam_isp_ife_sfe_hw_caps isp_caps; struct cam_isp_hw_path_port_map path_port_map; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_hw_ver1.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_hw_ver1.c index 4af6a892a1..4900748ddc 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_hw_ver1.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_hw_ver1.c @@ -2640,7 +2640,7 @@ static int cam_ife_csid_ver1_enable_hw(struct cam_ife_csid_ver1_hw *csid_hw) CAM_DBG(CAM_ISP, "CSID[%d] clk lvl %u received clk_rate %u applied clk_rate %lu", csid_hw->hw_intf->hw_idx, clk_lvl, csid_hw->clk_rate, - soc_info->applied_src_clk_rate); + soc_info->applied_src_clk_rates.sw_client); rc = cam_ife_csid_enable_soc_resources(soc_info, clk_lvl); @@ -3987,28 +3987,28 @@ static int cam_ife_csid_ver1_rx_bottom_half_handler( event_type |= CAM_ISP_HW_ERROR_CSID_LANE_FIFO_OVERFLOW; CAM_ERR_BUF(CAM_ISP, log_buf, CAM_IFE_CSID_LOG_BUF_LEN, &len, "RX_ERROR_LANE0_FIFO_OVERFLOW: Skew/Less Data on lanes/ Slow csid clock:%luHz\n", - soc_info->applied_src_clk_rate); + soc_info->applied_src_clk_rates.sw_client); } if (irq_status & IFE_CSID_VER1_RX_LANE1_FIFO_OVERFLOW) { event_type |= CAM_ISP_HW_ERROR_CSID_LANE_FIFO_OVERFLOW; CAM_ERR_BUF(CAM_ISP, log_buf, CAM_IFE_CSID_LOG_BUF_LEN, &len, "RX_ERROR_LANE1_FIFO_OVERFLOW: Skew/Less Data on lanes/ Slow csid clock:%luHz\n", - soc_info->applied_src_clk_rate); + soc_info->applied_src_clk_rates.sw_client); } if (irq_status & IFE_CSID_VER1_RX_LANE2_FIFO_OVERFLOW) { event_type |= CAM_ISP_HW_ERROR_CSID_LANE_FIFO_OVERFLOW; CAM_ERR_BUF(CAM_ISP, log_buf, CAM_IFE_CSID_LOG_BUF_LEN, &len, "RX_ERROR_LANE2_FIFO_OVERFLOW: Skew/Less Data on lanes/ Slow csid clock:%luHz\n", - soc_info->applied_src_clk_rate); + soc_info->applied_src_clk_rates.sw_client); } if (irq_status & IFE_CSID_VER1_RX_LANE3_FIFO_OVERFLOW) { event_type |= CAM_ISP_HW_ERROR_CSID_LANE_FIFO_OVERFLOW; CAM_ERR_BUF(CAM_ISP, log_buf, CAM_IFE_CSID_LOG_BUF_LEN, &len, "RX_ERROR_LANE3_FIFO_OVERFLOW: Skew/Less Data on lanes/ Slow csid clock:%luHz\n", - soc_info->applied_src_clk_rate); + soc_info->applied_src_clk_rates.sw_client); } if (irq_status & IFE_CSID_VER1_RX_TG_FIFO_OVERFLOW) { diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_hw_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_hw_ver2.c index d3f9fa574f..c5d12006b9 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_hw_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_hw_ver2.c @@ -1231,7 +1231,7 @@ static int cam_ife_csid_ver2_rx_err_bottom_half( event_type |= CAM_ISP_HW_ERROR_CSID_LANE_FIFO_OVERFLOW; CAM_ERR_BUF(CAM_ISP, log_buf, CAM_IFE_CSID_LOG_BUF_LEN, &len, "INPUT_FIFO_OVERFLOW [Lanes:%s]: Skew/Less Data on lanes/ Slow csid clock:%luHz", - tmp_buf, soc_info->applied_src_clk_rate); + tmp_buf, cam_soc_util_get_applied_src_clk(soc_info, true)); } if (irq_status & IFE_CSID_VER2_RX_ERROR_CPHY_PH_CRC) { @@ -1673,17 +1673,17 @@ static int cam_ife_csid_ver2_top_info_irq_bottom_half( } if (irq_status & IFE_CSID_VER2_TOP_INFO_VOTE_UP) { - cam_cpas_log_votes(true); CAM_INFO(CAM_ISP, "CSID:%d INFO_VOTE_UP timestamp:[%lld.%09lld]", csid_hw->hw_intf->hw_idx, payload->timestamp.tv_sec, payload->timestamp.tv_nsec); + cam_cpas_log_votes(true); } if (irq_status & IFE_CSID_VER2_TOP_INFO_VOTE_DN) { - cam_cpas_log_votes(true); CAM_INFO(CAM_ISP, "CSID:%d INFO_VOTE_DN timestamp:[%lld.%09lld]", csid_hw->hw_intf->hw_idx, payload->timestamp.tv_sec, payload->timestamp.tv_nsec); + cam_cpas_log_votes(true); } if (irq_status & IFE_CSID_VER2_TOP_ERR_NO_VOTE_DN) { @@ -4230,6 +4230,44 @@ static int cam_ife_csid_ver2_program_top( return 0; } +static int cam_ife_csid_ver2_set_cesta_clk_rate(struct cam_ife_csid_ver2_hw *csid_hw, + bool force_channel_switch, const char *identifier) +{ + struct cam_hw_soc_info *soc_info = &csid_hw->hw_info->soc_info; + bool channel_switch = force_channel_switch; + int rc = 0; + + CAM_DBG(CAM_ISP, "CSID:%d clk_rate=%llu, channel_switch=%d, identifier=%s", + csid_hw->hw_intf->hw_idx, csid_hw->clk_rate, channel_switch, identifier); + + if (csid_hw->clk_rate) { + rc = cam_soc_util_set_src_clk_rate(soc_info, csid_hw->hw_intf->hw_idx, + csid_hw->clk_rate, + soc_info->clk_rate[CAM_LOWSVS_VOTE][soc_info->src_clk_idx]); + if (rc) { + CAM_ERR(CAM_ISP, + "Failed in setting cesta clk rates[high low]:[%ld %ld] client_idx:%d rc:%d", + csid_hw->clk_rate, + soc_info->clk_rate[CAM_LOWSVS_VOTE][soc_info->src_clk_idx], + csid_hw->hw_intf->hw_idx, rc); + return rc; + } + channel_switch = true; + } + + if (channel_switch) { + rc = cam_soc_util_cesta_channel_switch(csid_hw->hw_intf->hw_idx, identifier); + if (rc) { + CAM_ERR(CAM_CSIPHY, + "Failed to apply power states for cesta client:%d rc:%d", + csid_hw->hw_intf->hw_idx, rc); + return rc; + } + } + + return rc; +} + static int cam_ife_csid_ver2_enable_core(struct cam_ife_csid_ver2_hw *csid_hw) { int rc = 0; @@ -4237,10 +4275,11 @@ static int cam_ife_csid_ver2_enable_core(struct cam_ife_csid_ver2_hw *csid_hw) const struct cam_ife_csid_ver2_reg_info *csid_reg; uint32_t clk_lvl; uint32_t irq_mask = 0; + struct cam_csid_soc_private *soc_private; - csid_reg = (struct cam_ife_csid_ver2_reg_info *) - csid_hw->core_info->csid_reg; + csid_reg = (struct cam_ife_csid_ver2_reg_info *)csid_hw->core_info->csid_reg; soc_info = &csid_hw->hw_info->soc_info; + soc_private = (struct cam_csid_soc_private *)soc_info->soc_private; /* overflow check before increment */ if (csid_hw->hw_info->open_count == UINT_MAX) { @@ -4266,20 +4305,42 @@ static int cam_ife_csid_ver2_enable_core(struct cam_ife_csid_ver2_hw *csid_hw) csid_hw->clk_rate); } - CAM_DBG(CAM_ISP, - "CSID[%d] clk lvl %u received clk_rate %u applied clk_rate %lu", - csid_hw->hw_intf->hw_idx, clk_lvl, csid_hw->clk_rate, - soc_info->applied_src_clk_rate); + if (soc_private->is_ife_csid_lite) + CAM_DBG(CAM_ISP, + "CSID[%d] clk lvl %u received clk_rate %u applied clk_rate :%lu", + csid_hw->hw_intf->hw_idx, clk_lvl, csid_hw->clk_rate, + soc_info->applied_src_clk_rates.sw_client); + else + CAM_DBG(CAM_ISP, + "CSID[%d] clk lvl %u received clk_rate %u applied clk_rate sw_client:%lu hw_client:[%lu %lu]", + csid_hw->hw_intf->hw_idx, clk_lvl, csid_hw->clk_rate, + soc_info->applied_src_clk_rates.sw_client, + soc_info->applied_src_clk_rates.hw_client[csid_hw->hw_intf->hw_idx].high, + soc_info->applied_src_clk_rates.hw_client[csid_hw->hw_intf->hw_idx].low); rc = cam_ife_csid_enable_soc_resources(soc_info, clk_lvl); - if (rc) { - CAM_ERR(CAM_ISP, - "CSID[%d] Enable soc failed", - csid_hw->hw_intf->hw_idx); + CAM_ERR(CAM_ISP, "CSID[%d] Enable soc failed", csid_hw->hw_intf->hw_idx); goto err; } + CAM_DBG(CAM_ISP, "csid %d is_clk_drv_en %d is_drv_config_en %d", + csid_hw->hw_intf->hw_idx, soc_info->is_clk_drv_en, csid_hw->is_drv_config_en); + + /* + * cam_ife_csid_enable_soc_resources sets clk_lvl for high, low values, if the usecase + * enables drv config, i.e enabling csid DRV events, overwrite low value with LowSVS to get + * power benefit. + */ + if (soc_info->is_clk_drv_en && csid_hw->is_drv_config_en) { + rc = cam_ife_csid_ver2_set_cesta_clk_rate(csid_hw, false, "csid_init"); + if (rc) { + CAM_ERR(CAM_ISP, "Failed in setting cesta clk rates, client_idx:%d rc:%d", + csid_hw->hw_intf->hw_idx, rc); + return rc; + } + } + irq_mask = csid_reg->cmn_reg->top_reset_irq_mask; csid_hw->reset_irq_handle = cam_irq_controller_subscribe_irq( @@ -4688,15 +4749,19 @@ static void cam_ife_csid_ver2_send_secure_info( int cam_ife_csid_ver2_start(void *hw_priv, void *args, uint32_t arg_size) { - struct cam_ife_csid_ver2_hw *csid_hw = NULL; - struct cam_isp_resource_node *res; - struct cam_csid_hw_start_args *start_args; - struct cam_ife_csid_ver2_reg_info *csid_reg; - struct cam_hw_soc_info *soc_info; - struct cam_hw_info *hw_info; - uint32_t rup_aup_mask = 0; - int rc = 0, i; - bool delay_rdi0_enable = false; + struct cam_ife_csid_ver2_hw *csid_hw = NULL; + struct cam_isp_resource_node *res; + struct cam_csid_hw_start_args *start_args; + struct cam_ife_csid_ver2_reg_info *csid_reg; + struct cam_hw_soc_info *soc_info; + struct cam_hw_info *hw_info; + uint32_t rup_aup_mask = 0; + int rc = 0, i; + bool delay_rdi0_enable = false; + struct cam_subdev_msg_phy_conn_csid_info conn_csid_info; + struct cam_subdev_msg_phy_drv_info drv_info; + struct cam_subdev_msg_phy_halt_resume_info halt_resume_info; + bool cesta_enabled = false; if (!hw_priv || !args) { CAM_ERR(CAM_ISP, "CSID Invalid params"); @@ -4720,8 +4785,14 @@ int cam_ife_csid_ver2_start(void *hw_priv, void *args, mutex_lock(&csid_hw->hw_info->hw_mutex); csid_hw->flags.sof_irq_triggered = false; csid_hw->counters.irq_debug_cnt = 0; + csid_hw->is_drv_config_en = start_args->is_drv_config_en; - if (start_args->is_internal_start) { + CAM_DBG(CAM_ISP, + "csid %d is_drv_config_en %d start_only %d is_internal_start %d, clk_rate=%lld", + csid_hw->hw_intf->hw_idx, csid_hw->is_drv_config_en, + start_args->start_only, start_args->is_internal_start, csid_hw->clk_rate); + + if (start_args->start_only) { rc = cam_cpas_csid_process_resume(csid_hw->hw_intf->hw_idx); if (rc) { CAM_ERR(CAM_ISP, "CSID:%u Failed to process resume rc: %d", @@ -4730,6 +4801,32 @@ int cam_ife_csid_ver2_start(void *hw_priv, void *args, } } + if (soc_info->is_clk_drv_en && csid_hw->is_drv_config_en) { + /* + * This will do 2 things : + * 1. At the time of enable_core, we do not have drv info yet populated into + * csid layer, so we set high, low here will overwrite previously set high, low + * 2. We trigger a channel switch so that we go to high clocks for all including + * csiphy before calling CSIPHY RESUME, so that we remove sw client vote from + * csiphy device + */ + rc = cam_ife_csid_ver2_set_cesta_clk_rate(csid_hw, true, "csid_start"); + if (rc) { + CAM_ERR(CAM_ISP, "Failed in setting cesta clk rates, client_idx:%d rc:%d", + csid_hw->hw_intf->hw_idx, rc); + return rc; + } + + if (csid_hw->sync_mode != CAM_ISP_HW_SYNC_SLAVE) { + halt_resume_info.phy_idx = (csid_hw->rx_cfg.phy_sel - 1); + halt_resume_info.lane_cfg = csid_hw->rx_cfg.lane_cfg; + halt_resume_info.csid_state = CAM_SUBDEV_PHY_CSID_RESUME; + cam_subdev_notify_message(CAM_CSIPHY_DEVICE_TYPE, + CAM_SUBDEV_MESSAGE_NOTIFY_HALT_RESUME, + (void *)&halt_resume_info); + } + } + rc = cam_ife_csid_ver2_enable_hw(csid_hw); for (i = 0; i < start_args->num_res; i++) { @@ -4803,6 +4900,40 @@ int cam_ife_csid_ver2_start(void *hw_priv, void *args, cam_ife_csid_ver2_enable_csi2(csid_hw); + if (csid_hw->sync_mode != CAM_ISP_HW_SYNC_SLAVE) { + struct cam_csid_soc_private *soc_private = + (struct cam_csid_soc_private *)soc_info->soc_private; + + conn_csid_info.phy_idx = (csid_hw->rx_cfg.phy_sel - 1); + conn_csid_info.lane_cfg = csid_hw->rx_cfg.lane_cfg; + conn_csid_info.core_idx = csid_hw->hw_intf->hw_idx; + cam_subdev_notify_message(CAM_CSIPHY_DEVICE_TYPE, CAM_SUBDEV_MESSAGE_CONN_CSID_INFO, + (void *)&conn_csid_info); + + if (!soc_private->is_ife_csid_lite) + cam_cpas_query_drv_enable(NULL, &cesta_enabled); + + if (cesta_enabled) { + /* for ifelites, soc_info->is_clk_drv_en is false */ + drv_info.use_hw_client_voting = soc_info->is_clk_drv_en; + drv_info.is_drv_config_en = csid_hw->is_drv_config_en; + } else { + drv_info.use_hw_client_voting = false; + drv_info.is_drv_config_en = false; + } + + drv_info.phy_idx = (csid_hw->rx_cfg.phy_sel - 1); + drv_info.lane_cfg = csid_hw->rx_cfg.lane_cfg; + + /* + * send this even when cesta is not enabled - to support debugfs to switch between + * cesta and non-cesta between runs. CSIPHY might have stale information if we + * do not send this info everytime + */ + cam_subdev_notify_message(CAM_CSIPHY_DEVICE_TYPE, + CAM_SUBDEV_MESSAGE_DRV_INFO, (void *)&drv_info); + } + for (i = 0; i < start_args->num_res; i++) { res = start_args->node_res[i]; @@ -4855,6 +4986,7 @@ int cam_ife_csid_ver2_stop(void *hw_priv, uint32_t i; struct cam_csid_hw_stop_args *csid_stop; struct cam_csid_reset_cfg_args reset = {0}; + struct cam_subdev_msg_phy_halt_resume_info halt_resume_info; if (!hw_priv || !stop_args || (arg_size != sizeof(struct cam_csid_hw_stop_args))) { @@ -4883,6 +5015,15 @@ int cam_ife_csid_ver2_stop(void *hw_priv, csid_hw->flags.device_enabled = false; + if (csid_hw->hw_info->soc_info.is_clk_drv_en && csid_hw->is_drv_config_en) { + halt_resume_info.phy_idx = (csid_hw->rx_cfg.phy_sel - 1); + halt_resume_info.lane_cfg = csid_hw->rx_cfg.lane_cfg; + halt_resume_info.csid_state = CAM_SUBDEV_PHY_CSID_HALT; + cam_subdev_notify_message(CAM_CSIPHY_DEVICE_TYPE, + CAM_SUBDEV_MESSAGE_NOTIFY_HALT_RESUME, + (void *)&halt_resume_info); + } + reset.reset_type = (csid_hw->flags.fatal_err_detected) ? CAM_IFE_CSID_RESET_GLOBAL : CAM_IFE_CSID_RESET_PATH; cam_ife_csid_ver2_reset(hw_priv, &reset, @@ -5413,6 +5554,8 @@ static int cam_ife_csid_ver2_set_csid_clock( csid_hw->clk_rate = clk_update->clk_rate; + CAM_DBG(CAM_ISP, "CSID:%d, clk_rate=%lld", csid_hw->hw_intf->hw_idx, csid_hw->clk_rate); + return 0; } diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_hw_ver2.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_hw_ver2.h index 0dcf1cbea0..7625beec8f 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_hw_ver2.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_hw_ver2.h @@ -615,6 +615,7 @@ struct cam_ife_csid_ver2_reg_info { * @mup: MUP for incoming VC of next frame * @discard_frame_per_path: Count of paths dropping initial frames * @drv_init_done: Indicates if drv init config is done + * @is_drv_config_en: If drv config is enabled * */ struct cam_ife_csid_ver2_hw { @@ -659,6 +660,7 @@ struct cam_ife_csid_ver2_hw { uint32_t mup; atomic_t discard_frame_per_path; bool drv_init_done; + bool is_drv_config_en; }; /* diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c index f89c5e53e5..2441b09289 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c @@ -176,10 +176,20 @@ int cam_ife_csid_enable_soc_resources( goto end; } - rc = cam_soc_util_enable_platform_resource(soc_info, true, + if (!soc_private->is_ife_csid_lite) { + /* query this everytime to support debugfs to disable clk drv */ + rc = cam_cpas_query_drv_enable(NULL, &soc_info->is_clk_drv_en); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to query DRV enable rc:%d", rc); + goto stop_cpas; + } + } + + rc = cam_soc_util_enable_platform_resource(soc_info, + (soc_info->is_clk_drv_en ? soc_info->index : CAM_CLK_SW_CLIENT_IDX), true, clk_level, true); if (rc) { - CAM_ERR(CAM_ISP, "enable platform failed"); + CAM_ERR(CAM_ISP, "enable platform failed rc %d", rc); goto stop_cpas; } @@ -202,7 +212,9 @@ int cam_ife_csid_disable_soc_resources(struct cam_hw_soc_info *soc_info) } soc_private = soc_info->soc_private; - rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + rc = cam_soc_util_disable_platform_resource(soc_info, + ((soc_info->is_clk_drv_en && (!soc_private->is_ife_csid_lite)) ? + soc_info->index : CAM_CLK_SW_CLIENT_IDX), true, true); if (rc) CAM_ERR(CAM_ISP, "Disable platform failed"); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h index 07ce264386..8e4f8e93c4 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h @@ -303,6 +303,8 @@ struct cam_csid_hw_stop_args { * @cdm_hw_idx: Physical CDM in use together with these resources * @is_secure: If these resources are run in secure session * @is_internal_start: Start triggered internally for reset & recovery + * @start_only: start only, no init required + * @is_drv_config_en: If drv config is enabled * */ struct cam_csid_hw_start_args { @@ -311,6 +313,8 @@ struct cam_csid_hw_start_args { uint32_t cdm_hw_idx; bool is_secure; bool is_internal_start; + bool start_only; + bool is_drv_config_en; }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h index af45d72ce2..ec0aaa0d2c 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h @@ -67,11 +67,15 @@ struct cam_isp_bw_control_args { * @hw_intf: Isp hw intf pointer * @request_id: Request Id * @skip_clk_data_rst: Skip resetting any clk info + * @is_drv_config_en: Enable clk DRV while setting this clk rate + * @clock_updated: If clock is updated for any of the cores */ struct cam_isp_apply_clk_bw_args { struct cam_hw_intf *hw_intf; uint64_t request_id; bool skip_clk_data_rst; + bool is_drv_config_en; + bool clock_updated; }; /* diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_sfe_hw_intf.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_sfe_hw_intf.h index 4320c46327..9879f190b0 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_sfe_hw_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_sfe_hw_intf.h @@ -120,10 +120,12 @@ struct cam_sfe_fe_update_args { * * @node_res: ISP Resource * @clk_rate: Clock rate requested + * @vote_level: DRV vote level corresponding to requested rate */ struct cam_sfe_clock_update_args { struct cam_isp_resource_node *node_res; uint64_t clk_rate; + uint32_t vote_level; }; /* diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h index 1404ffe251..5ecad9b410 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h @@ -222,10 +222,12 @@ struct cam_vfe_acquire_args { * * @node_res: Resource to get the time stamp * @clk_rate: Clock rate requested + * @vote_level: DRV vote level corresponding to requested rate */ struct cam_vfe_clock_update_args { struct cam_isp_resource_node *node_res; uint64_t clk_rate; + uint32_t vote_level; }; /* diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.c index 7559bda99e..3d182ffd8c 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -76,7 +77,7 @@ static int cam_csid_ppi_enable_hw(struct cam_csid_ppi_hw *ppi_hw) } for (i = 0; i < soc_info->num_clk; i++) { - rc = cam_soc_util_clk_enable(soc_info, false, i, -1, NULL); + rc = cam_soc_util_clk_enable(soc_info, CAM_CLK_SW_CLIENT_IDX, false, i, -1); if (rc) goto clk_disable; } @@ -106,7 +107,7 @@ static int cam_csid_ppi_enable_hw(struct cam_csid_ppi_hw *ppi_hw) return 0; clk_disable: for (--i; i >= 0; i--) - cam_soc_util_clk_disable(soc_info, false, i); + cam_soc_util_clk_disable(soc_info, CAM_CLK_SW_CLIENT_IDX, false, i); ppi_hw->hw_info->open_count--; return rc; } @@ -152,7 +153,7 @@ static int cam_csid_ppi_disable_hw(struct cam_csid_ppi_hw *ppi_hw) ppi_hw->device_enabled = 0; for (i = 0; i < soc_info->num_clk; i++) - cam_soc_util_clk_disable(soc_info, false, i); + cam_soc_util_clk_disable(soc_info, CAM_CLK_SW_CLIENT_IDX, false, i); return rc; } diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_soc.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_soc.c index da970fbe83..12d411b1f8 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_soc.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_soc.c @@ -191,7 +191,18 @@ int cam_sfe_enable_soc_resources(struct cam_hw_soc_info *soc_info) goto end; } - rc = cam_soc_util_enable_platform_resource(soc_info, true, + rc = cam_cpas_query_drv_enable(NULL, &soc_info->is_clk_drv_en); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to query DRV enable rc:%d", rc); + return rc; + } + + /* + * using sfe index - assuming csid and sfe are one to one map on chipsets where + * cesta is present. + */ + rc = cam_soc_util_enable_platform_resource(soc_info, + (soc_info->is_clk_drv_en ? soc_info->index : CAM_CLK_SW_CLIENT_IDX), true, CAM_LOWSVS_VOTE, true); if (rc) { CAM_ERR(CAM_SFE, "Enable platform failed rc=%d", rc); @@ -231,7 +242,8 @@ int cam_sfe_disable_soc_resources(struct cam_hw_soc_info *soc_info) soc_private = soc_info->soc_private; - rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + rc = cam_soc_util_disable_platform_resource(soc_info, + (soc_info->is_clk_drv_en ? soc_info->index : CAM_CLK_SW_CLIENT_IDX), true, true); if (rc) CAM_ERR(CAM_SFE, "Disable platform failed rc=%d", rc); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_top/cam_sfe_top.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_top/cam_sfe_top.c index e89fd06eaa..dbfd21eb1e 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_top/cam_sfe_top.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_top/cam_sfe_top.c @@ -48,11 +48,10 @@ struct cam_sfe_top_priv { struct cam_axi_vote req_axi_vote[CAM_SFE_TOP_IN_PORT_MAX]; struct cam_axi_vote last_bw_vote[CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ]; uint64_t last_total_bw_vote[CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ]; - uint64_t last_clk_vote[CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ]; + unsigned long last_clk_vote[CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ]; enum cam_clk_bw_state clk_state; enum cam_clk_bw_state bw_state; - enum cam_isp_bw_control_action axi_vote_control[ - CAM_SFE_TOP_IN_PORT_MAX]; + enum cam_isp_bw_control_action axi_vote_control[CAM_SFE_TOP_IN_PORT_MAX]; struct cam_axi_vote applied_axi_vote; struct cam_sfe_core_cfg core_cfg; uint32_t sfe_debug_cfg; @@ -170,31 +169,47 @@ static int cam_sfe_top_set_axi_bw_vote( } -static int cam_sfe_top_set_hw_clk_rate( - struct cam_sfe_top_priv *top_priv, uint64_t final_clk_rate, bool start_stop, - uint64_t request_id) +static int cam_sfe_top_set_hw_clk_rate(struct cam_sfe_top_priv *top_priv, + unsigned long final_clk_rate, bool start_stop, uint64_t request_id, bool is_drv_config_en) { struct cam_hw_soc_info *soc_info = NULL; struct cam_sfe_soc_private *soc_private = NULL; struct cam_ahb_vote ahb_vote; int rc = 0, clk_lvl = -1; + unsigned long cesta_clk_rate_high, cesta_clk_rate_low; + int cesta_client_idx = -1; soc_info = top_priv->common_data.soc_info; soc_private = (struct cam_sfe_soc_private *)soc_info->soc_private; - CAM_DBG(CAM_PERF, "Applying SFE:%d Clock name=%s idx=%d clk=%llu req_id=%ld", - top_priv->common_data.hw_intf->hw_idx, soc_info->clk_name[soc_info->src_clk_idx], - soc_info->src_clk_idx, final_clk_rate, (start_stop ? -1 : request_id)); + cesta_clk_rate_high = final_clk_rate; + cesta_clk_rate_low = final_clk_rate; - rc = cam_soc_util_set_src_clk_rate(soc_info, final_clk_rate); + if (soc_info->is_clk_drv_en) { + cesta_client_idx = top_priv->common_data.hw_intf->hw_idx; + if (is_drv_config_en) + cesta_clk_rate_low = + soc_info->clk_rate[CAM_LOWSVS_VOTE][soc_info->src_clk_idx]; + else + cesta_clk_rate_low = final_clk_rate; + } + + CAM_DBG(CAM_PERF, + "Applying SFE:%d Clock name=%s idx=%d cesta_client_idx:%d req clk[high low]=[%lu %lu] req_id=%ld", + top_priv->common_data.hw_intf->hw_idx, soc_info->clk_name[soc_info->src_clk_idx], + soc_info->src_clk_idx, cesta_client_idx, cesta_clk_rate_high, cesta_clk_rate_low, + (start_stop ? -1 : request_id)); + + rc = cam_soc_util_set_src_clk_rate(soc_info, cesta_client_idx, cesta_clk_rate_high, + cesta_clk_rate_low); if (!rc) { - top_priv->applied_clk_rate = final_clk_rate; - rc = cam_soc_util_get_clk_level(soc_info, final_clk_rate, + top_priv->applied_clk_rate = cesta_clk_rate_high; + rc = cam_soc_util_get_clk_level(soc_info, cesta_clk_rate_low, soc_info->src_clk_idx, &clk_lvl); if (rc) { - CAM_WARN(CAM_SFE, - "Failed to get clk level for %s with clk_rate %llu src_idx %d rc %d", - soc_info->dev_name, final_clk_rate, + CAM_WARN(CAM_ISP, + "Failed to get clk level for %s with clk_rate %lu src_idx %d rc %d", + soc_info->dev_name, cesta_clk_rate_high, soc_info->src_clk_idx, rc); rc = 0; goto end; @@ -204,8 +219,10 @@ static int cam_sfe_top_set_hw_clk_rate( ahb_vote.vote.level = clk_lvl; cam_cpas_update_ahb_vote(soc_private->cpas_handle, &ahb_vote); } else { - CAM_ERR(CAM_PERF, "SFE:%d Set Clock rate failed, rc=%d", - top_priv->common_data.hw_intf->hw_idx, rc); + CAM_ERR(CAM_ISP, + "SFE:%d cesta_client_idx:%d Failed to set the req clk rate[high low]: [%llu %llu] rc:%d", + top_priv->common_data.hw_intf->hw_idx, cesta_client_idx, + cesta_clk_rate_high, cesta_clk_rate_low, rc); } end: @@ -402,6 +419,13 @@ int cam_sfe_top_calc_axi_bw_vote(struct cam_sfe_top_priv *top_priv, bool bw_unchanged = true; struct cam_axi_vote *final_bw_vote = NULL; + if (top_priv->num_in_ports > CAM_SFE_TOP_IN_PORT_MAX) { + CAM_ERR(CAM_SFE, "Invalid number of ports %d, max %d", + top_priv->num_in_ports, CAM_SFE_TOP_IN_PORT_MAX); + rc = -EINVAL; + goto end; + } + memset(&top_priv->agg_incoming_vote, 0, sizeof(struct cam_axi_vote)); for (i = 0; i < top_priv->num_in_ports; i++) { if (top_priv->axi_vote_control[i] == @@ -562,6 +586,12 @@ int cam_sfe_top_bw_update(struct cam_sfe_soc_private *soc_private, return -EINVAL; } + if (top_priv->num_in_ports > CAM_SFE_TOP_IN_PORT_MAX) { + CAM_ERR(CAM_SFE, "Invalid number of ports %d, max %d", + top_priv->num_in_ports, CAM_SFE_TOP_IN_PORT_MAX); + return -EINVAL; + } + for (i = 0; i < top_priv->num_in_ports; i++) { if (top_priv->in_rsrc[i].res_id == res->res_id) { memcpy(&top_priv->req_axi_vote[i], @@ -602,6 +632,12 @@ int cam_sfe_top_bw_control(struct cam_sfe_soc_private *soc_private, return -EINVAL; } + if (top_priv->num_in_ports > CAM_SFE_TOP_IN_PORT_MAX) { + CAM_ERR(CAM_SFE, "Invalid number of ports %d, max %d", + top_priv->num_in_ports, CAM_SFE_TOP_IN_PORT_MAX); + return -EINVAL; + } + for (i = 0; i < top_priv->num_in_ports; i++) { if (top_priv->in_rsrc[i].res_id == res->res_id) { top_priv->axi_vote_control[i] = bw_ctrl->action; @@ -646,7 +682,7 @@ static int cam_sfe_top_core_cfg( static inline void cam_sfe_top_delay_clk_reduction( struct cam_sfe_top_priv *top_priv, - uint64_t *max_clk) + unsigned long *max_clk) { int i; @@ -658,10 +694,10 @@ static inline void cam_sfe_top_delay_clk_reduction( int cam_sfe_top_calc_hw_clk_rate( struct cam_sfe_top_priv *top_priv, bool start_stop, - uint64_t *final_clk_rate, uint64_t request_id) + unsigned long *final_clk_rate, uint64_t request_id) { int i, rc = 0; - uint64_t max_req_clk_rate = 0; + unsigned long max_req_clk_rate = 0; for (i = 0; i < top_priv->num_in_ports; i++) { if (top_priv->req_clk_rate[i] > max_req_clk_rate) @@ -675,15 +711,13 @@ int cam_sfe_top_calc_hw_clk_rate( memset(top_priv->last_clk_vote, 0, sizeof(uint64_t) * CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ); top_priv->last_clk_counter = 0; - top_priv->last_clk_vote[top_priv->last_clk_counter] = - max_req_clk_rate; + top_priv->last_clk_vote[top_priv->last_clk_counter] = max_req_clk_rate; top_priv->last_clk_counter = (top_priv->last_clk_counter + 1) % CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ; } else { - top_priv->last_clk_vote[top_priv->last_clk_counter] = - max_req_clk_rate; + top_priv->last_clk_vote[top_priv->last_clk_counter] = max_req_clk_rate; top_priv->last_clk_counter = (top_priv->last_clk_counter + 1) % - CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ; + CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ; /* Find max clk request in last few requests */ cam_sfe_top_delay_clk_reduction(top_priv, final_clk_rate); @@ -701,7 +735,7 @@ int cam_sfe_top_calc_hw_clk_rate( top_priv->clk_state = CAM_CLK_BW_STATE_DECREASE; CAM_DBG(CAM_PERF, "SFE:%d Clock state:%s hw_clk_rate:%llu req_id:%ld", - top_priv->common_data.hw_intf->hw_idx, + top_priv->common_data.hw_intf->hw_idx, cam_sfe_top_clk_bw_state_to_string(top_priv->clk_state), top_priv->applied_clk_rate, (start_stop ? -1 : request_id)); @@ -864,8 +898,10 @@ static int cam_sfe_top_handle_overflow( top_priv->common_data.common_reg->ipp_violation_status); CAM_ERR(CAM_ISP, - "SFE%d src_clk_rate:%luHz bus_overflow_status:%s violation: %s", - soc_info->index, soc_info->applied_src_clk_rate, + "SFE%d src_clk_rate sw_client:%lu hw_client:[%lu %lu] bus_overflow_status:%s violation: %s", + soc_info->index, soc_info->applied_src_clk_rates.sw_client, + soc_info->applied_src_clk_rates.hw_client[soc_info->index].high, + soc_info->applied_src_clk_rates.hw_client[soc_info->index].low, CAM_BOOL_TO_YESNO(bus_overflow_status), CAM_BOOL_TO_YESNO(violation_status)); tmp = bus_overflow_status; @@ -896,7 +932,7 @@ static int cam_sfe_top_apply_clk_bw_update(struct cam_sfe_top_priv *top_priv, struct cam_hw_intf *hw_intf = NULL; struct cam_axi_vote *to_be_applied_axi_vote = NULL; struct cam_isp_apply_clk_bw_args *clk_bw_args = NULL; - uint64_t final_clk_rate = 0; + unsigned long final_clk_rate = 0; uint64_t total_bw_new_vote = 0; uint64_t request_id; int rc = 0; @@ -952,10 +988,12 @@ static int cam_sfe_top_apply_clk_bw_update(struct cam_sfe_top_priv *top_priv, goto end; } - CAM_DBG(CAM_PERF, "SFE:%d APPLY CLK/BW req_id:%ld clk_state:%s bw_state:%s ", + CAM_DBG(CAM_PERF, + "SFE:%d APPLY CLK/BW req_id:%ld clk_state:%s bw_state:%s is_drv_config_en:%s", hw_intf->hw_idx, request_id, cam_sfe_top_clk_bw_state_to_string(top_priv->clk_state), - cam_sfe_top_clk_bw_state_to_string(top_priv->bw_state)); + cam_sfe_top_clk_bw_state_to_string(top_priv->bw_state), + CAM_BOOL_TO_YESNO(clk_bw_args->is_drv_config_en)); /* Determine BW and clock voting sequence according to state */ if ((top_priv->clk_state == CAM_CLK_BW_STATE_UNCHANGED) && @@ -966,20 +1004,23 @@ static int cam_sfe_top_apply_clk_bw_update(struct cam_sfe_top_priv *top_priv, total_bw_new_vote, false, request_id); if (rc) { CAM_ERR(CAM_SFE, - "SFE:%d Failed in voting final bw:%llu clk_state:%s bw_state:%s", + "SFE:%d Failed in voting final bw:%llu clk_state:%s bw_state:%s is_drv_config_en:%s", hw_intf->hw_idx, total_bw_new_vote, cam_sfe_top_clk_bw_state_to_string(top_priv->clk_state), - cam_sfe_top_clk_bw_state_to_string(top_priv->bw_state)); + cam_sfe_top_clk_bw_state_to_string(top_priv->bw_state), + CAM_BOOL_TO_YESNO(clk_bw_args->is_drv_config_en)); goto end; } } else if (top_priv->bw_state == CAM_CLK_BW_STATE_UNCHANGED) { - rc = cam_sfe_top_set_hw_clk_rate(top_priv, final_clk_rate, false, request_id); + rc = cam_sfe_top_set_hw_clk_rate(top_priv, final_clk_rate, false, request_id, + clk_bw_args->is_drv_config_en); if (rc) { CAM_ERR(CAM_SFE, - "SFE:%d Failed in voting final clk:%llu clk_state:%s bw_state:%s", + "SFE:%d Failed in voting final clk:%lu clk_state:%s bw_state:%s is_drv_config_en:%s", hw_intf->hw_idx, final_clk_rate, cam_sfe_top_clk_bw_state_to_string(top_priv->clk_state), - cam_sfe_top_clk_bw_state_to_string(top_priv->bw_state)); + cam_sfe_top_clk_bw_state_to_string(top_priv->bw_state), + CAM_BOOL_TO_YESNO(clk_bw_args->is_drv_config_en)); goto end; } } else if (top_priv->clk_state == CAM_CLK_BW_STATE_INCREASE) { @@ -988,31 +1029,36 @@ static int cam_sfe_top_apply_clk_bw_update(struct cam_sfe_top_priv *top_priv, total_bw_new_vote, false, request_id); if (rc) { CAM_ERR(CAM_SFE, - "SFE:%d Failed in voting final bw:%llu clk_state:%s bw_state:%s", + "SFE:%d Failed in voting final bw:%llu clk_state:%s bw_state:%s is_drv_config_en:%s", hw_intf->hw_idx, total_bw_new_vote, cam_sfe_top_clk_bw_state_to_string(top_priv->clk_state), - cam_sfe_top_clk_bw_state_to_string(top_priv->bw_state)); + cam_sfe_top_clk_bw_state_to_string(top_priv->bw_state), + CAM_BOOL_TO_YESNO(clk_bw_args->is_drv_config_en)); goto end; } - rc = cam_sfe_top_set_hw_clk_rate(top_priv, final_clk_rate, false, request_id); + rc = cam_sfe_top_set_hw_clk_rate(top_priv, final_clk_rate, false, request_id, + clk_bw_args->is_drv_config_en); if (rc) { CAM_ERR(CAM_SFE, - "SFE:%d Failed in voting final clk:%llu clk_state:%s bw_state:%s", + "SFE:%d Failed in voting final clk:%lu clk_state:%s bw_state:%s is_drv_config_en:%s", hw_intf->hw_idx, final_clk_rate, cam_sfe_top_clk_bw_state_to_string(top_priv->clk_state), - cam_sfe_top_clk_bw_state_to_string(top_priv->bw_state)); + cam_sfe_top_clk_bw_state_to_string(top_priv->bw_state), + CAM_BOOL_TO_YESNO(clk_bw_args->is_drv_config_en)); goto end; } } else if (top_priv->clk_state == CAM_CLK_BW_STATE_DECREASE) { /* Set Clock first, followed by BW */ - rc = cam_sfe_top_set_hw_clk_rate(top_priv, final_clk_rate, false, request_id); + rc = cam_sfe_top_set_hw_clk_rate(top_priv, final_clk_rate, false, request_id, + clk_bw_args->is_drv_config_en); if (rc) { CAM_ERR(CAM_SFE, - "SFE:%d Failed in voting final clk:%llu clk_state:%s bw_state:%s", + "SFE:%d Failed in voting final clk:%lu clk_state:%s bw_state:%s is_drv_config_en:%s", hw_intf->hw_idx, final_clk_rate, cam_sfe_top_clk_bw_state_to_string(top_priv->clk_state), - cam_sfe_top_clk_bw_state_to_string(top_priv->bw_state)); + cam_sfe_top_clk_bw_state_to_string(top_priv->bw_state), + CAM_BOOL_TO_YESNO(clk_bw_args->is_drv_config_en)); goto end; } @@ -1020,20 +1066,26 @@ static int cam_sfe_top_apply_clk_bw_update(struct cam_sfe_top_priv *top_priv, total_bw_new_vote, false, request_id); if (rc) { CAM_ERR(CAM_SFE, - "SFE:%d Failed in voting final bw:%llu clk_state:%s bw_state:%s", + "SFE:%d Failed in voting final bw:%llu clk_state:%s bw_state:%s is_drv_config_en:%s", hw_intf->hw_idx, total_bw_new_vote, cam_sfe_top_clk_bw_state_to_string(top_priv->clk_state), - cam_sfe_top_clk_bw_state_to_string(top_priv->bw_state)); + cam_sfe_top_clk_bw_state_to_string(top_priv->bw_state), + CAM_BOOL_TO_YESNO(clk_bw_args->is_drv_config_en)); goto end; } } else { - CAM_ERR(CAM_SFE, "Invalid state to apply CLK/BW clk_state:%s bw_state:%s", + CAM_ERR(CAM_SFE, + "Invalid state to apply CLK/BW clk_state:%s bw_state:%s is_drv_config_en:%s", cam_sfe_top_clk_bw_state_to_string(top_priv->clk_state), - cam_sfe_top_clk_bw_state_to_string(top_priv->bw_state)); + cam_sfe_top_clk_bw_state_to_string(top_priv->bw_state), + CAM_BOOL_TO_YESNO(clk_bw_args->is_drv_config_en)); rc = -EINVAL; goto end; } + if (top_priv->clk_state != CAM_CLK_BW_STATE_UNCHANGED) + clk_bw_args->clock_updated = true; + end: top_priv->clk_state = CAM_CLK_BW_STATE_INIT; top_priv->bw_state = CAM_CLK_BW_STATE_INIT; @@ -1043,7 +1095,7 @@ end: static int cam_sfe_top_apply_clock_start_stop(struct cam_sfe_top_priv *top_priv) { int rc = 0; - uint64_t final_clk_rate = 0; + unsigned long final_clk_rate = 0; rc = cam_sfe_top_calc_hw_clk_rate(top_priv, true, &final_clk_rate, 0); if (rc) { @@ -1056,9 +1108,9 @@ static int cam_sfe_top_apply_clock_start_stop(struct cam_sfe_top_priv *top_priv) if (top_priv->clk_state == CAM_CLK_BW_STATE_UNCHANGED) goto end; - rc = cam_sfe_top_set_hw_clk_rate(top_priv, final_clk_rate, true, 0); + rc = cam_sfe_top_set_hw_clk_rate(top_priv, final_clk_rate, true, 0, false); if (rc) { - CAM_ERR(CAM_SFE, "SFE:%d Failed in voting final clk:%llu clk_state:%s", + CAM_ERR(CAM_SFE, "SFE:%d Failed in voting final clk:%lu clk_state:%s", top_priv->common_data.hw_intf->hw_idx, final_clk_rate, cam_sfe_top_clk_bw_state_to_string(top_priv->clk_state)); goto end; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_soc.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_soc.c index 17f3fc7fb5..c103866e5f 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_soc.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_soc.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include #include "cam_tfe_csid_soc.h" @@ -113,7 +114,7 @@ int cam_tfe_csid_enable_soc_resources( goto end; } - rc = cam_soc_util_enable_platform_resource(soc_info, true, + rc = cam_soc_util_enable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDX, true, clk_level, true); if (rc) { CAM_ERR(CAM_ISP, "enable platform failed"); @@ -139,7 +140,7 @@ int cam_tfe_csid_disable_soc_resources(struct cam_hw_soc_info *soc_info) } soc_private = soc_info->soc_private; - rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + rc = cam_soc_util_disable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDX, true, true); if (rc) CAM_ERR(CAM_ISP, "Disable platform failed"); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.c index 4ebd6bfad5..058b67139e 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.c @@ -962,7 +962,7 @@ static int cam_tfe_top_set_hw_clk_rate( soc_info->clk_name[soc_info->src_clk_idx], soc_info->src_clk_idx, max_clk_rate); - rc = cam_soc_util_set_src_clk_rate(soc_info, max_clk_rate); + rc = cam_soc_util_set_src_clk_rate(soc_info, CAM_CLK_SW_CLIENT_IDX, max_clk_rate, 0); if (!rc) top_priv->hw_clk_rate = max_clk_rate; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_soc.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_soc.c index b93760ce1e..e0f544b9d4 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_soc.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_soc.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -171,7 +172,7 @@ int cam_tfe_enable_soc_resources(struct cam_hw_soc_info *soc_info) goto end; } - rc = cam_soc_util_enable_platform_resource(soc_info, true, + rc = cam_soc_util_enable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDXs, true, CAM_LOWSVS_VOTE, true); if (rc) { CAM_ERR(CAM_ISP, "Error! enable platform failed rc=%d", rc); @@ -200,8 +201,8 @@ int cam_tfe_soc_enable_clk(struct cam_hw_soc_info *soc_info, soc_private = soc_info->soc_private; if (strcmp(clk_name, CAM_TFE_DSP_CLK_NAME) == 0) { - rc = cam_soc_util_clk_enable(soc_info, true, - soc_private->dsp_clk_index, 0, NULL); + rc = cam_soc_util_clk_enable(soc_info, CAM_CLK_SW_CLIENT_IDX, true, + soc_private->dsp_clk_index, 0); if (rc) CAM_ERR(CAM_ISP, "Error enable dsp clk failed rc=%d", rc); @@ -224,7 +225,7 @@ int cam_tfe_soc_disable_clk(struct cam_hw_soc_info *soc_info, soc_private = soc_info->soc_private; if (strcmp(clk_name, CAM_TFE_DSP_CLK_NAME) == 0) { - rc = cam_soc_util_clk_disable(soc_info, true, + rc = cam_soc_util_clk_disable(soc_info, CAM_CLK_SW_CLIENT_IDX, true, soc_private->dsp_clk_index); if (rc) CAM_ERR(CAM_ISP, @@ -247,7 +248,7 @@ int cam_tfe_disable_soc_resources(struct cam_hw_soc_info *soc_info) } soc_private = soc_info->soc_private; - rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + rc = cam_soc_util_disable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDX, true, true); if (rc) { CAM_ERR(CAM_ISP, "Disable platform failed rc=%d", rc); return rc; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c index 99c54619df..6ee1085091 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c @@ -277,7 +277,16 @@ int cam_vfe_enable_soc_resources(struct cam_hw_soc_info *soc_info) goto end; } - rc = cam_soc_util_enable_platform_resource(soc_info, true, + if (!soc_private->is_ife_lite) { + rc = cam_cpas_query_drv_enable(NULL, &soc_info->is_clk_drv_en); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to query DRV enable rc:%d", rc); + return rc; + } + } + + rc = cam_soc_util_enable_platform_resource(soc_info, + (soc_info->is_clk_drv_en ? soc_info->index : CAM_CLK_SW_CLIENT_IDX), true, CAM_LOWSVS_VOTE, true); if (rc) { CAM_ERR(CAM_ISP, "Error! enable platform failed rc=%d", rc); @@ -313,8 +322,8 @@ int cam_vfe_soc_enable_clk(struct cam_hw_soc_info *soc_info, goto end; } - rc = cam_soc_util_clk_enable(soc_info, true, - soc_private->dsp_clk_index, 0, NULL); + rc = cam_soc_util_clk_enable(soc_info, CAM_CLK_SW_CLIENT_IDX, true, + soc_private->dsp_clk_index, 0); if (rc) CAM_ERR(CAM_ISP, "Error enable dsp clk failed rc=%d", rc); @@ -345,7 +354,7 @@ int cam_vfe_soc_disable_clk(struct cam_hw_soc_info *soc_info, goto end; } - rc = cam_soc_util_clk_disable(soc_info, true, + rc = cam_soc_util_clk_disable(soc_info, CAM_CLK_SW_CLIENT_IDX, true, soc_private->dsp_clk_index); if (rc) CAM_ERR(CAM_ISP, @@ -367,9 +376,11 @@ int cam_vfe_disable_soc_resources(struct cam_hw_soc_info *soc_info) rc = -EINVAL; return rc; } + soc_private = soc_info->soc_private; - rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + rc = cam_soc_util_disable_platform_resource(soc_info, + (soc_info->is_clk_drv_en ? soc_info->index : CAM_CLK_SW_CLIENT_IDX), true, true); if (rc) { CAM_ERR(CAM_ISP, "Disable platform failed rc=%d", rc); return rc; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c index 8164731434..824dd19b8d 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c @@ -2709,7 +2709,7 @@ static int cam_vfe_bus_ver3_mini_dump( } md = (struct cam_vfe_bus_ver3_mini_dump_data *)md_args->start_addr; - md->clk_rate = hw_info->soc_info.applied_src_clk_rate; + md->clk_rate = cam_soc_util_get_applied_src_clk(&hw_info->soc_info, true); md->hw_idx = bus_priv->common_data.hw_intf->hw_idx; md->hw_state = hw_info->hw_state; bytes_written += sizeof(*md); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_common.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_common.c index eaf2769173..105c74263d 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_common.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_common.c @@ -85,31 +85,46 @@ static int cam_vfe_top_set_axi_bw_vote(struct cam_vfe_top_priv_common *top_commo } static int cam_vfe_top_set_hw_clk_rate(struct cam_vfe_top_priv_common *top_common, - uint64_t final_clk_rate, bool start_stop, uint64_t request_id) + unsigned long final_clk_rate, bool start_stop, uint64_t request_id, bool is_drv_config_en) { struct cam_hw_soc_info *soc_info = NULL; struct cam_vfe_soc_private *soc_private = NULL; struct cam_ahb_vote ahb_vote; int rc = 0, clk_lvl = -1; + unsigned long cesta_clk_rate_high = 0, cesta_clk_rate_low = 0; + int cesta_client_idx = -1; soc_info = top_common->soc_info; soc_private = (struct cam_vfe_soc_private *)soc_info->soc_private; - CAM_DBG(CAM_PERF, "Applying VFE:%d Clock name=%s idx=%d clk=%llu req_id=%ld", + cesta_clk_rate_high = final_clk_rate; + cesta_clk_rate_low = final_clk_rate; + + if (soc_info->is_clk_drv_en) { + cesta_client_idx = top_common->hw_idx; + if (is_drv_config_en) + cesta_clk_rate_low = + soc_info->clk_rate[CAM_LOWSVS_VOTE][soc_info->src_clk_idx]; + else + cesta_clk_rate_low = final_clk_rate; + } + + CAM_DBG(CAM_PERF, + "Applying VFE:%d Clock name=%s idx=%d cesta_client_idx:%d req clk[high low]=[%lu %lu] req_id=%ld", top_common->hw_idx, soc_info->clk_name[soc_info->src_clk_idx], - soc_info->src_clk_idx, final_clk_rate, (start_stop ? -1 : request_id)); + soc_info->src_clk_idx, cesta_client_idx, cesta_clk_rate_high, cesta_clk_rate_low, + (start_stop ? -1 : request_id)); - rc = cam_soc_util_set_src_clk_rate(soc_info, final_clk_rate); + rc = cam_soc_util_set_src_clk_rate(soc_info, cesta_client_idx, cesta_clk_rate_high, + cesta_clk_rate_low); if (!rc) { - soc_private->ife_clk_src = final_clk_rate; - - top_common->applied_clk_rate = final_clk_rate; - rc = cam_soc_util_get_clk_level(soc_info, final_clk_rate, + top_common->applied_clk_rate = cesta_clk_rate_high; + rc = cam_soc_util_get_clk_level(soc_info, cesta_clk_rate_low, soc_info->src_clk_idx, &clk_lvl); if (rc) { CAM_WARN(CAM_ISP, - "Failed to get clk level for %s with clk_rate %llu src_idx %d rc %d", - soc_info->dev_name, final_clk_rate, + "Failed to get clk level for %s with clk_rate %lu src_idx %d rc %d", + soc_info->dev_name, cesta_clk_rate_high, soc_info->src_clk_idx, rc); rc = 0; goto end; @@ -119,8 +134,10 @@ static int cam_vfe_top_set_hw_clk_rate(struct cam_vfe_top_priv_common *top_commo ahb_vote.vote.level = clk_lvl; cam_cpas_update_ahb_vote(soc_private->cpas_handle, &ahb_vote); } else { - CAM_ERR(CAM_PERF, "VFE:%d Set Clock rate failed, rc=%d", - top_common->hw_idx, rc); + CAM_ERR(CAM_ISP, + "VFE:%d cesta_client_idx:%d Failed to set the req clk rate[high low]: [%llu %llu] rc:%d", + top_common->hw_idx, cesta_client_idx, cesta_clk_rate_high, + cesta_clk_rate_low, rc); } end: @@ -129,7 +146,7 @@ end: static inline void cam_vfe_top_delay_clk_reduction( struct cam_vfe_top_priv_common *top_common, - uint64_t *max_clk) + unsigned long *max_clk) { int i; @@ -141,10 +158,10 @@ static inline void cam_vfe_top_delay_clk_reduction( static int cam_vfe_top_calc_hw_clk_rate( struct cam_vfe_top_priv_common *top_common, bool start_stop, - uint64_t *final_clk_rate, uint64_t request_id) + unsigned long *final_clk_rate, uint64_t request_id) { int i, rc = 0; - uint64_t max_req_clk_rate = 0; + unsigned long max_req_clk_rate = 0; for (i = 0; i < top_common->num_mux; i++) { if (top_common->req_clk_rate[i] > max_req_clk_rate) @@ -158,15 +175,13 @@ static int cam_vfe_top_calc_hw_clk_rate( memset(top_common->last_clk_vote, 0, sizeof(uint64_t) * CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ); top_common->last_clk_counter = 0; - top_common->last_clk_vote[top_common->last_clk_counter] = - max_req_clk_rate; + top_common->last_clk_vote[top_common->last_clk_counter] = max_req_clk_rate; top_common->last_clk_counter = (top_common->last_clk_counter + 1) % CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ; } else { top_common->last_clk_vote[top_common->last_clk_counter] = max_req_clk_rate; - top_common->last_clk_counter = - (top_common->last_clk_counter + 1) % + top_common->last_clk_counter = (top_common->last_clk_counter + 1) % CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ; /* Find max clk request in last few requests */ @@ -575,7 +590,7 @@ int cam_vfe_top_apply_clk_bw_update(struct cam_vfe_top_priv_common *top_common, struct cam_hw_intf *hw_intf = NULL; struct cam_axi_vote *to_be_applied_axi_vote = NULL; struct cam_isp_apply_clk_bw_args *clk_bw_args = NULL; - uint64_t final_clk_rate = 0; + unsigned long final_clk_rate = 0; uint64_t total_bw_new_vote = 0; uint64_t request_id; int rc = 0; @@ -630,10 +645,12 @@ int cam_vfe_top_apply_clk_bw_update(struct cam_vfe_top_priv_common *top_common, goto end; } - CAM_DBG(CAM_PERF, "VFE:%d APPLY CLK/BW req_id:%ld clk_state:%s bw_state:%s ", + CAM_DBG(CAM_PERF, + "VFE:%d APPLY CLK/BW req_id:%ld clk_state:%s bw_state:%s is_drv_config_en:%s", hw_intf->hw_idx, request_id, cam_vfe_top_clk_bw_state_to_string(top_common->clk_state), - cam_vfe_top_clk_bw_state_to_string(top_common->bw_state)); + cam_vfe_top_clk_bw_state_to_string(top_common->bw_state), + CAM_BOOL_TO_YESNO(clk_bw_args->is_drv_config_en)); /* Determine BW and clock voting sequence according to state */ if ((top_common->clk_state == CAM_CLK_BW_STATE_UNCHANGED) && @@ -644,20 +661,23 @@ int cam_vfe_top_apply_clk_bw_update(struct cam_vfe_top_priv_common *top_common, total_bw_new_vote, false, request_id); if (rc) { CAM_ERR(CAM_ISP, - "VFE:%d Failed in voting final bw:%llu clk_state:%s bw_state:%s", + "VFE:%d Failed in voting final bw:%llu clk_state:%s bw_state:%s is_drv_config_en:%s", hw_intf->hw_idx, total_bw_new_vote, cam_vfe_top_clk_bw_state_to_string(top_common->clk_state), - cam_vfe_top_clk_bw_state_to_string(top_common->bw_state)); + cam_vfe_top_clk_bw_state_to_string(top_common->bw_state), + CAM_BOOL_TO_YESNO(clk_bw_args->is_drv_config_en)); goto end; } } else if (top_common->bw_state == CAM_CLK_BW_STATE_UNCHANGED) { - rc = cam_vfe_top_set_hw_clk_rate(top_common, final_clk_rate, false, request_id); + rc = cam_vfe_top_set_hw_clk_rate(top_common, final_clk_rate, false, request_id, + clk_bw_args->is_drv_config_en); if (rc) { CAM_ERR(CAM_ISP, - "VFE:%d Failed in voting final clk:%llu clk_state:%s bw_state:%s", + "VFE:%d Failed in voting final clk:%lu clk_state:%s bw_state:%s is_drv_config_en:%s", hw_intf->hw_idx, final_clk_rate, cam_vfe_top_clk_bw_state_to_string(top_common->clk_state), - cam_vfe_top_clk_bw_state_to_string(top_common->bw_state)); + cam_vfe_top_clk_bw_state_to_string(top_common->bw_state), + CAM_BOOL_TO_YESNO(clk_bw_args->is_drv_config_en)); goto end; } } else if (top_common->clk_state == CAM_CLK_BW_STATE_INCREASE) { @@ -666,31 +686,36 @@ int cam_vfe_top_apply_clk_bw_update(struct cam_vfe_top_priv_common *top_common, total_bw_new_vote, false, request_id); if (rc) { CAM_ERR(CAM_ISP, - "VFE:%d Failed in voting final bw:%llu clk_state:%s bw_state:%s", + "VFE:%d Failed in voting final bw:%llu clk_state:%s bw_state:%s is_drv_config_en:%s", hw_intf->hw_idx, total_bw_new_vote, cam_vfe_top_clk_bw_state_to_string(top_common->clk_state), - cam_vfe_top_clk_bw_state_to_string(top_common->bw_state)); + cam_vfe_top_clk_bw_state_to_string(top_common->bw_state), + CAM_BOOL_TO_YESNO(clk_bw_args->is_drv_config_en)); goto end; } - rc = cam_vfe_top_set_hw_clk_rate(top_common, final_clk_rate, false, 0); + rc = cam_vfe_top_set_hw_clk_rate(top_common, final_clk_rate, false, 0, + clk_bw_args->is_drv_config_en); if (rc) { CAM_ERR(CAM_ISP, - "VFE:%d Failed in voting final clk:%llu clk_state:%s bw_state:%s", + "VFE:%d Failed in voting final clk:%lu clk_state:%s bw_state:%s is_drv_config_en:%s", hw_intf->hw_idx, final_clk_rate, cam_vfe_top_clk_bw_state_to_string(top_common->clk_state), - cam_vfe_top_clk_bw_state_to_string(top_common->bw_state)); + cam_vfe_top_clk_bw_state_to_string(top_common->bw_state), + CAM_BOOL_TO_YESNO(clk_bw_args->is_drv_config_en)); goto end; } } else if (top_common->clk_state == CAM_CLK_BW_STATE_DECREASE) { /* Set Clock first, followed by BW */ - rc = cam_vfe_top_set_hw_clk_rate(top_common, final_clk_rate, false, request_id); + rc = cam_vfe_top_set_hw_clk_rate(top_common, final_clk_rate, false, request_id, + clk_bw_args->is_drv_config_en); if (rc) { CAM_ERR(CAM_ISP, - "VFE:%d Failed in voting final clk:%llu clk_state:%s bw_state:%s", + "VFE:%d Failed in voting final clk:%lu clk_state:%s bw_state:%s is_drv_config_en:%s", hw_intf->hw_idx, final_clk_rate, cam_vfe_top_clk_bw_state_to_string(top_common->clk_state), - cam_vfe_top_clk_bw_state_to_string(top_common->bw_state)); + cam_vfe_top_clk_bw_state_to_string(top_common->bw_state), + CAM_BOOL_TO_YESNO(clk_bw_args->is_drv_config_en)); goto end; } @@ -698,20 +723,26 @@ int cam_vfe_top_apply_clk_bw_update(struct cam_vfe_top_priv_common *top_common, total_bw_new_vote, false, request_id); if (rc) { CAM_ERR(CAM_ISP, - "VFE:%d Failed in voting final bw:%llu clk_state:%s bw_state:%s", + "VFE:%d Failed in voting final bw:%llu clk_state:%s bw_state:%s is_drv_config_en:%s", hw_intf->hw_idx, total_bw_new_vote, cam_vfe_top_clk_bw_state_to_string(top_common->clk_state), - cam_vfe_top_clk_bw_state_to_string(top_common->bw_state)); + cam_vfe_top_clk_bw_state_to_string(top_common->bw_state), + CAM_BOOL_TO_YESNO(clk_bw_args->is_drv_config_en)); goto end; } } else { - CAM_ERR(CAM_ISP, "Invalid state to apply CLK/BW clk_state:%s bw_state:%s", + CAM_ERR(CAM_ISP, + "Invalid state to apply CLK/BW clk_state:%s bw_state:%s is_drv_config_en:%s", cam_vfe_top_clk_bw_state_to_string(top_common->clk_state), - cam_vfe_top_clk_bw_state_to_string(top_common->bw_state)); + cam_vfe_top_clk_bw_state_to_string(top_common->bw_state), + CAM_BOOL_TO_YESNO(clk_bw_args->is_drv_config_en)); rc = -EINVAL; goto end; } + if (top_common->clk_state != CAM_CLK_BW_STATE_UNCHANGED) + clk_bw_args->clock_updated = true; + end: top_common->clk_state = CAM_CLK_BW_STATE_INIT; top_common->bw_state = CAM_CLK_BW_STATE_INIT; @@ -721,7 +752,7 @@ end: int cam_vfe_top_apply_clock_start_stop(struct cam_vfe_top_priv_common *top_common) { int rc = 0; - uint64_t final_clk_rate = 0; + unsigned long final_clk_rate = 0; rc = cam_vfe_top_calc_hw_clk_rate(top_common, true, &final_clk_rate, 0); if (rc) { @@ -734,9 +765,9 @@ int cam_vfe_top_apply_clock_start_stop(struct cam_vfe_top_priv_common *top_commo if (top_common->clk_state == CAM_CLK_BW_STATE_UNCHANGED) goto end; - rc = cam_vfe_top_set_hw_clk_rate(top_common, final_clk_rate, true, 0); + rc = cam_vfe_top_set_hw_clk_rate(top_common, final_clk_rate, true, 0, false); if (rc) { - CAM_ERR(CAM_ISP, "VFE:%d Failed in voting final clk:%llu clk_state:%s", + CAM_ERR(CAM_ISP, "VFE:%d Failed in voting final clk:%lu clk_state:%s", top_common->hw_idx, final_clk_rate, cam_vfe_top_clk_bw_state_to_string(top_common->clk_state)); goto end; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_common.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_common.h index 1eebf61090..f1c43e9be0 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_common.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_common.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _CAM_VFE_TOP_COMMON_H_ @@ -26,7 +27,7 @@ struct cam_vfe_top_priv_common { struct cam_axi_vote last_bw_vote[CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ]; uint64_t last_total_bw_vote[CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ]; uint32_t last_bw_counter; - uint64_t last_clk_vote[CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ]; + unsigned long last_clk_vote[CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ]; uint32_t last_clk_counter; uint64_t total_bw_applied; enum cam_clk_bw_state clk_state; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c index 45d0086240..43658ec243 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -99,7 +100,7 @@ static int cam_vfe_top_dump_info( switch (cmd_type) { case CAM_ISP_HW_NOTIFY_OVERFLOW: CAM_INFO_RATE_LIMIT(CAM_ISP, "VFE%d src_clk_rate:%luHz", - soc_info->index, soc_info->applied_src_clk_rate); + soc_info->index, soc_info->applied_src_clk_rates.sw_client); break; default: CAM_ERR(CAM_ISP, "cmd_type: %u not supported", cmd_type); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c index c976f87aec..5031193929 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -118,7 +119,7 @@ static int cam_vfe_top_ver3_dump_info( switch (cmd_type) { case CAM_ISP_HW_NOTIFY_OVERFLOW: CAM_INFO_RATE_LIMIT(CAM_ISP, "VFE%d src_clk_rate:%luHz", - soc_info->index, soc_info->applied_src_clk_rate); + soc_info->index, soc_info->applied_src_clk_rates.sw_client); break; default: CAM_ERR(CAM_ISP, "cmd_type: %u not supported", cmd_type); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver4.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver4.c index 0de7e6d236..cd89c430db 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver4.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver4.c @@ -540,9 +540,22 @@ static int cam_vfe_top_ver4_print_overflow_debug_info( violation_status = cam_io_r(soc_info->reg_map[VFE_CORE_BASE_IDX].mem_base + common_data->common_reg->bus_violation_status); - CAM_ERR(CAM_ISP, "VFE[%d] sof_cnt:%d src_clk:%luMHz overflow:%s violation:%s", - soc_info->index, top_priv->sof_cnt, soc_info->applied_src_clk_rate / 1000000, - CAM_BOOL_TO_YESNO(bus_overflow_status), CAM_BOOL_TO_YESNO(violation_status)); + if (soc_private->is_ife_lite) + CAM_ERR(CAM_ISP, + "VFE[%d] sof_cnt:%d src_clk:%lu overflow:%s violation:%s", + soc_info->index, top_priv->sof_cnt, + soc_info->applied_src_clk_rates.sw_client, + CAM_BOOL_TO_YESNO(bus_overflow_status), + CAM_BOOL_TO_YESNO(violation_status)); + else + CAM_ERR(CAM_ISP, + "VFE[%d] sof_cnt:%d src_clk sw_client:%lu hw_client:[%lu %lu] overflow:%s violation:%s", + soc_info->index, top_priv->sof_cnt, + soc_info->applied_src_clk_rates.sw_client, + soc_info->applied_src_clk_rates.hw_client[soc_info->index].high, + soc_info->applied_src_clk_rates.hw_client[soc_info->index].low, + CAM_BOOL_TO_YESNO(bus_overflow_status), + CAM_BOOL_TO_YESNO(violation_status)); if (bus_overflow_status) { overflow_info->is_bus_overflow = true; diff --git a/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.c b/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.c index b5abbd4990..ee9a466141 100644 --- a/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.c +++ b/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2019, 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -69,7 +70,7 @@ int cam_jpeg_dma_enable_soc_resources(struct cam_hw_soc_info *soc_info) { int rc; - rc = cam_soc_util_enable_platform_resource(soc_info, true, + rc = cam_soc_util_enable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDX, true, CAM_SVS_VOTE, true); if (rc) CAM_ERR(CAM_JPEG, "enable platform failed %d", rc); @@ -81,7 +82,7 @@ int cam_jpeg_dma_disable_soc_resources(struct cam_hw_soc_info *soc_info) { int rc; - rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + rc = cam_soc_util_disable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDX, true, true); if (rc) CAM_ERR(CAM_JPEG, "disable platform failed %d", rc); diff --git a/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.c b/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.c index 79428a6c4c..787902ebef 100644 --- a/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.c +++ b/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2019, 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -68,7 +69,7 @@ int cam_jpeg_enc_enable_soc_resources(struct cam_hw_soc_info *soc_info) { int rc; - rc = cam_soc_util_enable_platform_resource(soc_info, true, + rc = cam_soc_util_enable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDX, true, CAM_SVS_VOTE, true); if (rc) CAM_ERR(CAM_JPEG, "enable platform failed %d", rc); @@ -80,7 +81,7 @@ int cam_jpeg_enc_disable_soc_resources(struct cam_hw_soc_info *soc_info) { int rc; - rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + rc = cam_soc_util_disable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDX, true, true); if (rc) CAM_ERR(CAM_JPEG, "disable platform failed %d", rc); diff --git a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.c b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.c index 5ef984cba8..68e7b1a248 100644 --- a/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.c +++ b/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -43,8 +44,8 @@ int cam_lrme_soc_enable_resources(struct cam_hw_info *lrme_hw) return -EFAULT; } - rc = cam_soc_util_enable_platform_resource(soc_info, true, CAM_SVS_VOTE, - true); + rc = cam_soc_util_enable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDX, true, + CAM_SVS_VOTE, true); if (rc) { CAM_ERR(CAM_LRME, "Failed to enable platform resource, rc %d", rc); @@ -72,7 +73,7 @@ int cam_lrme_soc_disable_resources(struct cam_hw_info *lrme_hw) cam_lrme_set_irq(lrme_hw, CAM_LRME_IRQ_DISABLE); - rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + rc = cam_soc_util_disable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDX, true, true); if (rc) { CAM_ERR(CAM_LRME, "Failed to disable platform resource"); return rc; diff --git a/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_core.c b/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_core.c index b9a20fdf58..57c1633344 100644 --- a/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_core.c +++ b/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_core.c @@ -1688,7 +1688,7 @@ int cam_ope_process_cmd(void *device_priv, uint32_t cmd_type, (struct cam_ope_dev_clk_update *)cmd_args; if (core_info->clk_enable == false) { - rc = cam_soc_util_clk_enable_default(soc_info, + rc = cam_soc_util_clk_enable_default(soc_info, CAM_CLK_SW_CLIENT_IDX, CAM_SVS_VOTE); if (rc) { CAM_ERR(CAM_OPE, "Clock enable is failed"); @@ -1704,7 +1704,7 @@ int cam_ope_process_cmd(void *device_priv, uint32_t cmd_type, break; case OPE_HW_CLK_DISABLE: { if (core_info->clk_enable == true) - cam_soc_util_clk_disable_default(soc_info); + cam_soc_util_clk_disable_default(soc_info, CAM_CLK_SW_CLIENT_IDX); core_info->clk_enable = false; } diff --git a/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_soc.c b/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_soc.c index ca1491c7ca..9f1918c8fe 100644 --- a/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_soc.c +++ b/drivers/cam_ope/ope_hw_mgr/ope_hw/ope_soc.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -96,7 +97,7 @@ int cam_ope_enable_soc_resources(struct cam_hw_soc_info *soc_info) { int rc = 0; - rc = cam_soc_util_enable_platform_resource(soc_info, true, + rc = cam_soc_util_enable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDX, true, CAM_SVS_VOTE, true); if (rc) { CAM_ERR(CAM_OPE, "enable platform failed"); @@ -111,7 +112,7 @@ int cam_ope_disable_soc_resources(struct cam_hw_soc_info *soc_info, { int rc = 0; - rc = cam_soc_util_disable_platform_resource(soc_info, disable_clk, + rc = cam_soc_util_disable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDX, disable_clk, true); if (rc) CAM_ERR(CAM_OPE, "enable platform failed"); @@ -144,7 +145,7 @@ int cam_ope_update_clk_rate(struct cam_hw_soc_info *soc_info, CAM_DBG(CAM_OPE, "clk_rate = %u src_clk_index = %d", clk_rate, src_clk_idx); - return cam_soc_util_set_src_clk_rate(soc_info, clk_rate); + return cam_soc_util_set_src_clk_rate(soc_info, CAM_CLK_SW_CLIENT_IDX, clk_rate, 0); } int cam_ope_toggle_clk(struct cam_hw_soc_info *soc_info, bool clk_enable) @@ -152,9 +153,9 @@ int cam_ope_toggle_clk(struct cam_hw_soc_info *soc_info, bool clk_enable) int rc = 0; if (clk_enable) - rc = cam_soc_util_clk_enable_default(soc_info, CAM_SVS_VOTE); + rc = cam_soc_util_clk_enable_default(soc_info, CAM_CLK_SW_CLIENT_IDX, CAM_SVS_VOTE); else - cam_soc_util_clk_disable_default(soc_info); + cam_soc_util_clk_disable_default(soc_info, CAM_CLK_SW_CLIENT_IDX); return rc; } diff --git a/drivers/cam_req_mgr/cam_subdev.h b/drivers/cam_req_mgr/cam_subdev.h index 27b08d3438..6af89c75bc 100644 --- a/drivers/cam_req_mgr/cam_subdev.h +++ b/drivers/cam_req_mgr/cam_subdev.h @@ -17,10 +17,71 @@ #define CAM_SUBDEVICE_EVENT_MAX 30 + +/* Enum for indicating CSID event */ +enum cam_subdev_phy_csid_state { + CAM_SUBDEV_PHY_CSID_HALT = 1, + CAM_SUBDEV_PHY_CSID_RESUME, +}; + +/** + * struct cam_subdev_msg_phy_conn_csid_info: Contains phy num and connected CSID info + * + * @phy_idx: Phy idx value indicating which phy is connected to csid core + * @lane_cfg: This value is similar to lane_assign in the PHY + * driver, and is used to identify the particular + * PHY instance with which this IFE session is + * connected to. + * @core_idx: Primary(in case of dual ife) core idx for the csid to which the phy + * is connected, -1 while disconnecting + */ +struct cam_subdev_msg_phy_conn_csid_info { + uint32_t phy_idx; + uint32_t lane_cfg; + int32_t core_idx; +}; + +/** + * struct cam_subdev_msg_phy_drv_info: Contains drv config info + * + * @phy_idx: Phy idx value indicating which phy is connected to csid core + * @lane_cfg: This value is similar to lane_assign in the PHY + * driver, and is used to identify the particular + * PHY instance with which this IFE session is + * connected to. + * @use_hw_client_voting: Whether to use hw client voting for csiphy clk + * @is_drv_config_en: If DRV config is enabled in CSID + */ +struct cam_subdev_msg_phy_drv_info { + uint32_t phy_idx; + uint32_t lane_cfg; + bool use_hw_client_voting; + bool is_drv_config_en; +}; + +/** + * struct cam_subdev_msg_phy_halt_resume_info: Contains csid halt resume info + * + * @phy_idx: Phy idx value indicating which phy is connected to csid core + * @lane_cfg: This value is similar to lane_assign in the PHY + * driver, and is used to identify the particular + * PHY instance with which this IFE session is + * connected to. + * @csid_state: Notification of CSID state + */ +struct cam_subdev_msg_phy_halt_resume_info { + uint32_t phy_idx; + uint32_t lane_cfg; + enum cam_subdev_phy_csid_state csid_state; +}; + enum cam_subdev_message_type_t { CAM_SUBDEV_MESSAGE_REG_DUMP = 0x1, CAM_SUBDEV_MESSAGE_APPLY_CSIPHY_AUX, CAM_SUBDEV_MESSAGE_DOMAIN_ID_SECURE_PARAMS, + CAM_SUBDEV_MESSAGE_CONN_CSID_INFO, + CAM_SUBDEV_MESSAGE_DRV_INFO, + CAM_SUBDEV_MESSAGE_NOTIFY_HALT_RESUME, }; /* Enum for close sequence priority */ diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c b/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c index b1a783f8a1..0721a0913f 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c @@ -176,7 +176,7 @@ int cam_cci_init(struct v4l2_subdev *sd, cam_cci_get_clk_rates(cci_dev, c_ctrl); /* Enable Regulators and IRQ*/ - rc = cam_soc_util_enable_platform_resource(soc_info, true, + rc = cam_soc_util_enable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDX, true, CAM_LOWSVS_VOTE, true); if (rc < 0) { CAM_DBG(CAM_CCI, "CCI%d_I2C_M%d request platform resources failed, rc: %d", @@ -220,7 +220,7 @@ int cam_cci_init(struct v4l2_subdev *sd, return 0; reset_complete_failed: - cam_soc_util_disable_platform_resource(soc_info, true, true); + cam_soc_util_disable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDX, true, true); platform_enable_failed: cci_dev->ref_count--; cam_cpas_stop(cci_dev->cpas_handle); @@ -456,7 +456,7 @@ int cam_cci_soc_release(struct cci_device *cci_dev, cci_dev->i2c_freq_mode[i] = I2C_MAX_MODES; } - rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + rc = cam_soc_util_disable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDX, true, true); if (rc) { CAM_ERR(CAM_CCI, "CCI%d_I2C_M%d platform resources disable failed, rc: %d", cci_dev->soc_info.index, master, rc); diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c index d7a000d34b..d8bd159287 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c @@ -161,6 +161,9 @@ static void cam_csiphy_reset_phyconfig_param(struct csiphy_device *csiphy_dev, csiphy_dev->csiphy_info[index].mipi_flags = 0; csiphy_dev->csiphy_info[index].hdl_data.device_hdl = -1; csiphy_dev->csiphy_info[index].csiphy_3phase = -1; + csiphy_dev->csiphy_info[index].conn_csid_idx = -1; + csiphy_dev->csiphy_info[index].use_hw_client_voting = false; + csiphy_dev->csiphy_info[index].is_drv_config_en = false; } static inline void cam_csiphy_apply_onthego_reg_values(void __iomem *csiphybase, uint8_t csiphy_idx) @@ -1401,7 +1404,9 @@ void cam_csiphy_shutdown(struct csiphy_device *csiphy_dev) { struct cam_hw_soc_info *soc_info; struct csiphy_reg_parms_t *csiphy_reg; + struct cam_csiphy_param *param; int32_t i = 0; + int rc = 0; if (csiphy_dev->csiphy_state == CAM_CSIPHY_INIT) return; @@ -1423,13 +1428,31 @@ void cam_csiphy_shutdown(struct csiphy_device *csiphy_dev) soc_info = &csiphy_dev->soc_info; for (i = 0; i < csiphy_dev->acquire_count; i++) { - if (csiphy_dev->csiphy_info[i].secure_mode) - cam_csiphy_program_secure_mode( - csiphy_dev, + param = &csiphy_dev->csiphy_info[i]; + + if (param->secure_mode) + cam_csiphy_program_secure_mode(csiphy_dev, CAM_SECURE_MODE_NON_SECURE, i); - csiphy_dev->csiphy_info[i].secure_mode = - CAM_SECURE_MODE_NON_SECURE; + param->secure_mode = CAM_SECURE_MODE_NON_SECURE; + + if (soc_info->is_clk_drv_en && param->use_hw_client_voting) { + rc = cam_soc_util_set_src_clk_rate(soc_info, param->conn_csid_idx, + 0, 0); + if (rc) { + CAM_ERR(CAM_CSIPHY, + "[%d] Failed in setting clk rate for %d", + soc_info->index, param->conn_csid_idx); + } else { + rc = cam_soc_util_cesta_channel_switch(param->conn_csid_idx, + "csiphy_shutdown"); + if (rc) { + CAM_ERR(CAM_CSIPHY, + "Failed to apply power states for cesta client:%d rc:%d", + param->conn_csid_idx, rc); + } + } + } cam_csiphy_reset_phyconfig_param(csiphy_dev, i); } @@ -1445,7 +1468,7 @@ void cam_csiphy_shutdown(struct csiphy_device *csiphy_dev) } cam_csiphy_reset(csiphy_dev); - cam_soc_util_disable_platform_resource(soc_info, true, true); + cam_soc_util_disable_platform_resource(soc_info, CAM_CLK_SW_CLIENT_IDX, true, true); cam_cpas_stop(csiphy_dev->cpas_handle); csiphy_dev->csiphy_state = CAM_CSIPHY_ACQUIRE; @@ -2092,6 +2115,9 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, csiphy_acq_dev.session_handle; csiphy_dev->csiphy_info[index].csiphy_3phase = csiphy_acq_params.csiphy_3phase; + csiphy_dev->csiphy_info[index].conn_csid_idx = -1; + csiphy_dev->csiphy_info[index].use_hw_client_voting = false; + csiphy_dev->csiphy_info[index].is_drv_config_en = false; CAM_DBG(CAM_CSIPHY, "Add dev_handle:0x%x at index: %d ", csiphy_dev->csiphy_info[index].hdl_data.device_hdl, @@ -2151,6 +2177,7 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, case CAM_STOP_DEV: { int32_t offset, rc = 0; struct cam_start_stop_dev_cmd config; + struct cam_csiphy_param *param; rc = copy_from_user(&config, (void __user *)cmd->handle, sizeof(config)); @@ -2173,40 +2200,52 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, goto release_mutex; } + param = &csiphy_dev->csiphy_info[offset]; + if (--csiphy_dev->start_dev_count) { - if (csiphy_dev->csiphy_info[offset].secure_mode) - cam_csiphy_program_secure_mode( - csiphy_dev, + if (param->secure_mode) + cam_csiphy_program_secure_mode(csiphy_dev, CAM_SECURE_MODE_NON_SECURE, offset); - csiphy_dev->csiphy_info[offset].secure_mode = - CAM_SECURE_MODE_NON_SECURE; - csiphy_dev->csiphy_info[offset].csiphy_cpas_cp_reg_mask - = 0; + param->secure_mode = CAM_SECURE_MODE_NON_SECURE; + param->csiphy_cpas_cp_reg_mask = 0; cam_csiphy_update_lane_selection(csiphy_dev, offset, false); + if (soc_info->is_clk_drv_en && param->use_hw_client_voting) { + rc = cam_soc_util_set_src_clk_rate(soc_info, param->conn_csid_idx, + 0, 0); + if (rc) { + CAM_ERR(CAM_CSIPHY, + "[%d] Failed in setting clk rate for %d", + soc_info->index, param->conn_csid_idx); + } else { + rc = cam_soc_util_cesta_channel_switch(param->conn_csid_idx, + "csiphy_stop_dev"); + if (rc) { + CAM_ERR(CAM_CSIPHY, + "Failed to apply power states for cesta client:%d rc:%d", + param->conn_csid_idx, rc); + } + } + } + CAM_INFO(CAM_CSIPHY, - "CAM_STOP_PHYDEV: %d, Type: %s, dev_cnt: %u, slot: %d, Datarate: %llu, Settletime: %llu", - soc_info->index, + "CAM_STOP_PHYDEV: %d, CSID:%d, Type: %s, dev_cnt: %u, slot: %d, Datarate: %llu, Settletime: %llu", + soc_info->index, param->conn_csid_idx, g_phy_data[soc_info->index].is_3phase ? "CPHY" : "DPHY", - csiphy_dev->start_dev_count, - offset, - csiphy_dev->csiphy_info[offset].data_rate, - csiphy_dev->csiphy_info[offset].settle_time); + csiphy_dev->start_dev_count, offset, param->data_rate, + param->settle_time); goto release_mutex; } - if (csiphy_dev->csiphy_info[offset].secure_mode) - cam_csiphy_program_secure_mode( - csiphy_dev, - CAM_SECURE_MODE_NON_SECURE, offset); + if (param->secure_mode) + cam_csiphy_program_secure_mode(csiphy_dev, CAM_SECURE_MODE_NON_SECURE, + offset); - csiphy_dev->csiphy_info[offset].secure_mode = - CAM_SECURE_MODE_NON_SECURE; - - csiphy_dev->csiphy_info[offset].csiphy_cpas_cp_reg_mask = 0x0; + param->secure_mode = CAM_SECURE_MODE_NON_SECURE; + param->csiphy_cpas_cp_reg_mask = 0x0; if (csiphy_dev->prgm_cmn_reg_across_csiphy) { mutex_lock(&active_csiphy_cnt_mutex); @@ -2225,7 +2264,7 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, cam_csiphy_update_lane_selection(csiphy_dev, offset, false); - rc = cam_csiphy_disable_hw(csiphy_dev); + rc = cam_csiphy_disable_hw(csiphy_dev, offset); if (rc < 0) CAM_ERR(CAM_CSIPHY, "Failed in csiphy release"); @@ -2237,12 +2276,10 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, csiphy_dev->csiphy_state = CAM_CSIPHY_ACQUIRE; CAM_INFO(CAM_CSIPHY, - "CAM_STOP_PHYDEV: %u, Type: %s, slot: %d, Datarate: %llu, Settletime: %llu", - soc_info->index, + "CAM_STOP_PHYDEV: %u, CSID:%d, Type: %s, slot: %d, Datarate: %llu, Settletime: %llu", + soc_info->index, param->conn_csid_idx, g_phy_data[soc_info->index].is_3phase ? "CPHY" : "DPHY", - offset, - csiphy_dev->csiphy_info[offset].data_rate, - csiphy_dev->csiphy_info[offset].settle_time); + offset, param->data_rate, param->settle_time); } break; case CAM_RELEASE_DEV: { @@ -2350,9 +2387,11 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, break; } case CAM_START_DEV: { + struct cam_csiphy_param *param; struct cam_start_stop_dev_cmd config; int32_t offset; - int clk_vote_level = -1; + int clk_vote_level_high = -1; + int clk_vote_level_low = -1; uint8_t data_rate_variant_idx = 0; CAM_DBG(CAM_CSIPHY, "START_DEV Called"); @@ -2382,17 +2421,63 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, goto release_mutex; } + param = &csiphy_dev->csiphy_info[offset]; + + rc = cam_cpas_query_drv_enable(NULL, &soc_info->is_clk_drv_en); + if (rc) { + CAM_ERR(CAM_CSIPHY, "Failed to query DRV enable rc: %d", rc); + goto release_mutex; + } + if (csiphy_dev->start_dev_count) { - clk_vote_level = - csiphy_dev->ctrl_reg->getclockvoting( - csiphy_dev, offset); - rc = cam_soc_util_set_clk_rate_level( - &csiphy_dev->soc_info, clk_vote_level, false); - if (rc) { - CAM_WARN(CAM_CSIPHY, - "Failed to set the clk_rate level: %d", - clk_vote_level); - rc = 0; + clk_vote_level_high = + csiphy_dev->ctrl_reg->getclockvoting(csiphy_dev, offset); + clk_vote_level_low = clk_vote_level_high; + + CAM_DBG(CAM_CSIPHY, + "CSIPHY[%d] is_clk_drv_en[%d] conn_csid_idx[%d] use_hw_client_voting[%d] is_drv_config_en[%d]", + csiphy_dev->soc_info.index, soc_info->is_clk_drv_en, + param->conn_csid_idx, param->use_hw_client_voting, + param->is_drv_config_en); + + if (soc_info->is_clk_drv_en && param->use_hw_client_voting) { + if (param->is_drv_config_en) + clk_vote_level_low = CAM_LOWSVS_VOTE; + + rc = cam_soc_util_set_clk_rate_level(&csiphy_dev->soc_info, + param->conn_csid_idx, clk_vote_level_high, + clk_vote_level_low, false); + if (rc) { + CAM_ERR(CAM_CSIPHY, + "Failed to set the req clk_rate level[high low]: [%s %s] cesta_client_idx: %d rc: %d", + cam_soc_util_get_string_from_level( + clk_vote_level_high), + cam_soc_util_get_string_from_level( + clk_vote_level_low), param->conn_csid_idx, rc); + rc = -EINVAL; + goto release_mutex; + } + + rc = cam_soc_util_cesta_channel_switch(param->conn_csid_idx, + "csiphy_combo"); + if (rc) { + CAM_ERR(CAM_CSIPHY, + "Failed to apply power states for crm client:%d rc:%d", + param->conn_csid_idx, rc); + rc = 0; + } + } else { + rc = cam_soc_util_set_clk_rate_level(&csiphy_dev->soc_info, + CAM_CLK_SW_CLIENT_IDX, clk_vote_level_high, 0, false); + if (rc) { + CAM_WARN(CAM_CSIPHY, + "Failed to set the req clk_rate level: %s", + cam_soc_util_get_string_from_level( + clk_vote_level_high)); + rc = -EINVAL; + goto release_mutex; + + } } if (csiphy_dev->csiphy_info[offset].secure_mode == 1) { @@ -2440,8 +2525,9 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, csiphy_dev->start_dev_count++; CAM_INFO(CAM_CSIPHY, - "CAM_START_PHYDEV: %d, Type: %s, dev_cnt: %u, slot: %d, combo: %u, cphy+dphy: %u, sec_mode: %d, Datarate: %llu, Settletime: %llu", + "CAM_START_PHYDEV: %d, CSID:%d, Type: %s, dev_cnt: %u, slot: %d, combo: %u, cphy+dphy: %u, sec_mode: %d, Datarate: %llu, Settletime: %llu", soc_info->index, + csiphy_dev->csiphy_info[offset].conn_csid_idx, g_phy_data[soc_info->index].is_3phase ? "CPHY" : "DPHY", csiphy_dev->start_dev_count, offset, @@ -2505,7 +2591,7 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, rc = cam_csiphy_config_dev(csiphy_dev, config.dev_handle, data_rate_variant_idx); if (rc < 0) { CAM_ERR(CAM_CSIPHY, "cam_csiphy_config_dev failed"); - cam_csiphy_disable_hw(csiphy_dev); + cam_csiphy_disable_hw(csiphy_dev, offset); goto hw_cnt_decrement; } @@ -2549,8 +2635,9 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, csiphy_dev->csiphy_state = CAM_CSIPHY_START; CAM_INFO(CAM_CSIPHY, - "CAM_START_PHYDEV: %d, Type: %s, slot: %d, sec_mode: %d, Datarate: %llu, Settletime: %llu, combo: %u, cphy+dphy: %u", + "CAM_START_PHYDEV: %d, CSID:%d, Type: %s, slot: %d, sec_mode: %d, Datarate: %llu, Settletime: %llu, combo: %u, cphy+dphy: %u", soc_info->index, + csiphy_dev->csiphy_info[offset].conn_csid_idx, g_phy_data[soc_info->index].is_3phase ? "CPHY" : "DPHY", offset, csiphy_dev->csiphy_info[offset].secure_mode, diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c index b39c0297f1..08caa03943 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c @@ -85,6 +85,22 @@ int cam_csiphy_format_secure_phy_lane_info( } +static int cam_csiphy_get_session_index(struct csiphy_device *csiphy_dev, + uint32_t lane_assign) +{ + int i = 0; + struct cam_csiphy_param *param; + + for (i = 0; i < CSIPHY_MAX_INSTANCES_PER_PHY; i++) { + param = &csiphy_dev->csiphy_info[i]; + + if (param->lane_assign == lane_assign) + break; + } + + return i; +} + static void cam_csiphy_populate_secure_info( struct csiphy_device *csiphy_dev, void *data) { @@ -136,6 +152,7 @@ static void cam_csiphy_subdev_handle_message(struct v4l2_subdev *sd, { struct csiphy_device *csiphy_dev = v4l2_get_subdevdata(sd); uint32_t phy_idx; + int rc = 0; if (!data) { CAM_ERR(CAM_CSIPHY, "Empty Payload"); @@ -172,6 +189,110 @@ static void cam_csiphy_subdev_handle_message(struct v4l2_subdev *sd, break; } + case CAM_SUBDEV_MESSAGE_CONN_CSID_INFO: { + struct cam_subdev_msg_phy_conn_csid_info *conn_csid_info = + (struct cam_subdev_msg_phy_conn_csid_info *) data; + int idx; + struct cam_csiphy_param *param; + + idx = cam_csiphy_get_session_index(csiphy_dev, conn_csid_info->lane_cfg); + if (idx >= CSIPHY_MAX_INSTANCES_PER_PHY) { + CAM_ERR(CAM_CSIPHY, "Phy session not found %d %d", + csiphy_dev->soc_info.index, conn_csid_info->lane_cfg); + rc = -EBADR; + break; + } + + param = &csiphy_dev->csiphy_info[idx]; + param->conn_csid_idx = conn_csid_info->core_idx; + + CAM_DBG(CAM_CSIPHY, "PHY: %d, CSID: %d connected", csiphy_dev->soc_info.index, + param->conn_csid_idx); + break; + } + case CAM_SUBDEV_MESSAGE_DRV_INFO: { + struct cam_subdev_msg_phy_drv_info *drv_info = + (struct cam_subdev_msg_phy_drv_info *) data; + int idx; + struct cam_csiphy_param *param; + + idx = cam_csiphy_get_session_index(csiphy_dev, drv_info->lane_cfg); + if (idx >= CSIPHY_MAX_INSTANCES_PER_PHY) { + CAM_ERR(CAM_CSIPHY, "Phy session not found %d %d", + csiphy_dev->soc_info.index, drv_info->lane_cfg); + rc = -EBADR; + break; + } + + param = &csiphy_dev->csiphy_info[idx]; + param->is_drv_config_en = drv_info->is_drv_config_en; + param->use_hw_client_voting = drv_info->use_hw_client_voting; + + CAM_DBG(CAM_CSIPHY, + "PHY: %d, CSID: %d DRV info : use hw client %d, enable drv config %d", + csiphy_dev->soc_info.index, param->conn_csid_idx, + param->use_hw_client_voting, param->is_drv_config_en); + + break; + } + case CAM_SUBDEV_MESSAGE_NOTIFY_HALT_RESUME: { + int drv_idx; + struct cam_subdev_msg_phy_halt_resume_info *halt_resume_info = + (struct cam_subdev_msg_phy_halt_resume_info *) data; + int idx; + struct cam_csiphy_param *param; + unsigned long clk_rate; + + idx = cam_csiphy_get_session_index(csiphy_dev, halt_resume_info->lane_cfg); + if (idx >= CSIPHY_MAX_INSTANCES_PER_PHY) { + CAM_ERR(CAM_CSIPHY, "Phy session not found %d %d", + csiphy_dev->soc_info.index, halt_resume_info->lane_cfg); + rc = -EBADR; + break; + } + + param = &csiphy_dev->csiphy_info[idx]; + drv_idx = param->conn_csid_idx; + + if (!csiphy_dev->soc_info.is_clk_drv_en || !param->use_hw_client_voting || + !param->is_drv_config_en) + break; + + CAM_DBG(CAM_CSIPHY, + "PHY: %d, CSID: %d DRV info : use hw client %d, enable drv config %d, op=%s", + csiphy_dev->soc_info.index, param->conn_csid_idx, + param->use_hw_client_voting, param->is_drv_config_en, + (halt_resume_info->csid_state == CAM_SUBDEV_PHY_CSID_HALT) ? "HALT" : + "RESUME"); + + if (halt_resume_info->csid_state == CAM_SUBDEV_PHY_CSID_HALT) { + clk_rate = + csiphy_dev->soc_info.applied_src_clk_rates.hw_client[drv_idx].high; + + rc = cam_soc_util_set_src_clk_rate(&csiphy_dev->soc_info, + CAM_CLK_SW_CLIENT_IDX, clk_rate, 0); + if (rc) + CAM_ERR(CAM_CSIPHY, + "PHY[%d] CSID HALT: csiphy set_rate %ld failed rc: %d", + phy_idx, clk_rate, rc); + } else if (halt_resume_info->csid_state == CAM_SUBDEV_PHY_CSID_RESUME) { + int32_t src_idx = csiphy_dev->soc_info.src_clk_idx; + + clk_rate = csiphy_dev->soc_info.clk_rate[CAM_LOWSVS_VOTE][src_idx]; + + rc = cam_soc_util_set_src_clk_rate(&csiphy_dev->soc_info, + CAM_CLK_SW_CLIENT_IDX, clk_rate, 0); + if (rc) + CAM_ERR(CAM_CSIPHY, + "PHY[%d] CSID RESUME: csiphy _set_rate %ld failed rc: %d", + phy_idx, clk_rate, rc); + } else { + CAM_ERR(CAM_CSIPHY, + "CSIPHY:%d Failed to handle CSID halt resume csid_state: %d", + phy_idx, halt_resume_info->csid_state); + } + break; + } default: break; } @@ -431,6 +552,9 @@ static int cam_csiphy_component_bind(struct device *dev, new_csiphy_dev->csiphy_info[i].lane_assign = 0; new_csiphy_dev->csiphy_info[i].lane_enable = 0; new_csiphy_dev->csiphy_info[i].mipi_flags = 0; + new_csiphy_dev->csiphy_info[i].conn_csid_idx = -1; + new_csiphy_dev->csiphy_info[i].use_hw_client_voting = false; + new_csiphy_dev->csiphy_info[i].is_drv_config_en = false; } new_csiphy_dev->ops.get_dev_info = NULL; diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h index 4f19ccbdcf..9525699471 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h @@ -334,6 +334,9 @@ struct csiphy_ctrl_t { * format for scm call * @secure_info_updated : If all information in the secure_info struct above * is passed and formatted properly from CSID driver + * @conn_csid_idx : Connected CSID core idx (Primary csid in case of dual ife) + * @use_hw_client_voting : Whether to use hw client voting for clk on chipsets with cesta + * @is_drv_config_en : If drv is configured in CSID */ struct cam_csiphy_param { uint16_t lane_assign; @@ -348,6 +351,9 @@ struct cam_csiphy_param { struct csiphy_hdl_tbl hdl_data; struct cam_csiphy_tz_secure_info secure_info; bool secure_info_updated; + int32_t conn_csid_idx; + bool use_hw_client_voting; + bool is_drv_config_en; }; struct csiphy_work_queue { diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c index 15054f44fb..e866b2aa43 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c @@ -179,53 +179,80 @@ int32_t cam_csiphy_enable_hw(struct csiphy_device *csiphy_dev, int32_t index) { int32_t rc = 0; struct cam_hw_soc_info *soc_info; - enum cam_vote_level vote_level = CAM_SVS_VOTE; + enum cam_vote_level vote_level; + struct cam_csiphy_param *param = &csiphy_dev->csiphy_info[index]; soc_info = &csiphy_dev->soc_info; if (csiphy_dev->ref_count++) { CAM_ERR(CAM_CSIPHY, "csiphy refcount = %d", csiphy_dev->ref_count); - return rc; + goto end; } vote_level = csiphy_dev->ctrl_reg->getclockvoting(csiphy_dev, index); - rc = cam_soc_util_enable_platform_resource(soc_info, true, - vote_level, true); - if (rc < 0) { - CAM_ERR(CAM_CSIPHY, "failed to enable platform resources %d", - rc); - return rc; + + rc = cam_soc_util_enable_platform_resource(soc_info, + (soc_info->is_clk_drv_en && param->use_hw_client_voting) ? + param->conn_csid_idx : CAM_CLK_SW_CLIENT_IDX, true, vote_level, true); + if (rc) { + CAM_ERR(CAM_CSIPHY, + "[%s] failed to enable platform resources, clk_drv_en=%d, use_hw_client=%d conn_csid_idx=%d, rc=%d", + soc_info->dev_name, soc_info->is_clk_drv_en, param->use_hw_client_voting, + param->conn_csid_idx, rc); + goto end; } - rc = cam_soc_util_set_src_clk_rate(soc_info, - soc_info->clk_rate[0][soc_info->src_clk_idx]); + if (soc_info->is_clk_drv_en && param->use_hw_client_voting && param->is_drv_config_en) { + int clk_vote_level_high = vote_level; + int clk_vote_level_low = CAM_LOWSVS_VOTE; + + rc = cam_soc_util_set_clk_rate_level(soc_info, param->conn_csid_idx, + clk_vote_level_high, clk_vote_level_low, false); + if (rc) { + CAM_ERR(CAM_CSIPHY, + "Failed to set the req clk_rate level[high low]: [%s %s] cesta_client_idx: %d rc: %d", + cam_soc_util_get_string_from_level(clk_vote_level_high), + cam_soc_util_get_string_from_level(clk_vote_level_low), + param->conn_csid_idx, rc); + rc = -EINVAL; + goto disable_platform_resource; + } + + rc = cam_soc_util_cesta_channel_switch(param->conn_csid_idx, "csiphy_start"); + if (rc) { + CAM_ERR(CAM_CSIPHY, + "[%s] Failed to apply power states for crm client:%d rc:%d", + soc_info->dev_name, param->conn_csid_idx, rc); + goto disable_platform_resource; + } - if (rc < 0) { - CAM_ERR(CAM_CSIPHY, "csiphy_clk_set_rate failed rc: %d", rc); - goto csiphy_disable_platform_resource; } cam_csiphy_reset(csiphy_dev); return rc; - -csiphy_disable_platform_resource: - cam_soc_util_disable_platform_resource(soc_info, true, true); - +disable_platform_resource: + cam_soc_util_disable_platform_resource(soc_info, + (soc_info->is_clk_drv_en && param->use_hw_client_voting) ? + param->conn_csid_idx : CAM_CLK_SW_CLIENT_IDX, + true, true); +end: return rc; } -int32_t cam_csiphy_disable_hw(struct csiphy_device *csiphy_dev) +int32_t cam_csiphy_disable_hw(struct csiphy_device *csiphy_dev, int32_t index) { struct cam_hw_soc_info *soc_info; + struct cam_csiphy_param *param; if (!csiphy_dev || !csiphy_dev->ref_count) { CAM_ERR(CAM_CSIPHY, "csiphy dev NULL / ref_count ZERO"); return 0; } soc_info = &csiphy_dev->soc_info; + param = &csiphy_dev->csiphy_info[index]; if (--csiphy_dev->ref_count) { CAM_ERR(CAM_CSIPHY, "csiphy refcount = %d", @@ -235,7 +262,10 @@ int32_t cam_csiphy_disable_hw(struct csiphy_device *csiphy_dev) cam_csiphy_reset(csiphy_dev); - cam_soc_util_disable_platform_resource(soc_info, true, true); + cam_soc_util_disable_platform_resource(soc_info, + (soc_info->is_clk_drv_en && param->use_hw_client_voting) ? + param->conn_csid_idx : CAM_CLK_SW_CLIENT_IDX, + true, true); return 0; } diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h index b3dfaf18af..31dabf125a 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h +++ b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h @@ -65,7 +65,7 @@ int cam_csiphy_enable_hw(struct csiphy_device *csiphy_dev, int32_t index); * * This API disables SOC related parameters */ -int cam_csiphy_disable_hw(struct csiphy_device *csiphy_dev); +int cam_csiphy_disable_hw(struct csiphy_device *csiphy_dev, int32_t index); /** * @soc_info: Soc info of cam hw driver module diff --git a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c index f8c9572d47..9a92698601 100644 --- a/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c +++ b/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c @@ -2174,8 +2174,8 @@ int cam_sensor_core_power_up(struct cam_sensor_power_ctrl_t *ctrl, power_setting->config_val; for (j = 0; j < soc_info->num_clk; j++) { - rc = cam_soc_util_clk_enable(soc_info, false, - j, 0, NULL); + rc = cam_soc_util_clk_enable(soc_info, CAM_CLK_SW_CLIENT_IDX, + false, j, 0); if (rc) { CAM_ERR(CAM_UTIL, "Failed in clk enable %d", i); @@ -2318,7 +2318,7 @@ power_up_failed: switch (power_setting->seq_type) { case SENSOR_MCLK: for (i = soc_info->num_clk - 1; i >= 0; i--) { - cam_soc_util_clk_disable(soc_info, false, i); + cam_soc_util_clk_disable(soc_info, CAM_CLK_SW_CLIENT_IDX, false, i); } ret = cam_config_mclk_reg(ctrl, soc_info, index); if (ret < 0) { @@ -2475,7 +2475,7 @@ int cam_sensor_util_power_down(struct cam_sensor_power_ctrl_t *ctrl, switch (pd->seq_type) { case SENSOR_MCLK: for (i = soc_info->num_clk - 1; i >= 0; i--) { - cam_soc_util_clk_disable(soc_info, false, i); + cam_soc_util_clk_disable(soc_info, CAM_CLK_SW_CLIENT_IDX, false, i); } ret = cam_config_mclk_reg(ctrl, soc_info, index); diff --git a/drivers/cam_sensor_module/cam_tpg/tpg_hw/tpg_hw.c b/drivers/cam_sensor_module/cam_tpg/tpg_hw/tpg_hw.c index 4a0978a05a..847e0cb46d 100644 --- a/drivers/cam_sensor_module/cam_tpg/tpg_hw/tpg_hw.c +++ b/drivers/cam_sensor_module/cam_tpg/tpg_hw/tpg_hw.c @@ -307,7 +307,8 @@ static int tpg_hw_soc_disable(struct tpg_hw *hw) return -EINVAL; } - rc = cam_soc_util_disable_platform_resource(hw->soc_info, true, false); + rc = cam_soc_util_disable_platform_resource(hw->soc_info, CAM_CLK_SW_CLIENT_IDX, true, + false); if (rc) { CAM_ERR(CAM_TPG, "TPG[%d] Disable platform failed %d", hw->hw_idx, rc); @@ -356,7 +357,7 @@ static int tpg_hw_soc_enable( goto end; } - rc = cam_soc_util_enable_platform_resource(hw->soc_info, true, + rc = cam_soc_util_enable_platform_resource(hw->soc_info, CAM_CLK_SW_CLIENT_IDX, true, clk_level, false); if (rc) { CAM_ERR(CAM_TPG, "TPG[%d] enable platform failed", @@ -963,7 +964,8 @@ int tpg_hw_reset(struct tpg_hw *hw) /* disable the hw */ mutex_lock(&hw->mutex); if (hw->state != TPG_HW_STATE_HW_DISABLED) { - rc = cam_soc_util_disable_platform_resource(hw->soc_info, true, false); + rc = cam_soc_util_disable_platform_resource(hw->soc_info, CAM_CLK_SW_CLIENT_IDX, + true, false); if (rc) { CAM_ERR(CAM_TPG, "TPG[%d] Disable platform failed %d", hw->hw_idx, rc); return rc; diff --git a/drivers/cam_utils/cam_common_util.c b/drivers/cam_utils/cam_common_util.c index f21c2c4316..e27e027228 100644 --- a/drivers/cam_utils/cam_common_util.c +++ b/drivers/cam_utils/cam_common_util.c @@ -283,7 +283,8 @@ void *cam_common_user_dump_clock( } addr = (uint64_t *)addr_ptr; - *addr++ = hw_info->soc_info.applied_src_clk_rate; + *addr++ = cam_soc_util_get_applied_src_clk(&hw_info->soc_info, true); + return addr; } diff --git a/drivers/cam_utils/cam_soc_util.c b/drivers/cam_utils/cam_soc_util.c index 74c81dacae..bd49c1df4b 100644 --- a/drivers/cam_utils/cam_soc_util.c +++ b/drivers/cam_utils/cam_soc_util.c @@ -16,6 +16,11 @@ #include "cam_presil_hw_access.h" #include "cam_compat.h" +#if IS_ENABLED(CONFIG_QCOM_CRM) +#include +#include +#endif + #define CAM_TO_MASK(bitn) (1 << (int)(bitn)) #define CAM_IS_BIT_SET(mask, bit) ((mask) & CAM_TO_MASK(bit)) #define CAM_SET_BIT(mask, bit) ((mask) |= CAM_TO_MASK(bit)) @@ -86,6 +91,135 @@ static char supported_clk_info[256]; static DEFINE_MUTEX(wrapper_lock); static LIST_HEAD(wrapper_clk_list); +#define CAM_IS_VALID_CESTA_IDX(idx) ((idx >= 0) && (idx < CAM_CESTA_MAX_CLIENTS)) + +#define CAM_CRM_DEV_IDENTIFIER "cam_crm" + +const struct device *cam_cesta_crm_dev; + +#if IS_ENABLED(CONFIG_QCOM_CRM) +inline int cam_soc_util_cesta_populate_crm_device(void) +{ + cam_cesta_crm_dev = crm_get_device(CAM_CRM_DEV_IDENTIFIER); + if (!cam_cesta_crm_dev) { + CAM_ERR(CAM_UTIL, "Failed to get cesta crm dev for %s", CAM_CRM_DEV_IDENTIFIER); + return -ENODEV; + } + + return 0; +} + +int cam_soc_util_cesta_channel_switch(uint32_t cesta_client_idx, const char *identifier) +{ + int rc = 0; + + if (!cam_cesta_crm_dev) { + CAM_ERR(CAM_UTIL, "camera cesta crm device is null"); + return -EINVAL; + } + + if (!CAM_IS_VALID_CESTA_IDX(cesta_client_idx)) { + CAM_ERR(CAM_UTIL, "Invalid client index for camera cesta idx: %d max: %d", + cesta_client_idx, CAM_CESTA_MAX_CLIENTS); + return -EINVAL; + } + + CAM_DBG(CAM_PERF, "CESTA Channel switch : hw client idx %d identifier=%s", + cesta_client_idx, identifier); + + rc = crm_write_pwr_states(cam_cesta_crm_dev, cesta_client_idx); + if (rc) { + CAM_ERR(CAM_UTIL, + "Failed to trigger cesta channel switch cesta_client_idx: %u rc: %d", + cesta_client_idx, rc); + return rc; + } + + return rc; +} +#else +inline int cam_soc_util_cesta_populate_crm_device(void) +{ + CAM_ERR(CAM_UTIL, "Not supported"); + + return -EOPNOTSUPP; +} + +inline int cam_soc_util_cesta_channel_switch(uint32_t cesta_client_idx, const char *identifier) +{ + CAM_ERR(CAM_UTIL, "Not supported, cesta_client_idx=%d, identifier=%s", + cesta_client_idx, identifier); + + return -EOPNOTSUPP; +} +#endif + +#if IS_ENABLED(CONFIG_QCOM_CRM) && IS_ENABLED(CONFIG_SPECTRA_USE_CLK_CRM_API) +static int cam_soc_util_set_cesta_clk_rate(struct cam_hw_soc_info *soc_info, + uint32_t cesta_client_idx, unsigned long high_val, unsigned long low_val, + unsigned long *applied_high_val, unsigned long *applied_low_val) +{ + int32_t src_clk_idx; + struct clk *clk = NULL; + int rc = 0; + + if (!soc_info || (soc_info->src_clk_idx < 0) || + (soc_info->src_clk_idx >= CAM_SOC_MAX_CLK)) { + CAM_ERR(CAM_UTIL, "Invalid src_clk_idx: %d", + soc_info ? soc_info->src_clk_idx : -1); + return -EINVAL; + } + + if (!CAM_IS_VALID_CESTA_IDX(cesta_client_idx)) { + CAM_ERR(CAM_UTIL, "Invalid client index for camera cesta idx: %d max: %d", + cesta_client_idx, CAM_CESTA_MAX_CLIENTS); + return -EINVAL; + } + + /* Only source clocks are supported by this API to set HW client clock votes */ + src_clk_idx = soc_info->src_clk_idx; + clk = soc_info->clk[src_clk_idx]; + + CAM_DBG(CAM_UTIL, "%s Requested clk rate [high low]: [%llu %llu] cesta_client_idx: %d", + soc_info->clk_name[src_clk_idx], high_val, low_val, cesta_client_idx); + + rc = qcom_clk_crm_set_rate(clk, CRM_HW_DRV, cesta_client_idx, CRM_PWR_STATE1, high_val); + if (rc) { + CAM_ERR(CAM_UTIL, + "Failed in setting cesta high clk rate, client idx: %u pwr state: %u clk_val: %llu rc: %d", + cesta_client_idx, CRM_PWR_STATE1, high_val, rc); + return rc; + } + + rc = qcom_clk_crm_set_rate(clk, CRM_HW_DRV, cesta_client_idx, CRM_PWR_STATE0, low_val); + if (rc) { + CAM_ERR(CAM_UTIL, + "Failed in setting cesta low clk rate, client idx: %u pwr state: %u clk_val: %llu rc: %d", + cesta_client_idx, CRM_PWR_STATE0, low_val, rc); + return rc; + } + + if (applied_high_val) + *applied_high_val = high_val; + + if (applied_low_val) + *applied_low_val = low_val; + + return rc; +} + +#else +static inline int cam_soc_util_set_cesta_clk_rate(struct cam_hw_soc_info *soc_info, + uint32_t cesta_client_idx, unsigned long high_val, unsigned long low_val, + unsigned long *applied_high_val, unsigned long *applied_low_val) +{ + CAM_ERR(CAM_UTIL, "Not supported, dev=%s, cesta_client_idx=%d, high_val=%ld, low_val=%ld", + soc_info->dev_name, cesta_client_idx, high_val, low_val); + + return -EOPNOTSUPP; +} +#endif + #if IS_REACHABLE(CONFIG_MSM_MMRM) bool cam_is_mmrm_supported_on_current_chip(void) { @@ -559,17 +693,7 @@ int cam_soc_util_get_clk_level(struct cam_hw_soc_info *soc_info, return -EINVAL; } -/** - * cam_soc_util_get_string_from_level() - * - * @brief: Returns the string for a given clk level - * - * @level: Clock level - * - * @return: String corresponding to the clk level - */ -static const char *cam_soc_util_get_string_from_level( - enum cam_vote_level level) +const char *cam_soc_util_get_string_from_level(enum cam_vote_level level) { switch (level) { case CAM_SUSPEND_VOTE: @@ -648,32 +772,64 @@ static const struct file_operations cam_soc_util_clk_lvl_options = { .read = cam_soc_util_clk_lvl_options_read, }; -static int cam_soc_util_set_clk_lvl(void *data, u64 val) +static int cam_soc_util_set_clk_lvl_override(void *data, u64 val) { struct cam_hw_soc_info *soc_info = (struct cam_hw_soc_info *)data; - if (val <= CAM_SUSPEND_VOTE || val >= CAM_MAX_VOTE) + if ((val <= CAM_SUSPEND_VOTE) || (val >= CAM_MAX_VOTE)) { + CAM_WARN(CAM_UTIL, "Invalid clk lvl override %d", val); return 0; + } - if (soc_info->clk_level_valid[val] == true) - soc_info->clk_level_override = val; + if (soc_info->clk_level_valid[val]) + soc_info->clk_level_override_high = val; else - soc_info->clk_level_override = 0; + soc_info->clk_level_override_high = 0; return 0; } -static int cam_soc_util_get_clk_lvl(void *data, u64 *val) +static int cam_soc_util_get_clk_lvl_override(void *data, u64 *val) { struct cam_hw_soc_info *soc_info = (struct cam_hw_soc_info *)data; - *val = soc_info->clk_level_override; + *val = soc_info->clk_level_override_high; + + return 0; +} + +static int cam_soc_util_set_clk_lvl_override_low(void *data, u64 val) +{ + struct cam_hw_soc_info *soc_info = (struct cam_hw_soc_info *)data; + + if ((val <= CAM_SUSPEND_VOTE) || (val >= CAM_MAX_VOTE)) { + CAM_WARN(CAM_UTIL, "Invalid clk lvl override %d", val); + return 0; + } + + if (soc_info->clk_level_valid[val]) + soc_info->clk_level_override_low = val; + else + soc_info->clk_level_override_low = 0; + + return 0; +} + +static int cam_soc_util_get_clk_lvl_override_low(void *data, u64 *val) +{ + struct cam_hw_soc_info *soc_info = (struct cam_hw_soc_info *)data; + + *val = soc_info->clk_level_override_low; return 0; } DEFINE_SIMPLE_ATTRIBUTE(cam_soc_util_clk_lvl_control, - cam_soc_util_get_clk_lvl, cam_soc_util_set_clk_lvl, "%08llu"); + cam_soc_util_get_clk_lvl_override, cam_soc_util_set_clk_lvl_override, "%08llu"); + +DEFINE_SIMPLE_ATTRIBUTE(cam_soc_util_clk_lvl_control_low, + cam_soc_util_get_clk_lvl_override_low, cam_soc_util_set_clk_lvl_override_low, "%08llu"); + /** * cam_soc_util_create_clk_lvl_debugfs() @@ -722,6 +878,8 @@ static int cam_soc_util_create_clk_lvl_debugfs(struct cam_hw_soc_info *soc_info) soc_info->dentry, soc_info, &cam_soc_util_clk_lvl_options); dbgfileptr = debugfs_create_file("clk_lvl_control", 0644, soc_info->dentry, soc_info, &cam_soc_util_clk_lvl_control); + dbgfileptr = debugfs_create_file("clk_lvl_control_low", 0644, + soc_info->dentry, soc_info, &cam_soc_util_clk_lvl_control_low); rc = PTR_ERR_OR_ZERO(dbgfileptr); end: return rc; @@ -799,8 +957,9 @@ static int cam_soc_util_get_clk_level_to_apply( } } - CAM_DBG(CAM_UTIL, "Req level %d, Applying %d", - req_level, *apply_level); + CAM_DBG(CAM_UTIL, "Req level %s, Applying %s", + cam_soc_util_get_string_from_level(req_level), + cam_soc_util_get_string_from_level(*apply_level)); return 0; } @@ -961,8 +1120,8 @@ static int cam_soc_util_set_clk_rate(struct cam_hw_soc_info *soc_info, return rc; } -int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, - int64_t clk_rate) +int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, int cesta_client_idx, + unsigned long clk_rate_high, unsigned long clk_rate_low) { int rc = 0; int i = 0; @@ -970,7 +1129,7 @@ int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, int32_t scl_clk_idx; struct clk *clk = NULL; int32_t apply_level; - uint32_t clk_level_override = 0; + uint32_t clk_level_override_high = 0, clk_level_override_low = 0; if (!soc_info || (soc_info->src_clk_idx < 0) || (soc_info->src_clk_idx >= CAM_SOC_MAX_CLK)) { @@ -980,40 +1139,59 @@ int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, } src_clk_idx = soc_info->src_clk_idx; - clk_level_override = soc_info->clk_level_override; - if (clk_level_override && clk_rate) - clk_rate = - soc_info->clk_rate[clk_level_override][src_clk_idx]; + clk_level_override_high = soc_info->clk_level_override_high; + clk_level_override_low = soc_info->clk_level_override_low; + + if (clk_level_override_high && clk_rate_high) + clk_rate_high = soc_info->clk_rate[clk_level_override_high][src_clk_idx]; + + if (clk_level_override_low && clk_rate_low) + clk_rate_low = soc_info->clk_rate[clk_level_override_low][src_clk_idx]; clk = soc_info->clk[src_clk_idx]; - rc = cam_soc_util_get_clk_level(soc_info, clk_rate, src_clk_idx, + rc = cam_soc_util_get_clk_level(soc_info, clk_rate_high, src_clk_idx, &apply_level); if (rc || (apply_level < 0) || (apply_level >= CAM_MAX_VOTE)) { CAM_ERR(CAM_UTIL, "set %s, rate %lld dev_name = %s apply level = %d", - soc_info->clk_name[src_clk_idx], clk_rate, + soc_info->clk_name[src_clk_idx], clk_rate_high, soc_info->dev_name, apply_level); return -EINVAL; } - CAM_DBG(CAM_UTIL, "set %s, rate %lld dev_name = %s apply level = %d", - soc_info->clk_name[src_clk_idx], clk_rate, + CAM_DBG(CAM_UTIL, + "set %s, cesta_client_idx: %d rate [%ld %ld] dev_name = %s apply level = %d", + soc_info->clk_name[src_clk_idx], cesta_client_idx, clk_rate_high, clk_rate_low, soc_info->dev_name, apply_level); - if ((soc_info->cam_cx_ipeak_enable) && (clk_rate >= 0)) { + if ((soc_info->cam_cx_ipeak_enable) && (clk_rate_high > 0)) { cam_cx_ipeak_update_vote_cx_ipeak(soc_info, apply_level); } + if (soc_info->is_clk_drv_en && CAM_IS_VALID_CESTA_IDX(cesta_client_idx)) { + rc = cam_soc_util_set_cesta_clk_rate(soc_info, cesta_client_idx, clk_rate_high, + clk_rate_low, + &soc_info->applied_src_clk_rates.hw_client[cesta_client_idx].high, + &soc_info->applied_src_clk_rates.hw_client[cesta_client_idx].low); + if (rc) { + CAM_ERR(CAM_UTIL, + "Failed in setting cesta clk rates[high low]:[%ld %ld] client_idx:%d rc:%d", + clk_rate_high, clk_rate_low, cesta_client_idx, rc); + return rc; + } + goto end; + } + rc = cam_soc_util_set_clk_rate(soc_info, clk, - soc_info->clk_name[src_clk_idx], clk_rate, + soc_info->clk_name[src_clk_idx], clk_rate_high, CAM_IS_BIT_SET(soc_info->shared_clk_mask, src_clk_idx), true, soc_info->clk_id[src_clk_idx], - &soc_info->applied_src_clk_rate); + &soc_info->applied_src_clk_rates.sw_client); if (rc) { CAM_ERR(CAM_UTIL, "SET_RATE Failed: src clk: %s, rate %lld, dev_name = %s rc: %d", - soc_info->clk_name[src_clk_idx], clk_rate, + soc_info->clk_name[src_clk_idx], clk_rate_high, soc_info->dev_name, rc); return rc; } @@ -1042,6 +1220,7 @@ int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, } } +end: return 0; } @@ -1199,14 +1378,13 @@ error: return rc; } -int cam_soc_util_clk_enable(struct cam_hw_soc_info *soc_info, - bool optional_clk, int32_t clk_idx, int32_t apply_level, - unsigned long *applied_clock_rate) +int cam_soc_util_clk_enable(struct cam_hw_soc_info *soc_info, int cesta_client_idx, + bool optional_clk, int32_t clk_idx, int32_t apply_level) { int rc = 0; struct clk *clk; const char *clk_name; - int32_t clk_rate; + unsigned long clk_rate; uint32_t shared_clk_mask; uint32_t clk_id; bool is_src_clk = false; @@ -1235,12 +1413,37 @@ int cam_soc_util_clk_enable(struct cam_hw_soc_info *soc_info, } if (!clk) return 0; - rc = cam_soc_util_set_clk_rate(soc_info, clk, clk_name, clk_rate, - CAM_IS_BIT_SET(shared_clk_mask, clk_idx), is_src_clk, clk_id, - applied_clock_rate); - if (rc) - return rc; + if (is_src_clk && soc_info->is_clk_drv_en && CAM_IS_VALID_CESTA_IDX(cesta_client_idx)) { + rc = cam_soc_util_set_cesta_clk_rate(soc_info, cesta_client_idx, clk_rate, clk_rate, + &soc_info->applied_src_clk_rates.hw_client[cesta_client_idx].high, + &soc_info->applied_src_clk_rates.hw_client[cesta_client_idx].low); + if (rc) { + CAM_ERR(CAM_UTIL, + "[%s] Failed in setting cesta clk rates[high low]:[%ld %ld] client_idx:%d rc:%d", + soc_info->dev_name, clk_rate, clk_rate, cesta_client_idx, rc); + return rc; + } + + rc = cam_soc_util_cesta_channel_switch(cesta_client_idx, soc_info->dev_name); + if (rc) { + CAM_ERR(CAM_UTIL, + "[%s] Failed to apply power states for cesta client:%d rc:%d", + soc_info->dev_name, cesta_client_idx, rc); + return rc; + } + } else { + rc = cam_soc_util_set_clk_rate(soc_info, clk, clk_name, clk_rate, + CAM_IS_BIT_SET(shared_clk_mask, clk_idx), is_src_clk, clk_id, + &soc_info->applied_src_clk_rates.sw_client); + if (rc) { + CAM_ERR(CAM_UTIL, "[%s] Failed in setting clk rate %ld rc:%d", + soc_info->dev_name, clk_rate, rc); + return rc; + } + } + + CAM_DBG(CAM_UTIL, "[%s] : clk enable %s", soc_info->dev_name, clk_name); rc = clk_prepare_enable(clk); if (rc) { CAM_ERR(CAM_UTIL, "enable failed for %s: rc(%d)", clk_name, rc); @@ -1250,10 +1453,10 @@ int cam_soc_util_clk_enable(struct cam_hw_soc_info *soc_info, return rc; } -int cam_soc_util_clk_disable(struct cam_hw_soc_info *soc_info, +int cam_soc_util_clk_disable(struct cam_hw_soc_info *soc_info, int cesta_client_idx, bool optional_clk, int32_t clk_idx) { - + int rc = 0; struct clk *clk; const char *clk_name; uint32_t shared_clk_mask; @@ -1279,21 +1482,43 @@ int cam_soc_util_clk_disable(struct cam_hw_soc_info *soc_info, CAM_DBG(CAM_UTIL, "disable %s", clk_name); if (!clk) return 0; + clk_disable_unprepare(clk); - if (CAM_IS_BIT_SET(shared_clk_mask, clk_idx)) { - CAM_DBG(CAM_UTIL, - "Dev %s clk %s Disabling Shared clk, set 0 rate", - soc_info->dev_name, clk_name); - cam_soc_util_clk_wrapper_set_clk_rate(clk_id, soc_info, clk, 0); - } else if (soc_info->mmrm_handle && (!skip_mmrm_set_rate) && - (soc_info->src_clk_idx == clk_idx)) { - CAM_DBG(CAM_UTIL, - "Dev %s Disabling %s clk, set 0 rate", soc_info->dev_name, clk_name); - cam_soc_util_set_rate_through_mmrm( - soc_info->mmrm_handle, - soc_info->is_nrt_dev, - 0, 0, 1); + if ((clk_idx == soc_info->src_clk_idx) && soc_info->is_clk_drv_en && + CAM_IS_VALID_CESTA_IDX(cesta_client_idx)) { + rc = cam_soc_util_set_cesta_clk_rate(soc_info, cesta_client_idx, 0, 0, + &soc_info->applied_src_clk_rates.hw_client[cesta_client_idx].high, + &soc_info->applied_src_clk_rates.hw_client[cesta_client_idx].low); + if (rc) { + CAM_ERR(CAM_UTIL, + "Failed in setting cesta clk rates[high low]:[0 0] client_idx:%d rc:%d", + cesta_client_idx, rc); + return rc; + } + + rc = cam_soc_util_cesta_channel_switch(cesta_client_idx, soc_info->dev_name); + if (rc) { + CAM_ERR(CAM_CSIPHY, + "Failed to apply power states for cesta_client_idx:%d rc:%d", + cesta_client_idx, rc); + return rc; + } + } else { + if (CAM_IS_BIT_SET(shared_clk_mask, clk_idx)) { + CAM_DBG(CAM_UTIL, + "Dev %s clk %s Disabling Shared clk, set 0 rate", + soc_info->dev_name, clk_name); + cam_soc_util_clk_wrapper_set_clk_rate(clk_id, soc_info, clk, 0); + } else if (soc_info->mmrm_handle && (!skip_mmrm_set_rate) && + (soc_info->src_clk_idx == clk_idx)) { + CAM_DBG(CAM_UTIL, "Dev %s Disabling %s clk, set 0 rate", + soc_info->dev_name, clk_name); + cam_soc_util_set_rate_through_mmrm( + soc_info->mmrm_handle, + soc_info->is_nrt_dev, + 0, 0, 1); + } } return 0; @@ -1306,16 +1531,16 @@ int cam_soc_util_clk_disable(struct cam_hw_soc_info *soc_info, * in soc_info * * @soc_info: Device soc struct to be populated + * @cesta_client_idx: CESTA Client idx for hw client based src clocks * @clk_level: Clk level to apply while enabling * * @return: success or failure */ int cam_soc_util_clk_enable_default(struct cam_hw_soc_info *soc_info, - enum cam_vote_level clk_level) + int cesta_client_idx, enum cam_vote_level clk_level) { int i, rc = 0; enum cam_vote_level apply_level; - unsigned long applied_clk_rate; if ((soc_info->num_clk == 0) || (soc_info->num_clk >= CAM_SOC_MAX_CLK)) { @@ -1326,29 +1551,35 @@ int cam_soc_util_clk_enable_default(struct cam_hw_soc_info *soc_info, rc = cam_soc_util_get_clk_level_to_apply(soc_info, clk_level, &apply_level); - if (rc) + if (rc) { + CAM_ERR(CAM_UTIL, "[%s] : failed to get level clk_level=%d, rc=%d", + soc_info->dev_name, clk_level, rc); return rc; + } if (soc_info->cam_cx_ipeak_enable) cam_cx_ipeak_update_vote_cx_ipeak(soc_info, apply_level); + CAM_DBG(CAM_UTIL, "Dev[%s] : cesta client %d, request level %s, apply level %s", + soc_info->dev_name, cesta_client_idx, + cam_soc_util_get_string_from_level(clk_level), + cam_soc_util_get_string_from_level(apply_level)); + + memset(&soc_info->applied_src_clk_rates, 0, sizeof(struct cam_soc_util_clk_rates)); + for (i = 0; i < soc_info->num_clk; i++) { - rc = cam_soc_util_clk_enable(soc_info, false, i, apply_level, - &applied_clk_rate); - if (rc) + rc = cam_soc_util_clk_enable(soc_info, cesta_client_idx, false, i, apply_level); + if (rc) { + CAM_ERR(CAM_UTIL, + "[%s] : failed to enable clk apply_level=%d, rc=%d, cesta_client_idx=%d", + soc_info->dev_name, apply_level, rc, cesta_client_idx); goto clk_disable; - - if (i == soc_info->src_clk_idx) - soc_info->applied_src_clk_rate = applied_clk_rate; - - if (soc_info->cam_cx_ipeak_enable) { - CAM_DBG(CAM_UTIL, - "dev name = %s clk name = %s idx = %d\n" - "apply_level = %d clc idx = %d", - soc_info->dev_name, soc_info->clk_name[i], i, - apply_level, i); } + if (soc_info->cam_cx_ipeak_enable) + CAM_DBG(CAM_UTIL, + "dev name = %s clk name = %s idx = %d apply_level = %d clc idx = %d", + soc_info->dev_name, soc_info->clk_name[i], i, apply_level, i); } return rc; @@ -1357,7 +1588,7 @@ clk_disable: if (soc_info->cam_cx_ipeak_enable) cam_cx_ipeak_update_vote_cx_ipeak(soc_info, 0); for (i--; i >= 0; i--) { - cam_soc_util_clk_disable(soc_info, false, i); + cam_soc_util_clk_disable(soc_info, cesta_client_idx, false, i); } return rc; @@ -1370,10 +1601,12 @@ clk_disable: * in soc_info * * @soc_info: device soc struct to be populated + * @cesta_client_idx: CESTA Client idx for hw client based src clocks * * @return: success or failure */ -void cam_soc_util_clk_disable_default(struct cam_hw_soc_info *soc_info) +void cam_soc_util_clk_disable_default(struct cam_hw_soc_info *soc_info, + int cesta_client_idx) { int i; @@ -1383,7 +1616,7 @@ void cam_soc_util_clk_disable_default(struct cam_hw_soc_info *soc_info) if (soc_info->cam_cx_ipeak_enable) cam_cx_ipeak_unvote_cx_ipeak(soc_info); for (i = soc_info->num_clk - 1; i >= 0; i--) - cam_soc_util_clk_disable(soc_info, false, i); + cam_soc_util_clk_disable(soc_info, cesta_client_idx, false, i); } /** @@ -1650,26 +1883,40 @@ end: } int cam_soc_util_set_clk_rate_level(struct cam_hw_soc_info *soc_info, - enum cam_vote_level clk_level, bool do_not_set_src_clk) + int cesta_client_idx, enum cam_vote_level clk_level_high, + enum cam_vote_level clk_level_low, bool do_not_set_src_clk) { int i, rc = 0; - enum cam_vote_level apply_level; + enum cam_vote_level apply_level_high; + enum cam_vote_level apply_level_low = CAM_LOWSVS_VOTE; unsigned long applied_clk_rate; if ((soc_info->num_clk == 0) || (soc_info->num_clk >= CAM_SOC_MAX_CLK)) { - CAM_ERR(CAM_UTIL, "Invalid number of clock %d", - soc_info->num_clk); + CAM_ERR(CAM_UTIL, "Invalid number of clock %d", soc_info->num_clk); return -EINVAL; } - rc = cam_soc_util_get_clk_level_to_apply(soc_info, clk_level, - &apply_level); - if (rc) + rc = cam_soc_util_get_clk_level_to_apply(soc_info, clk_level_high, + &apply_level_high); + if (rc) { + CAM_ERR(CAM_UTIL, "[%s] : failed to get level clk_level_high=%d, rc=%d", + soc_info->dev_name, clk_level_high, rc); return rc; + } + + if (soc_info->is_clk_drv_en && CAM_IS_VALID_CESTA_IDX(cesta_client_idx)) { + rc = cam_soc_util_get_clk_level_to_apply(soc_info, clk_level_low, + &apply_level_low); + if (rc) { + CAM_ERR(CAM_UTIL, "[%s] : failed to get level clk_level_low=%d, rc=%d", + soc_info->dev_name, clk_level_low, rc); + return rc; + } + } if (soc_info->cam_cx_ipeak_enable) - cam_cx_ipeak_update_vote_cx_ipeak(soc_info, apply_level); + cam_cx_ipeak_update_vote_cx_ipeak(soc_info, apply_level_high); for (i = 0; i < soc_info->num_clk; i++) { if (do_not_set_src_clk && (i == soc_info->src_clk_idx)) { @@ -1678,30 +1925,47 @@ int cam_soc_util_set_clk_rate_level(struct cam_hw_soc_info *soc_info, continue; } - CAM_DBG(CAM_UTIL, "Set rate for clk %s rate %d", - soc_info->clk_name[i], - soc_info->clk_rate[apply_level][i]); + if (soc_info->is_clk_drv_en && CAM_IS_VALID_CESTA_IDX(cesta_client_idx) && + (i == soc_info->src_clk_idx)) { + rc = cam_soc_util_set_cesta_clk_rate(soc_info, cesta_client_idx, + soc_info->clk_rate[apply_level_high][i], + soc_info->clk_rate[apply_level_low][i], + &soc_info->applied_src_clk_rates.hw_client[cesta_client_idx].high, + &soc_info->applied_src_clk_rates.hw_client[cesta_client_idx].low); + if (rc) { + CAM_ERR(CAM_UTIL, + "Failed to set the req clk level[high low]: [%s %s] cesta_client_idx: %d", + cam_soc_util_get_string_from_level(apply_level_high), + cam_soc_util_get_string_from_level(apply_level_low), + cesta_client_idx); + break; + } + + continue; + } + + CAM_DBG(CAM_UTIL, "Set rate for clk %s rate %d", soc_info->clk_name[i], + soc_info->clk_rate[apply_level_high][i]); rc = cam_soc_util_set_clk_rate(soc_info, soc_info->clk[i], soc_info->clk_name[i], - soc_info->clk_rate[apply_level][i], + soc_info->clk_rate[apply_level_high][i], CAM_IS_BIT_SET(soc_info->shared_clk_mask, i), (i == soc_info->src_clk_idx) ? true : false, soc_info->clk_id[i], &applied_clk_rate); if (rc < 0) { CAM_DBG(CAM_UTIL, - "dev name = %s clk_name = %s idx = %d\n" - "apply_level = %d", + "dev name = %s clk_name = %s idx = %d apply_level = %s", soc_info->dev_name, soc_info->clk_name[i], - i, apply_level); + i, cam_soc_util_get_string_from_level(apply_level_high)); if (soc_info->cam_cx_ipeak_enable) cam_cx_ipeak_update_vote_cx_ipeak(soc_info, 0); break; } if (i == soc_info->src_clk_idx) - soc_info->applied_src_clk_rate = applied_clk_rate; + soc_info->applied_src_clk_rates.sw_client = applied_clk_rate; } return rc; @@ -2182,8 +2446,8 @@ int cam_soc_util_regulator_enable(struct regulator *rgltr, } if (regulator_count_voltages(rgltr) > 0) { - CAM_DBG(CAM_UTIL, "voltage min=%d, max=%d", - rgltr_min_volt, rgltr_max_volt); + CAM_DBG(CAM_UTIL, "[%s] voltage min=%d, max=%d", + rgltr_name, rgltr_min_volt, rgltr_max_volt); rc = regulator_set_voltage( rgltr, rgltr_min_volt, rgltr_max_volt); @@ -2410,6 +2674,8 @@ static int cam_soc_util_regulator_enable_default( } for (j = 0; j < num_rgltr; j++) { + CAM_DBG(CAM_UTIL, "[%s] : start regulator %s enable, rgltr_ctrl_support %d", + soc_info->dev_name, soc_info->rgltr_name[j], soc_info->rgltr_ctrl_support); if (soc_info->rgltr_ctrl_support == true) { rc = cam_soc_util_regulator_enable(soc_info->rgltr[j], soc_info->rgltr_name[j], @@ -2851,7 +3117,8 @@ int cam_soc_util_release_platform_resource(struct cam_hw_soc_info *soc_info) } int cam_soc_util_enable_platform_resource(struct cam_hw_soc_info *soc_info, - bool enable_clocks, enum cam_vote_level clk_level, bool enable_irq) + int cesta_client_idx, bool enable_clocks, enum cam_vote_level clk_level, + bool enable_irq) { int rc = 0; @@ -2865,7 +3132,7 @@ int cam_soc_util_enable_platform_resource(struct cam_hw_soc_info *soc_info, } if (enable_clocks) { - rc = cam_soc_util_clk_enable_default(soc_info, clk_level); + rc = cam_soc_util_clk_enable_default(soc_info, cesta_client_idx, clk_level); if (rc) goto disable_regulator; } @@ -2880,7 +3147,7 @@ int cam_soc_util_enable_platform_resource(struct cam_hw_soc_info *soc_info, disable_clk: if (enable_clocks) - cam_soc_util_clk_disable_default(soc_info); + cam_soc_util_clk_disable_default(soc_info, cesta_client_idx); disable_regulator: cam_soc_util_regulator_disable_default(soc_info); @@ -2889,7 +3156,7 @@ disable_regulator: } int cam_soc_util_disable_platform_resource(struct cam_hw_soc_info *soc_info, - bool disable_clocks, bool disable_irq) + int cesta_client_idx, bool disable_clocks, bool disable_irq) { int rc = 0; @@ -2900,7 +3167,7 @@ int cam_soc_util_disable_platform_resource(struct cam_hw_soc_info *soc_info, rc |= cam_soc_util_irq_disable(soc_info); if (disable_clocks) - cam_soc_util_clk_disable_default(soc_info); + cam_soc_util_clk_disable_default(soc_info, cesta_client_idx); cam_soc_util_regulator_disable_default(soc_info); @@ -3649,6 +3916,33 @@ int cam_soc_util_print_clk_freq(struct cam_hw_soc_info *soc_info) return 0; } +inline unsigned long cam_soc_util_get_applied_src_clk( + struct cam_hw_soc_info *soc_info, bool is_max) +{ + unsigned long clk_rate; + + /* + * For CRMC type, exa - ife, csid, cphy + * final clk = max(hw_client_0, hw_client_1, hw_client_2, sw_client) + * For CRMB type, exa - camnoc axi + * final clk = max(hw_client_0 + hw_client_1 + hw_client_2, sw_client) + */ + + if (is_max) { + clk_rate = max(soc_info->applied_src_clk_rates.hw_client[0].high, + soc_info->applied_src_clk_rates.hw_client[1].high); + clk_rate = max(clk_rate, soc_info->applied_src_clk_rates.hw_client[2].high); + clk_rate = max(clk_rate, soc_info->applied_src_clk_rates.sw_client); + } else { + clk_rate = max((soc_info->applied_src_clk_rates.hw_client[0].high + + soc_info->applied_src_clk_rates.hw_client[1].high + + soc_info->applied_src_clk_rates.hw_client[2].high), + soc_info->applied_src_clk_rates.sw_client); + } + + return clk_rate; +} + int cam_soc_util_regulators_enabled(struct cam_hw_soc_info *soc_info) { int j = 0, rc = 0; diff --git a/drivers/cam_utils/cam_soc_util.h b/drivers/cam_utils/cam_soc_util.h index dfe9c4a395..bf36768a8c 100644 --- a/drivers/cam_utils/cam_soc_util.h +++ b/drivers/cam_utils/cam_soc_util.h @@ -57,6 +57,9 @@ /* Maximum length of tag while dumping */ #define CAM_SOC_HW_DUMP_TAG_MAX_LEN 32 +/* Client index to be used to vote clk frequency through sw client */ +#define CAM_CLK_SW_CLIENT_IDX -1 + /** * enum cam_vote_level - Enum for voting level * @@ -86,6 +89,30 @@ enum cam_vote_level { #define CAM_SOC_PINCTRL_STATE_SLEEP "cam_suspend" #define CAM_SOC_PINCTRL_STATE_DEFAULT "cam_default" +#define CAM_CESTA_MAX_CLIENTS 3 + +/** + * struct cam_soc_util_hw_client_clk_rates: Information about HW client clock vote + * + * @high: HW client clock vote high value + * @low: HW client clock vote low value + **/ +struct cam_soc_util_hw_client_clk_rates { + unsigned long high; + unsigned long low; +}; + +/** + * struct cam_soc_util_clk_rates: Information about clock vote for SW and HW clients + * + * @sw_client: SW client clock vote + * @hw_client: HW client clock vote + **/ +struct cam_soc_util_clk_rates { + unsigned long sw_client; + struct cam_soc_util_hw_client_clk_rates hw_client[CAM_CESTA_MAX_CLIENTS]; +}; + /** * struct cam_soc_reg_map: Information about the mapped register space * @@ -187,7 +214,7 @@ struct cam_soc_gpio_data { * through camera clk wrapper for aggregation. * @prev_clk_level Last vote level * @src_clk_idx: Source clock index that is rate-controllable - * @applied_src_clk_rate Current clock rate of the core source clk + * @applied_src_clk_rates: Applied src clock rates for SW and HW client * @clk_level_valid: Indicates whether corresponding level is valid * @lowest_clk_level: Lowest clock level that has valid freq info * @scl_clk_count: Number of scalable clocks present @@ -201,9 +228,13 @@ struct cam_soc_gpio_data { * through camera clk wrapper for aggregation. * @gpio_data: Pointer to gpio info * @mmrm_handle: MMRM Client handle for src clock + * @is_clk_drv_en: If clock drv is enabled in hw * @pinctrl_info: Pointer to pinctrl info * @dentry: Debugfs entry - * @clk_level_override: Clk level set from debugfs + * @clk_level_override_high:Clk level set from debugfs. When cesta is enabled, used to override + * high clk value + * @clk_level_override_high:Low clk level set from debugfs when cesta is enabled, used to override + * low clk value * @clk_control: Enable/disable clk rate control through debugfs * @cam_cx_ipeak_enable cx-ipeak enable/disable flag * @cam_cx_ipeak_bit cx-ipeak mask for driver @@ -250,7 +281,7 @@ struct cam_hw_soc_info { uint32_t shared_clk_mask; int32_t prev_clk_level; int32_t src_clk_idx; - unsigned long applied_src_clk_rate; + struct cam_soc_util_clk_rates applied_src_clk_rates; bool clk_level_valid[CAM_MAX_VOTE]; uint32_t lowest_clk_level; int32_t scl_clk_count; @@ -263,11 +294,14 @@ struct cam_hw_soc_info { void *mmrm_handle; + bool is_clk_drv_en; + struct cam_soc_gpio_data *gpio_data; struct cam_soc_pinctrl_info pinctrl_info; struct dentry *dentry; - uint32_t clk_level_override; + uint32_t clk_level_override_high; + uint32_t clk_level_override_low; bool clk_control_enable; bool cam_cx_ipeak_enable; int32_t cam_cx_ipeak_bit; @@ -410,6 +444,7 @@ int cam_soc_util_release_platform_resource(struct cam_hw_soc_info *soc_info); * @brief: Enable regulator, irq resources * * @soc_info: Device soc information + * @cesta_client_idx: CESTA Client idx for hw client based src clocks * @enable_clocks: Boolean flag: * TRUE: Enable all clocks in soc_info Now. * False: Don't enable clocks Now. Driver will @@ -425,7 +460,8 @@ int cam_soc_util_release_platform_resource(struct cam_hw_soc_info *soc_info); * @return: Success or failure */ int cam_soc_util_enable_platform_resource(struct cam_hw_soc_info *soc_info, - bool enable_clocks, enum cam_vote_level clk_level, bool enable_irq); + int cesta_client_idx, bool enable_clocks, enum cam_vote_level clk_level, + bool enable_irq); /** * cam_soc_util_disable_platform_resource() @@ -433,6 +469,7 @@ int cam_soc_util_enable_platform_resource(struct cam_hw_soc_info *soc_info, * @brief: Disable regulator, irq resources * * @soc_info: Device soc information + * @cesta_client_idx: CESTA Client idx for hw client based src clocks * @disable_irq: Boolean flag: * TRUE: Disable IRQ in soc_info Now. * False: Don't disable IRQ Now. Driver will @@ -441,7 +478,7 @@ int cam_soc_util_enable_platform_resource(struct cam_hw_soc_info *soc_info, * @return: Success or failure */ int cam_soc_util_disable_platform_resource(struct cam_hw_soc_info *soc_info, - bool disable_clocks, bool disable_irq); + int cesta_client_idx, bool disable_clocks, bool disable_irq); /** * cam_soc_util_get_clk_round_rate() @@ -461,15 +498,21 @@ long cam_soc_util_get_clk_round_rate(struct cam_hw_soc_info *soc_info, /** * cam_soc_util_set_src_clk_rate() * - * @brief: Set the rate on the source clock. + * @brief: Set the rate on the source clock for sw or hw clients. Requires a valid + * CESTA client idx for hw client voting. * * @soc_info: Device soc information - * @clk_rate: Clock rate associated with the src clk + * @cesta_client_idx: CESTA client idx if src clock belongs to cesta client, otherwise -1 + * @clk_rate_high: High clock rate associated with the src clk, applies to sw client vote + * if not cesta client + * @clk_rate_low: Low clock rate associated with the src clk, only applies to cesta based + * hw client vote * * @return: success or failure */ -int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, - int64_t clk_rate); +int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, int cesta_client_idx, + unsigned long clk_rate_high, unsigned long clk_rate_low); + /** * cam_soc_util_get_option_clk_by_name() @@ -505,6 +548,7 @@ int cam_soc_util_put_optional_clk(struct cam_hw_soc_info *soc_info, * @brief: Enable clock specified in params * * @soc_info: Device soc information + * @cesta_client_idx: CESTA Client idx for hw client based src clocks * @optional_clk: Whether to set optional clk or normal clk with * the idx given * @clk_idx: Clock index to set @@ -513,13 +557,11 @@ int cam_soc_util_put_optional_clk(struct cam_hw_soc_info *soc_info, * any other value indicate level for normal clocks * For optional clocks any other value means the rate saved * in soc_info - * @applied_clock_rate Final Clock rate applied to the clk * * @return: Success or failure */ -int cam_soc_util_clk_enable(struct cam_hw_soc_info *soc_info, - bool optional_clk, int32_t clk_idx, int32_t apply_level, - unsigned long *applied_clock_rate); +int cam_soc_util_clk_enable(struct cam_hw_soc_info *soc_info, int cesta_client_idx, + bool optional_clk, int32_t clk_idx, int32_t apply_level); /** * cam_soc_util_set_clk_rate_level() @@ -529,13 +571,16 @@ int cam_soc_util_clk_enable(struct cam_hw_soc_info *soc_info, * the clocks listed in DT based on their values. * * @soc_info: Device soc information - * @clk_level: Clock level number to set + * @cesta_client_idx: CESTA client idx for HW client based src clocks + * @clk_level_high: Clock level number to set, high value if crm based src clock + * @clk_level_low: Low clock level value if crm based src clock * @do_not_set_src_clk: If true, set clock rates except the src clk * * @return: Success or failure */ int cam_soc_util_set_clk_rate_level(struct cam_hw_soc_info *soc_info, - enum cam_vote_level clk_level, bool do_not_set_src_clk); + int cesta_client_idx, enum cam_vote_level clk_level_high, + enum cam_vote_level clk_level_low, bool do_not_set_src_clk); /** * cam_soc_util_clk_disable() @@ -543,13 +588,14 @@ int cam_soc_util_set_clk_rate_level(struct cam_hw_soc_info *soc_info, * @brief: Disable clock specified in params * * @soc_info: Device soc information + * @cesta_client_idx: CESTA Client idx for hw client based src clocks * @optional_clk: Whether to set optional clk or normal clk with * the idx given * @clk_idx: Clock index to disable * * @return: Success or failure */ -int cam_soc_util_clk_disable(struct cam_hw_soc_info *soc_info, +int cam_soc_util_clk_disable(struct cam_hw_soc_info *soc_info, int cesta_client_idx, bool optional_clk, int32_t clk_idx); /** @@ -716,9 +762,10 @@ static inline uint32_t cam_soc_util_r_mb(struct cam_hw_soc_info *soc_info, int cam_soc_util_reg_dump(struct cam_hw_soc_info *soc_info, uint32_t base_index, uint32_t offset, int size); -void cam_soc_util_clk_disable_default(struct cam_hw_soc_info *soc_info); +void cam_soc_util_clk_disable_default(struct cam_hw_soc_info *soc_info, + int cesta_client_idx); -int cam_soc_util_clk_enable_default(struct cam_hw_soc_info *soc_info, +int cam_soc_util_clk_enable_default(struct cam_hw_soc_info *soc_info, int cesta_client_idx, enum cam_vote_level clk_level); int cam_soc_util_get_clk_level(struct cam_hw_soc_info *soc_info, @@ -788,4 +835,50 @@ int cam_soc_util_select_pinctrl_state( */ int cam_soc_util_regulators_enabled(struct cam_hw_soc_info *soc_info); +/** + * cam_soc_util_cesta_populate_crm_device() + * + * @brief: This function populates the camera cesta crm device in soc util + * + * @return: success or failure + */ +inline int cam_soc_util_cesta_populate_crm_device(void); + +/** + * cam_soc_util_cesta_channel_switch() + * + * @brief: This function triggers the application of power states to crm + * and channel switch operation in hw. Also, for camera it applies + * the high vote of the active channel + * @cesta_client_idx: CESTA client index through which power states need to be applied + * @identifier: Identifying the caller triggerring channel switch + * + * @return: success or failure + */ +int cam_soc_util_cesta_channel_switch(uint32_t cesta_client_idx, const char *identifier); + +/** + * cam_soc_util_get_applied_src_clk() + * + * @brief: Inline function to get applied src clk rate. + + * @soc_info: Device soc struct to be populated + * @is_max: Is max of all hw clients if cesta is enabled + * + * @return: success or failure + */ +inline unsigned long cam_soc_util_get_applied_src_clk( + struct cam_hw_soc_info *soc_info, bool is_max); + +/** + * cam_soc_util_get_string_from_level() + * + * @brief: Returns the string for a given clk level + * + * @level: Clock level + * + * @return: String corresponding to the clk level + */ +const char *cam_soc_util_get_string_from_level(enum cam_vote_level level); + #endif /* _CAM_SOC_UTIL_H_ */