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 @@ -204,6 +221,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 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 drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.c +29 −0 Original line number Diff line number Diff line Loading @@ -105,6 +105,35 @@ int cam_cpas_get_custom_dt_info(struct platform_device *pdev, soc_private->axi_camnoc_based = of_property_read_bool(of_node, "client-bus-camnoc-based"); soc_private->control_camnoc_axi_clk = of_property_read_bool(of_node, "control-camnoc-axi-clk"); if (soc_private->control_camnoc_axi_clk == true) { rc = of_property_read_u32(of_node, "camnoc-bus-width", &soc_private->camnoc_bus_width); if (rc || (soc_private->camnoc_bus_width == 0)) { CAM_ERR(CAM_CPAS, "Bus width not found rc=%d, %d", rc, soc_private->camnoc_bus_width); return rc; } rc = of_property_read_u32(of_node, "camnoc-axi-clk-bw-margin-perc", &soc_private->camnoc_axi_clk_bw_margin); if (rc) { /* this is not fatal, overwrite rc */ rc = 0; soc_private->camnoc_axi_clk_bw_margin = 0; } } CAM_DBG(CAM_CPAS, "control_camnoc_axi_clk=%d, width=%d, margin=%d", soc_private->control_camnoc_axi_clk, soc_private->camnoc_bus_width, soc_private->camnoc_axi_clk_bw_margin); count = of_property_count_u32_elems(of_node, "vdd-corners"); if ((count > 0) && (count <= CAM_REGULATOR_LEVEL_MAX) && (of_property_count_strings(of_node, "vdd-corner-ahb-mapping") == Loading drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.h +7 −0 Original line number Diff line number Diff line Loading @@ -43,6 +43,10 @@ struct cam_cpas_vdd_ahb_mapping { * @axi_port_list_node : Node representing AXI Ports list * @num_vdd_ahb_mapping : Number of vdd to ahb level mapping supported * @vdd_ahb : AHB level mapping info for the supported vdd levels * @control_camnoc_axi_clk : Whether CPAS driver need to set camnoc axi clk freq * @camnoc_bus_width : CAMNOC Bus width * @camnoc_axi_clk_bw_margin : BW Margin in percentage to add while calculating * camnoc axi clock * */ struct cam_cpas_private_soc { Loading @@ -56,6 +60,9 @@ struct cam_cpas_private_soc { struct device_node *axi_port_list_node; uint32_t num_vdd_ahb_mapping; struct cam_cpas_vdd_ahb_mapping vdd_ahb[CAM_REGULATOR_LEVEL_MAX]; bool control_camnoc_axi_clk; uint32_t camnoc_bus_width; uint32_t camnoc_axi_clk_bw_margin; }; int cam_cpas_soc_init_resources(struct cam_hw_soc_info *soc_info, 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 @@ -204,6 +221,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
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
drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.c +29 −0 Original line number Diff line number Diff line Loading @@ -105,6 +105,35 @@ int cam_cpas_get_custom_dt_info(struct platform_device *pdev, soc_private->axi_camnoc_based = of_property_read_bool(of_node, "client-bus-camnoc-based"); soc_private->control_camnoc_axi_clk = of_property_read_bool(of_node, "control-camnoc-axi-clk"); if (soc_private->control_camnoc_axi_clk == true) { rc = of_property_read_u32(of_node, "camnoc-bus-width", &soc_private->camnoc_bus_width); if (rc || (soc_private->camnoc_bus_width == 0)) { CAM_ERR(CAM_CPAS, "Bus width not found rc=%d, %d", rc, soc_private->camnoc_bus_width); return rc; } rc = of_property_read_u32(of_node, "camnoc-axi-clk-bw-margin-perc", &soc_private->camnoc_axi_clk_bw_margin); if (rc) { /* this is not fatal, overwrite rc */ rc = 0; soc_private->camnoc_axi_clk_bw_margin = 0; } } CAM_DBG(CAM_CPAS, "control_camnoc_axi_clk=%d, width=%d, margin=%d", soc_private->control_camnoc_axi_clk, soc_private->camnoc_bus_width, soc_private->camnoc_axi_clk_bw_margin); count = of_property_count_u32_elems(of_node, "vdd-corners"); if ((count > 0) && (count <= CAM_REGULATOR_LEVEL_MAX) && (of_property_count_strings(of_node, "vdd-corner-ahb-mapping") == Loading
drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.h +7 −0 Original line number Diff line number Diff line Loading @@ -43,6 +43,10 @@ struct cam_cpas_vdd_ahb_mapping { * @axi_port_list_node : Node representing AXI Ports list * @num_vdd_ahb_mapping : Number of vdd to ahb level mapping supported * @vdd_ahb : AHB level mapping info for the supported vdd levels * @control_camnoc_axi_clk : Whether CPAS driver need to set camnoc axi clk freq * @camnoc_bus_width : CAMNOC Bus width * @camnoc_axi_clk_bw_margin : BW Margin in percentage to add while calculating * camnoc axi clock * */ struct cam_cpas_private_soc { Loading @@ -56,6 +60,9 @@ struct cam_cpas_private_soc { struct device_node *axi_port_list_node; uint32_t num_vdd_ahb_mapping; struct cam_cpas_vdd_ahb_mapping vdd_ahb[CAM_REGULATOR_LEVEL_MAX]; bool control_camnoc_axi_clk; uint32_t camnoc_bus_width; uint32_t camnoc_axi_clk_bw_margin; }; int cam_cpas_soc_init_resources(struct cam_hw_soc_info *soc_info, Loading