Loading Documentation/devicetree/bindings/media/video/msm-cam-cpas.txt +20 −0 Original line number Diff line number Diff line Loading @@ -108,6 +108,23 @@ First Level Node - CAM CPAS device Definition: List of strings corresponds clock-rates levels. Supported strings: minsvs, lowsvs, svs, svs_l1, nominal, turbo. - control-camnoc-axi-clk Usage: optional Value type: <empty> Definition: Bool property specifying whether to control camnoc axi clock from cpas driver. - camnoc-bus-width Usage: required if control-camnoc-axi-clk is enabled Value type: <u32> Definition: camnoc bus width. - camnoc-axi-clk-bw-margin-perc Usage: optional Value type: <u32> Definition: Percentage value to be added to camnoc bw while calculating camnoc axi clock frequency. - qcom,msm-bus,name - qcom,msm-bus,num-cases - qcom,msm-bus,num-paths Loading Loading @@ -211,6 +228,9 @@ Example: src-clock-name = "slow_ahb_clk_src"; clock-rates = <0 0 0 0 80000000 0>; clock-cntl-level = "turbo"; control-camnoc-axi-clk; camnoc-bus-width = <32>; camnoc-axi-clk-bw-margin-perc = <10>; qcom,msm-bus,name = "cam_ahb"; qcom,msm-bus,num-cases = <4>; qcom,msm-bus,num-paths = <1>; Loading arch/arm64/boot/dts/qcom/sdm670-camera.dtsi +1 −3 Original line number Diff line number Diff line Loading @@ -234,9 +234,7 @@ msm_cam_smmu_lrme { compatible = "qcom,msm-cam-smmu-cb"; iommus = <&apps_smmu 0x1038 0x0>, <&apps_smmu 0x1058 0x0>, <&apps_smmu 0x1039 0x0>, <&apps_smmu 0x1059 0x0>; <&apps_smmu 0x1058 0x0>; label = "lrme"; lrme_iova_mem_map: iova-mem-map { iova-mem-region-shared { Loading arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi +2 −4 Original line number Diff line number Diff line /* * Copyright (c) 2017, The Linux Foundation. All rights reserved. * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -161,9 +161,7 @@ msm_cam_smmu_lrme { compatible = "qcom,msm-cam-smmu-cb"; iommus = <&apps_smmu 0x1038 0x0>, <&apps_smmu 0x1058 0x0>, <&apps_smmu 0x1039 0x0>, <&apps_smmu 0x1059 0x0>; <&apps_smmu 0x1058 0x0>; label = "lrme"; lrme_iova_mem_map: iova-mem-map { iova-mem-region-shared { Loading drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c +81 −8 Original line number Diff line number Diff line Loading @@ -543,10 +543,71 @@ static int cam_cpas_hw_reg_read(struct cam_hw_info *cpas_hw, return rc; } static int cam_cpas_util_set_camnoc_axi_clk_rate( struct cam_hw_info *cpas_hw) { 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 rc = 0; 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; struct cam_cpas_axi_port *curr_axi_port = NULL; struct cam_cpas_axi_port *temp_axi_port = NULL; uint64_t required_camnoc_bw = 0; int32_t clk_rate = 0; list_for_each_entry_safe(curr_axi_port, temp_axi_port, &cpas_core->axi_ports_list_head, sibling_port) { if (curr_axi_port->consolidated_axi_vote.uncompressed_bw > required_camnoc_bw) required_camnoc_bw = curr_axi_port-> consolidated_axi_vote.uncompressed_bw; CAM_DBG(CAM_CPAS, "[%s] : curr=%llu, overal=%llu", curr_axi_port->axi_port_name, curr_axi_port->consolidated_axi_vote. uncompressed_bw, required_camnoc_bw); } required_camnoc_bw += (required_camnoc_bw * soc_private->camnoc_axi_clk_bw_margin) / 100; if ((required_camnoc_bw > 0) && (required_camnoc_bw < CAM_CPAS_AXI_MIN_CAMNOC_IB_BW)) required_camnoc_bw = CAM_CPAS_AXI_MIN_CAMNOC_IB_BW; clk_rate = required_camnoc_bw / soc_private->camnoc_bus_width; CAM_DBG(CAM_CPAS, "Setting camnoc axi clk rate : %llu %d", required_camnoc_bw, clk_rate); rc = cam_soc_util_set_clk_rate( soc_info->clk[soc_info->src_clk_idx], soc_info->clk_name[soc_info->src_clk_idx], clk_rate); if (!rc) CAM_ERR(CAM_CPAS, "Failed in setting camnoc axi clk %llu %d %d", required_camnoc_bw, clk_rate, rc); } return rc; } static int cam_cpas_util_apply_client_axi_vote( struct cam_cpas *cpas_core, struct cam_cpas_private_soc *soc_private, struct cam_cpas_client *cpas_client, struct cam_axi_vote *axi_vote) struct cam_hw_info *cpas_hw, struct cam_cpas_client *cpas_client, struct cam_axi_vote *axi_vote) { struct cam_cpas_private_soc *soc_private = (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; struct cam_cpas_client *curr_client; struct cam_cpas_client *temp_client; struct cam_axi_vote req_axi_vote = *axi_vote; Loading Loading @@ -587,6 +648,9 @@ static int cam_cpas_util_apply_client_axi_vote( if ((!soc_private->axi_camnoc_based) && (mnoc_bw < camnoc_bw)) mnoc_bw = camnoc_bw; axi_port->consolidated_axi_vote.compressed_bw = mnoc_bw; axi_port->consolidated_axi_vote.uncompressed_bw = camnoc_bw; CAM_DBG(CAM_CPAS, "axi[(%d, %d),(%d, %d)] : camnoc_bw[%llu], mnoc_bw[%llu]", axi_port->mnoc_bus.src, axi_port->mnoc_bus.dst, Loading @@ -613,6 +677,14 @@ static int cam_cpas_util_apply_client_axi_vote( } } mutex_unlock(&axi_port->lock); 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; unlock_axi_port: mutex_unlock(&axi_port->lock); return rc; Loading Loading @@ -645,6 +717,7 @@ static int cam_cpas_hw_update_axi_vote(struct cam_hw_info *cpas_hw, if (!CAM_CPAS_CLIENT_VALID(client_indx)) return -EINVAL; mutex_lock(&cpas_hw->hw_mutex); mutex_lock(&cpas_core->client_mutex[client_indx]); if (!CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) { Loading @@ -658,12 +731,12 @@ static int cam_cpas_hw_update_axi_vote(struct cam_hw_info *cpas_hw, client_indx, axi_vote.compressed_bw, axi_vote.uncompressed_bw); rc = cam_cpas_util_apply_client_axi_vote(cpas_core, cpas_hw->soc_info.soc_private, rc = cam_cpas_util_apply_client_axi_vote(cpas_hw, cpas_core->cpas_client[client_indx], &axi_vote); unlock_client: mutex_unlock(&cpas_core->client_mutex[client_indx]); mutex_unlock(&cpas_hw->hw_mutex); return rc; } Loading Loading @@ -897,8 +970,8 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, "AXI client[%d] compressed_bw[%llu], uncompressed_bw[%llu]", client_indx, axi_vote->compressed_bw, axi_vote->uncompressed_bw); rc = cam_cpas_util_apply_client_axi_vote(cpas_core, cpas_hw->soc_info.soc_private, cpas_client, axi_vote); rc = cam_cpas_util_apply_client_axi_vote(cpas_hw, cpas_client, axi_vote); if (rc) goto done; Loading Loading @@ -1040,8 +1113,8 @@ static int cam_cpas_hw_stop(void *hw_priv, void *stop_args, axi_vote.uncompressed_bw = 0; axi_vote.compressed_bw = 0; rc = cam_cpas_util_apply_client_axi_vote(cpas_core, cpas_hw->soc_info.soc_private, cpas_client, &axi_vote); rc = cam_cpas_util_apply_client_axi_vote(cpas_hw, cpas_client, &axi_vote); done: mutex_unlock(&cpas_core->client_mutex[client_indx]); Loading drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.h +2 −0 Original line number Diff line number Diff line Loading @@ -145,6 +145,7 @@ struct cam_cpas_bus_client { * @axi_port_node: Node representing this AXI Port * @axi_port_mnoc_node: Node representing mnoc in this AXI Port * @axi_port_camnoc_node: Node representing camnoc in this AXI Port * @consolidated_axi_vote: Consolidated axi bw values for this AXI port * */ struct cam_cpas_axi_port { Loading @@ -157,6 +158,7 @@ struct cam_cpas_axi_port { struct device_node *axi_port_node; struct device_node *axi_port_mnoc_node; struct device_node *axi_port_camnoc_node; struct cam_axi_vote consolidated_axi_vote; }; /** Loading Loading
Documentation/devicetree/bindings/media/video/msm-cam-cpas.txt +20 −0 Original line number Diff line number Diff line Loading @@ -108,6 +108,23 @@ First Level Node - CAM CPAS device Definition: List of strings corresponds clock-rates levels. Supported strings: minsvs, lowsvs, svs, svs_l1, nominal, turbo. - control-camnoc-axi-clk Usage: optional Value type: <empty> Definition: Bool property specifying whether to control camnoc axi clock from cpas driver. - camnoc-bus-width Usage: required if control-camnoc-axi-clk is enabled Value type: <u32> Definition: camnoc bus width. - camnoc-axi-clk-bw-margin-perc Usage: optional Value type: <u32> Definition: Percentage value to be added to camnoc bw while calculating camnoc axi clock frequency. - qcom,msm-bus,name - qcom,msm-bus,num-cases - qcom,msm-bus,num-paths Loading Loading @@ -211,6 +228,9 @@ Example: src-clock-name = "slow_ahb_clk_src"; clock-rates = <0 0 0 0 80000000 0>; clock-cntl-level = "turbo"; control-camnoc-axi-clk; camnoc-bus-width = <32>; camnoc-axi-clk-bw-margin-perc = <10>; qcom,msm-bus,name = "cam_ahb"; qcom,msm-bus,num-cases = <4>; qcom,msm-bus,num-paths = <1>; Loading
arch/arm64/boot/dts/qcom/sdm670-camera.dtsi +1 −3 Original line number Diff line number Diff line Loading @@ -234,9 +234,7 @@ msm_cam_smmu_lrme { compatible = "qcom,msm-cam-smmu-cb"; iommus = <&apps_smmu 0x1038 0x0>, <&apps_smmu 0x1058 0x0>, <&apps_smmu 0x1039 0x0>, <&apps_smmu 0x1059 0x0>; <&apps_smmu 0x1058 0x0>; label = "lrme"; lrme_iova_mem_map: iova-mem-map { iova-mem-region-shared { Loading
arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi +2 −4 Original line number Diff line number Diff line /* * Copyright (c) 2017, The Linux Foundation. All rights reserved. * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -161,9 +161,7 @@ msm_cam_smmu_lrme { compatible = "qcom,msm-cam-smmu-cb"; iommus = <&apps_smmu 0x1038 0x0>, <&apps_smmu 0x1058 0x0>, <&apps_smmu 0x1039 0x0>, <&apps_smmu 0x1059 0x0>; <&apps_smmu 0x1058 0x0>; label = "lrme"; lrme_iova_mem_map: iova-mem-map { iova-mem-region-shared { Loading
drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c +81 −8 Original line number Diff line number Diff line Loading @@ -543,10 +543,71 @@ static int cam_cpas_hw_reg_read(struct cam_hw_info *cpas_hw, return rc; } static int cam_cpas_util_set_camnoc_axi_clk_rate( struct cam_hw_info *cpas_hw) { 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 rc = 0; 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; struct cam_cpas_axi_port *curr_axi_port = NULL; struct cam_cpas_axi_port *temp_axi_port = NULL; uint64_t required_camnoc_bw = 0; int32_t clk_rate = 0; list_for_each_entry_safe(curr_axi_port, temp_axi_port, &cpas_core->axi_ports_list_head, sibling_port) { if (curr_axi_port->consolidated_axi_vote.uncompressed_bw > required_camnoc_bw) required_camnoc_bw = curr_axi_port-> consolidated_axi_vote.uncompressed_bw; CAM_DBG(CAM_CPAS, "[%s] : curr=%llu, overal=%llu", curr_axi_port->axi_port_name, curr_axi_port->consolidated_axi_vote. uncompressed_bw, required_camnoc_bw); } required_camnoc_bw += (required_camnoc_bw * soc_private->camnoc_axi_clk_bw_margin) / 100; if ((required_camnoc_bw > 0) && (required_camnoc_bw < CAM_CPAS_AXI_MIN_CAMNOC_IB_BW)) required_camnoc_bw = CAM_CPAS_AXI_MIN_CAMNOC_IB_BW; clk_rate = required_camnoc_bw / soc_private->camnoc_bus_width; CAM_DBG(CAM_CPAS, "Setting camnoc axi clk rate : %llu %d", required_camnoc_bw, clk_rate); rc = cam_soc_util_set_clk_rate( soc_info->clk[soc_info->src_clk_idx], soc_info->clk_name[soc_info->src_clk_idx], clk_rate); if (!rc) CAM_ERR(CAM_CPAS, "Failed in setting camnoc axi clk %llu %d %d", required_camnoc_bw, clk_rate, rc); } return rc; } static int cam_cpas_util_apply_client_axi_vote( struct cam_cpas *cpas_core, struct cam_cpas_private_soc *soc_private, struct cam_cpas_client *cpas_client, struct cam_axi_vote *axi_vote) struct cam_hw_info *cpas_hw, struct cam_cpas_client *cpas_client, struct cam_axi_vote *axi_vote) { struct cam_cpas_private_soc *soc_private = (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; struct cam_cpas_client *curr_client; struct cam_cpas_client *temp_client; struct cam_axi_vote req_axi_vote = *axi_vote; Loading Loading @@ -587,6 +648,9 @@ static int cam_cpas_util_apply_client_axi_vote( if ((!soc_private->axi_camnoc_based) && (mnoc_bw < camnoc_bw)) mnoc_bw = camnoc_bw; axi_port->consolidated_axi_vote.compressed_bw = mnoc_bw; axi_port->consolidated_axi_vote.uncompressed_bw = camnoc_bw; CAM_DBG(CAM_CPAS, "axi[(%d, %d),(%d, %d)] : camnoc_bw[%llu], mnoc_bw[%llu]", axi_port->mnoc_bus.src, axi_port->mnoc_bus.dst, Loading @@ -613,6 +677,14 @@ static int cam_cpas_util_apply_client_axi_vote( } } mutex_unlock(&axi_port->lock); 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; unlock_axi_port: mutex_unlock(&axi_port->lock); return rc; Loading Loading @@ -645,6 +717,7 @@ static int cam_cpas_hw_update_axi_vote(struct cam_hw_info *cpas_hw, if (!CAM_CPAS_CLIENT_VALID(client_indx)) return -EINVAL; mutex_lock(&cpas_hw->hw_mutex); mutex_lock(&cpas_core->client_mutex[client_indx]); if (!CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) { Loading @@ -658,12 +731,12 @@ static int cam_cpas_hw_update_axi_vote(struct cam_hw_info *cpas_hw, client_indx, axi_vote.compressed_bw, axi_vote.uncompressed_bw); rc = cam_cpas_util_apply_client_axi_vote(cpas_core, cpas_hw->soc_info.soc_private, rc = cam_cpas_util_apply_client_axi_vote(cpas_hw, cpas_core->cpas_client[client_indx], &axi_vote); unlock_client: mutex_unlock(&cpas_core->client_mutex[client_indx]); mutex_unlock(&cpas_hw->hw_mutex); return rc; } Loading Loading @@ -897,8 +970,8 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, "AXI client[%d] compressed_bw[%llu], uncompressed_bw[%llu]", client_indx, axi_vote->compressed_bw, axi_vote->uncompressed_bw); rc = cam_cpas_util_apply_client_axi_vote(cpas_core, cpas_hw->soc_info.soc_private, cpas_client, axi_vote); rc = cam_cpas_util_apply_client_axi_vote(cpas_hw, cpas_client, axi_vote); if (rc) goto done; Loading Loading @@ -1040,8 +1113,8 @@ static int cam_cpas_hw_stop(void *hw_priv, void *stop_args, axi_vote.uncompressed_bw = 0; axi_vote.compressed_bw = 0; rc = cam_cpas_util_apply_client_axi_vote(cpas_core, cpas_hw->soc_info.soc_private, cpas_client, &axi_vote); rc = cam_cpas_util_apply_client_axi_vote(cpas_hw, cpas_client, &axi_vote); done: mutex_unlock(&cpas_core->client_mutex[client_indx]); Loading
drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.h +2 −0 Original line number Diff line number Diff line Loading @@ -145,6 +145,7 @@ struct cam_cpas_bus_client { * @axi_port_node: Node representing this AXI Port * @axi_port_mnoc_node: Node representing mnoc in this AXI Port * @axi_port_camnoc_node: Node representing camnoc in this AXI Port * @consolidated_axi_vote: Consolidated axi bw values for this AXI port * */ struct cam_cpas_axi_port { Loading @@ -157,6 +158,7 @@ struct cam_cpas_axi_port { struct device_node *axi_port_node; struct device_node *axi_port_mnoc_node; struct device_node *axi_port_camnoc_node; struct cam_axi_vote consolidated_axi_vote; }; /** Loading