Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a03f8a92 authored by Camera Software Integration's avatar Camera Software Integration Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: camera: cpas: Add support for camnoc based voting" into camera-kernel.lnx.3.1

parents 487b31f8 502e394e
Loading
Loading
Loading
Loading
+141 −23
Original line number Diff line number Diff line
@@ -242,6 +242,12 @@ static int cam_cpas_util_axi_cleanup(struct cam_cpas *cpas_core,
		return -EINVAL;
	}

	if (cpas_core->num_camnoc_axi_ports > CAM_CPAS_MAX_AXI_PORTS) {
		CAM_ERR(CAM_CPAS, "Invalid num_camnoc_axi_ports: %d",
			cpas_core->num_camnoc_axi_ports);
		return -EINVAL;
	}

	for (i = 0; i < cpas_core->num_axi_ports; i++) {
		cam_cpas_util_unregister_bus_client(
			&cpas_core->axi_port[i].bus_client);
@@ -249,6 +255,13 @@ static int cam_cpas_util_axi_cleanup(struct cam_cpas *cpas_core,
		cpas_core->axi_port[i].axi_port_node = NULL;
	}

	for (i = 0; i < cpas_core->num_camnoc_axi_ports; i++) {
		cam_cpas_util_unregister_bus_client(
			&cpas_core->camnoc_axi_port[i].bus_client);
		of_node_put(cpas_core->camnoc_axi_port[i].axi_port_node);
		cpas_core->camnoc_axi_port[i].axi_port_node = NULL;
	}

	return 0;
}

@@ -257,6 +270,7 @@ static int cam_cpas_util_axi_setup(struct cam_cpas *cpas_core,
{
	int i = 0, rc = 0;
	struct device_node *axi_port_mnoc_node = NULL;
	struct device_node *axi_port_camnoc_node = NULL;

	if (cpas_core->num_axi_ports > CAM_CPAS_MAX_AXI_PORTS) {
		CAM_ERR(CAM_CPAS, "Invalid num_axi_ports: %d",
@@ -271,6 +285,15 @@ static int cam_cpas_util_axi_setup(struct cam_cpas *cpas_core,
		if (rc)
			goto bus_register_fail;
	}
	for (i = 0; i < cpas_core->num_camnoc_axi_ports; i++) {
		axi_port_camnoc_node =
			cpas_core->camnoc_axi_port[i].axi_port_node;
		rc = cam_cpas_util_register_bus_client(soc_info,
			axi_port_camnoc_node,
			&cpas_core->camnoc_axi_port[i].bus_client);
		if (rc)
			goto bus_register_fail;
	}

	return 0;
bus_register_fail:
@@ -608,6 +631,99 @@ static int cam_cpas_axi_consolidate_path_votes(
	return rc;
}

static int cam_cpas_update_axi_vote_bw(
	struct cam_hw_info *cpas_hw,
	struct cam_cpas_tree_node *cpas_tree_node,
	bool   *mnoc_axi_port_updated,
	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;

	if (cpas_tree_node->axi_port_idx >= CAM_CPAS_MAX_AXI_PORTS) {
		CAM_ERR(CAM_CPAS, "Invalid axi_port_idx: %d",
			cpas_tree_node->axi_port_idx);
		return -EINVAL;
	}

	cpas_core->axi_port[cpas_tree_node->axi_port_idx].ab_bw =
		cpas_tree_node->mnoc_ab_bw;
	cpas_core->axi_port[cpas_tree_node->axi_port_idx].ib_bw =
		cpas_tree_node->mnoc_ib_bw;
	mnoc_axi_port_updated[cpas_tree_node->axi_port_idx] = true;

	if (soc_private->control_camnoc_axi_clk)
		return 0;

	cpas_core->camnoc_axi_port[cpas_tree_node->axi_port_idx].camnoc_bw =
		cpas_tree_node->camnoc_bw;
	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,
	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;

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

	if (cpas_core->num_camnoc_axi_ports > CAM_CPAS_MAX_AXI_PORTS) {
		CAM_ERR(CAM_CPAS, "Invalid num_camnoc_axi_ports: %d",
			cpas_core->num_camnoc_axi_ports);
		return -EINVAL;
	}

	for (i = 0; i < cpas_core->num_camnoc_axi_ports; i++) {
		if (camnoc_axi_port_updated[i])
			camnoc_axi_port = &cpas_core->camnoc_axi_port[i];
		else
			continue;

		CAM_DBG(CAM_PERF, "Port[%s] : camnoc_bw=%lld",
			camnoc_axi_port->axi_port_name,
			camnoc_axi_port->camnoc_bw);

		if (camnoc_axi_port->camnoc_bw)
			camnoc_bw = camnoc_axi_port->camnoc_bw;
		else
			camnoc_bw = camnoc_axi_port->additional_bw;

		rc = cam_cpas_util_vote_bus_client_bw(
			&camnoc_axi_port->bus_client,
			0, camnoc_bw, true);

		CAM_DBG(CAM_CPAS,
			"camnoc vote camnoc_bw[%llu] rc=%d %s",
			camnoc_bw, rc, camnoc_axi_port->axi_port_name);
		if (rc) {
			CAM_ERR(CAM_CPAS,
				"Failed in camnoc vote camnoc_bw[%llu] rc=%d",
				camnoc_bw, rc);
			break;
		}
	}
	return rc;
}

static int cam_cpas_util_apply_client_axi_vote(
	struct cam_hw_info *cpas_hw,
	struct cam_cpas_client *cpas_client,
@@ -615,12 +731,13 @@ static int cam_cpas_util_apply_client_axi_vote(
{
	struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
	struct cam_axi_vote *con_axi_vote = NULL;
	struct cam_cpas_axi_port *axi_port = NULL;
	struct cam_cpas_axi_port *mnoc_axi_port = NULL;
	struct cam_cpas_tree_node *curr_tree_node = NULL;
	struct cam_cpas_tree_node *par_tree_node = NULL;
	uint32_t transac_type;
	uint32_t path_data_type;
	bool axi_port_updated[CAM_CPAS_MAX_AXI_PORTS] = {false};
	bool mnoc_axi_port_updated[CAM_CPAS_MAX_AXI_PORTS] = {false};
	bool camnoc_axi_port_updated[CAM_CPAS_MAX_AXI_PORTS] = {false};
	uint64_t mnoc_ab_bw = 0, mnoc_ib_bw = 0,
		curr_camnoc_old = 0, curr_mnoc_ab_old = 0, curr_mnoc_ib_old = 0,
		par_camnoc_old = 0, par_mnoc_ab_old = 0, par_mnoc_ib_old = 0;
@@ -643,7 +760,7 @@ static int cam_cpas_util_apply_client_axi_vote(
				cpas_core->axi_port[i].additional_bw -=
					CAM_CPAS_DEFAULT_AXI_BW;
			}
			axi_port_updated[i] = true;
			mnoc_axi_port_updated[i] = true;
		}
		goto vote_start_clients;
	}
@@ -733,15 +850,15 @@ static int cam_cpas_util_apply_client_axi_vote(
					rc = -EINVAL;
					goto unlock_tree;
				}

				cpas_core->axi_port
				[par_tree_node->axi_port_idx].ab_bw =
				par_tree_node->mnoc_ab_bw;
				cpas_core->axi_port
				[par_tree_node->axi_port_idx].ib_bw =
				par_tree_node->mnoc_ib_bw;
				axi_port_updated[par_tree_node->axi_port_idx] =
					true;
				rc = cam_cpas_update_axi_vote_bw(cpas_hw,
					par_tree_node,
					mnoc_axi_port_updated,
					camnoc_axi_port_updated);
				if (rc) {
					CAM_ERR(CAM_CPAS,
						"Update Vote failed");
					goto unlock_tree;
				}
			}

			curr_tree_node = par_tree_node;
@@ -759,26 +876,27 @@ static int cam_cpas_util_apply_client_axi_vote(

vote_start_clients:
	for (i = 0; i < cpas_core->num_axi_ports; i++) {
		if (axi_port_updated[i])
			axi_port = &cpas_core->axi_port[i];
		if (mnoc_axi_port_updated[i])
			mnoc_axi_port = &cpas_core->axi_port[i];
		else
			continue;

		CAM_DBG(CAM_PERF, "Port[%s] : ab=%lld ib=%lld additional=%lld",
			axi_port->axi_port_name, axi_port->ab_bw,
			axi_port->ib_bw, axi_port->additional_bw);
			mnoc_axi_port->axi_port_name, mnoc_axi_port->ab_bw,
			mnoc_axi_port->ib_bw, mnoc_axi_port->additional_bw);

		if (axi_port->ab_bw)
			mnoc_ab_bw = axi_port->ab_bw;
		if (mnoc_axi_port->ab_bw)
			mnoc_ab_bw = mnoc_axi_port->ab_bw;
		else
			mnoc_ab_bw = axi_port->additional_bw;
			mnoc_ab_bw = mnoc_axi_port->additional_bw;

		if (cpas_core->axi_port[i].ib_bw_voting_needed)
			mnoc_ib_bw = axi_port->ib_bw;
			mnoc_ib_bw = mnoc_axi_port->ib_bw;
		else
			mnoc_ib_bw = 0;

		rc = cam_cpas_util_vote_bus_client_bw(&axi_port->bus_client,
		rc = cam_cpas_util_vote_bus_client_bw(
			&mnoc_axi_port->bus_client,
			mnoc_ab_bw, mnoc_ib_bw, false);
		if (rc) {
			CAM_ERR(CAM_CPAS,
@@ -787,8 +905,8 @@ static int cam_cpas_util_apply_client_axi_vote(
			goto unlock_tree;
		}
	}

	rc = cam_cpas_util_set_camnoc_axi_clk_rate(cpas_hw);
	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);

+7 −1
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
 */

#ifndef _CAM_CPAS_HW_H_
@@ -153,6 +153,7 @@ struct cam_cpas_bus_client {
 * @axi_port_node: Node representing AXI Port info in device tree
 * @ab_bw: AB bw value for this port
 * @ib_bw: IB bw value for this port
 * @camnoc_bw: CAMNOC bw value for this port
 * @additional_bw: Additional bandwidth to cover non-hw cpas clients
 */
struct cam_cpas_axi_port {
@@ -162,6 +163,7 @@ struct cam_cpas_axi_port {
	struct device_node *axi_port_node;
	uint64_t ab_bw;
	uint64_t ib_bw;
	uint64_t camnoc_bw;
	uint64_t additional_bw;
};

@@ -174,11 +176,13 @@ struct cam_cpas_axi_port {
 * @tree_lock: Mutex lock for accessing CPAS node tree
 * @num_clients: Total number of clients that CPAS supports
 * @num_axi_ports: Total number of axi ports found in device tree
 * @num_camnoc_axi_ports: Total number of camnoc axi ports found in device tree
 * @registered_clients: Number of Clients registered currently
 * @streamon_clients: Number of Clients that are in start state currently
 * @regbase_index: Register base indices for CPAS register base IDs
 * @ahb_bus_client: AHB Bus client info
 * @axi_port: AXI port info for a specific axi index
 * @camnoc_axi_port: CAMNOC AXI port info for a specific camnoc axi index
 * @internal_ops: CPAS HW internal ops
 * @work_queue: Work queue handle
 * @irq_count: atomic irq count
@@ -193,11 +197,13 @@ struct cam_cpas {
	struct mutex tree_lock;
	uint32_t num_clients;
	uint32_t num_axi_ports;
	uint32_t num_camnoc_axi_ports;
	uint32_t registered_clients;
	uint32_t streamon_clients;
	int32_t regbase_index[CAM_CPAS_REG_MAX];
	struct cam_cpas_bus_client ahb_bus_client;
	struct cam_cpas_axi_port axi_port[CAM_CPAS_MAX_AXI_PORTS];
	struct cam_cpas_axi_port camnoc_axi_port[CAM_CPAS_MAX_AXI_PORTS];
	struct cam_cpas_internal_ops internal_ops;
	struct workqueue_struct *work_queue;
	atomic_t irq_count;
+53 −1
Original line number Diff line number Diff line
@@ -134,6 +134,47 @@ static int cam_cpas_util_path_type_to_idx(uint32_t *path_data_type)
	return 0;
}

static int cam_cpas_update_camnoc_node(struct cam_cpas *cpas_core,
	struct device_node *curr_node,
	struct cam_cpas_tree_node *cpas_node_ptr,
	int *camnoc_idx)

{
	struct device_node *camnoc_node;
	int rc;

	camnoc_node = of_find_node_by_name(curr_node,
			"qcom,axi-port-camnoc");
	if (camnoc_node) {

		if (*camnoc_idx >=
			CAM_CPAS_MAX_AXI_PORTS) {
			CAM_ERR(CAM_CPAS, "CAMNOC axi index overshoot %d",
				*camnoc_idx);
			return -EINVAL;
		}

		cpas_core->camnoc_axi_port[*camnoc_idx]
			.axi_port_node = camnoc_node;
		rc = of_property_read_string(
			curr_node,
			"qcom,axi-port-name",
			&cpas_core->camnoc_axi_port[*camnoc_idx]
			.axi_port_name);

		if (rc) {
			CAM_ERR(CAM_CPAS,
				"fail to read camnoc-port-name rc=%d",
				rc);
			return rc;
		}
		cpas_node_ptr->camnoc_axi_port_idx = *camnoc_idx;
		cpas_core->num_camnoc_axi_ports++;
		(*camnoc_idx)++;
	}
	return 0;
}

static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core,
	struct device_node *of_node, struct cam_cpas_private_soc *soc_private)
{
@@ -142,7 +183,7 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core,
	struct device_node *curr_node;
	struct device_node *parent_node;
	struct device_node *mnoc_node;
	int mnoc_idx = 0;
	int mnoc_idx = 0, camnoc_idx = 0;
	uint32_t path_idx;
	bool camnoc_max_needed = false;
	struct cam_cpas_tree_node *curr_node_ptr = NULL;
@@ -248,6 +289,17 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core,
				cpas_core->num_axi_ports++;
			}

			if (!soc_private->control_camnoc_axi_clk) {
				rc = cam_cpas_update_camnoc_node(
					cpas_core, curr_node, curr_node_ptr,
					&camnoc_idx);
				if (rc) {
					CAM_ERR(CAM_CPAS,
						"Parse Camnoc port fail");
					return rc;
				}
			}

			rc = of_property_read_string(curr_node,
				"client-name", &client_name);
			if (!rc) {
+2 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ struct cam_cpas_vdd_ahb_mapping {
 * @cell_idx: Index to identify node from device tree and its parent
 * @level_idx: Index to identify at what level the node is present
 * @axi_port_idx: Index to identify which axi port to vote the consolidated bw
 * @camnoc_axi_port_idx: Index to find which axi port to vote consolidated bw
 * @path_data_type: Traffic type info from device tree (ife-vid, ife-disp etc)
 * @path_trans_type: Transaction type info from device tree (rd, wr)
 * @merge_type: Traffic merge type (calculation info) from device tree
@@ -54,6 +55,7 @@ struct cam_cpas_tree_node {
	uint32_t cell_idx;
	uint32_t level_idx;
	int axi_port_idx;
	int camnoc_axi_port_idx;
	const char *node_name;
	uint32_t path_data_type;
	uint32_t path_trans_type;