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

Commit f9284300 authored by Girish Mahadevan's avatar Girish Mahadevan Committed by Matt Wagantall
Browse files

msm: msm_bus: Add support to handle clock array for QoS programming



Bus driver needs to program the QoS registers for master ports in order
to ensure accurate response time for all bus masters in the SOC. However
programming these registers could entail enabling multiple clocks and
regulators. Add support to allow enabling an array of clock handles and
their corresponding regulator if needed.

Change-Id: Ie518cd8c033d9f2735a084aae0df8dc2817bd838
Signed-off-by: default avatarGirish Mahadevan <girishm@codeaurora.org>
parent 61a4084c
Loading
Loading
Loading
Loading
+14 −1
Original line number Diff line number Diff line
@@ -114,7 +114,6 @@ qcom,blacklist: An array of phandles that represent devices that this de
			intermediate nodes.
qcom,agg-ports:		The number of aggregation ports on the bus.


The following properties are optional as collecting data via coresight might
and are present on child nodes that represent NOC devices. The documentation
for coresight properties can be found in:
@@ -128,6 +127,14 @@ coresight-child-list List of phandles pointing to the children of this
			component.
coresight-child-ports	List of input port numbers of the children.

The following sub-nodes are optional paramters:

qcom,node-qos-clks:	Optional node listing all the clocks and regulators required for programming of
			QoS registers. Usually these are associated with fabric nodes.
	clock-names:	An array of clock names for QoS programming,
	clocks:		An array of clock phandles corresponding to the clock names listed above.
	clock-name-gdsc:
			An optional property listing the regulator associated with a given clock name.

Example:

@@ -148,6 +155,12 @@ Example:
                clock-names = "bus_clk", "bus_a_clk";
                clocks = <&clock_rpm  clk_snoc_msmbus_clk>,
                      <&clock_rpm  clk_snoc_msmbus_a_clk>;
		qcom,node-qos-clks {
			clock-names = "q0-clk", "q1-clk";
			clocks = <&clock_gcc clk_q0_clk>,
				<&clock_gcc clk_q1_clk>;
			q0-clk-supply = <&gdsc_q0_clk>;
		};
        };

        mm_int_bimc: mm-int-bimc {
+3 −1
Original line number Diff line number Diff line
@@ -118,7 +118,9 @@ struct msm_bus_node_device_type {
	struct list_head link;
	unsigned int ap_owned;
	struct nodeclk clk[NUM_CTX];
	struct nodeclk qos_clk;
	struct nodeclk bus_qos_clk;
	uint32_t num_node_qos_clks;
	struct nodeclk *node_qos_clks;
	struct device_node *of_node;
};

+1 −1
Original line number Diff line number Diff line
@@ -42,7 +42,7 @@
#define INTERLEAVED_VAL(fab_pdata, n) \
	((fab_pdata->il_flag) ? (n) : 1)
#define KBTOB(a) (a * 1000ULL)
#define MAX_REG_NAME	(20)
#define MAX_REG_NAME	(50)

enum msm_bus_dbg_op_type {
	MSM_BUS_DBG_UNREGISTER = -2,
+74 −105
Original line number Diff line number Diff line
@@ -398,13 +398,14 @@ static int flush_clk_data(struct device *node_device, int ctx)
			ret = enable_nodeclk(nodeclk, node_device);

			if ((node->node_info->is_fab_dev) &&
				!IS_ERR_OR_NULL(node->qos_clk.clk))
					ret = enable_nodeclk(&node->qos_clk,
				!IS_ERR_OR_NULL(node->bus_qos_clk.clk))
					ret = enable_nodeclk(&node->bus_qos_clk,
								node_device);
		} else {
			if ((node->node_info->is_fab_dev) &&
				!IS_ERR_OR_NULL(node->qos_clk.clk))
					ret = disable_nodeclk(&node->qos_clk);
				!IS_ERR_OR_NULL(node->bus_qos_clk.clk))
					ret =
					disable_nodeclk(&node->bus_qos_clk);

			ret = disable_nodeclk(nodeclk);
		}
@@ -642,119 +643,60 @@ static void msm_bus_fab_init_noc_ops(struct msm_bus_node_device_type *bus_dev)
	}
}

static int msm_bus_qos_disable_clk(struct msm_bus_node_device_type *node,
				int disable_bus_qos_clk)
static int msm_bus_disable_node_qos_clk(struct msm_bus_node_device_type *node)
{
	struct msm_bus_node_device_type *bus_node = NULL;
	int i;
	int ret = 0;

	if (!node) {
	if (!node || (!node->node_info->bus_device->platform_data)) {
		ret = -ENXIO;
		goto exit_disable_qos_clk;
		goto exit_disable_node_qos_clk;
	}

	bus_node = node->node_info->bus_device->platform_data;

	if (!bus_node) {
		ret = -ENXIO;
		goto exit_disable_qos_clk;
	}

	if (disable_bus_qos_clk)
		ret = disable_nodeclk(&bus_node->clk[DUAL_CTX]);
	for (i = 0; i < bus_node->num_node_qos_clks; i++)
		ret = disable_nodeclk(&bus_node->node_qos_clks[i]);

	if (ret) {
		MSM_BUS_ERR("%s: Failed to disable bus clk, node %d",
			__func__, node->node_info->id);
		goto exit_disable_qos_clk;
	}

	if (!IS_ERR_OR_NULL(node->qos_clk.clk)) {
		ret = disable_nodeclk(&node->qos_clk);

		if (ret) {
			MSM_BUS_ERR("%s: Failed to disable mas qos clk,node %d",
				__func__, node->node_info->id);
			goto exit_disable_qos_clk;
		}
	}

exit_disable_qos_clk:
exit_disable_node_qos_clk:
	return ret;
}

static int msm_bus_qos_enable_clk(struct msm_bus_node_device_type *node)
static int msm_bus_enable_node_qos_clk(struct msm_bus_node_device_type *node)
{
	struct msm_bus_node_device_type *bus_node = NULL;
	int i;
	int ret;
	long rounded_rate;
	int ret = 0;
	int bus_qos_enabled = 0;

	if (!node) {
	if (!node || (!node->node_info->bus_device->platform_data)) {
		ret = -ENXIO;
		goto exit_enable_qos_clk;
		goto exit_enable_node_qos_clk;
	}

	bus_node = node->node_info->bus_device->platform_data;

	if (!bus_node) {
		ret = -ENXIO;
		goto exit_enable_qos_clk;
	}

	/* Check if the bus clk is already set before trying to set it
	 * Do this only during
	 *	a. Bootup
	 *	b. Only for bus clks
	 **/
	if (!clk_get_rate(bus_node->clk[DUAL_CTX].clk)) {
		rounded_rate = clk_round_rate(bus_node->clk[DUAL_CTX].clk, 1);
		ret = setrate_nodeclk(&bus_node->clk[DUAL_CTX], rounded_rate);
		if (ret) {
			MSM_BUS_ERR("%s: Failed to set bus clk, node %d",
				__func__, node->node_info->id);
			goto exit_enable_qos_clk;
		}
	}

	ret = enable_nodeclk(&bus_node->clk[DUAL_CTX],
					node->node_info->bus_device);
	if (ret) {
		MSM_BUS_ERR("%s: Failed to enable bus clk, node %d",
	for (i = 0; i < bus_node->num_node_qos_clks; i++) {
		if (!bus_node->node_qos_clks[i].enable_only_clk) {
			rounded_rate =
				clk_round_rate(
					bus_node->node_qos_clks[i].clk, 1);
			ret = setrate_nodeclk(&bus_node->node_qos_clks[i],
								rounded_rate);
			if (ret)
				MSM_BUS_ERR("%s: Failed set rate clk, node %d",
					__func__, node->node_info->id);
		goto exit_enable_qos_clk;
		}
	bus_qos_enabled = 1;

	if (!IS_ERR_OR_NULL(bus_node->qos_clk.clk)) {
		ret = enable_nodeclk(&bus_node->qos_clk,
		ret = enable_nodeclk(&bus_node->node_qos_clks[i],
					node->node_info->bus_device);
		if (ret) {
			MSM_BUS_ERR("%s: Failed to enable bus QOS clk, node %d",
				__func__, node->node_info->id);
			goto exit_enable_qos_clk;
		}
			pr_err("%s: Failed to set Qos Clks ret %d",
				__func__, ret);
			msm_bus_disable_node_qos_clk(node);
			goto exit_enable_node_qos_clk;
		}

	if (!IS_ERR_OR_NULL(node->qos_clk.clk)) {
		rounded_rate = clk_round_rate(node->qos_clk.clk, 1);
		ret = setrate_nodeclk(&node->qos_clk, rounded_rate);
		if (ret) {
			MSM_BUS_ERR("%s: Failed to enable mas qos clk, node %d",
				__func__, node->node_info->id);
			goto exit_enable_qos_clk;
	}

		ret = enable_nodeclk(&node->qos_clk, NULL);
		if (ret) {
			MSM_BUS_ERR("Err enable mas qos clk, node %d ret %d",
				node->node_info->id, ret);
			goto exit_enable_qos_clk;
		}
	}
	ret = bus_qos_enabled;

exit_enable_qos_clk:
exit_enable_node_qos_clk:
	return ret;
}

@@ -842,7 +784,7 @@ static int msm_bus_dev_init_qos(struct device *dev, void *data)
				if (bus_node_info->fabdev->bypass_qos_prg)
					goto exit_init_qos;

				ret = msm_bus_qos_enable_clk(node_dev);
				ret = msm_bus_enable_node_qos_clk(node_dev);
				if (ret < 0) {
					MSM_BUS_ERR("Can't Enable QoS clk %d",
					node_dev->node_info->id);
@@ -855,7 +797,7 @@ static int msm_bus_dev_init_qos(struct device *dev, void *data)
					bus_node_info->fabdev->base_offset,
					bus_node_info->fabdev->qos_off,
					bus_node_info->fabdev->qos_freq);
				ret = msm_bus_qos_disable_clk(node_dev, ret);
				ret = msm_bus_disable_node_qos_clk(node_dev);
			}
		} else
			MSM_BUS_ERR("%s: Skipping QOS init for %d",
@@ -923,8 +865,8 @@ static int msm_bus_init_clk(struct device *bus_dev,
				struct msm_bus_node_device_type *pdata)
{
	unsigned int ctx;
	int ret = 0;
	struct msm_bus_node_device_type *node_dev = bus_dev->platform_data;
	int i;

	for (ctx = 0; ctx < NUM_CTX; ctx++) {
		if (!IS_ERR_OR_NULL(pdata->clk[ctx].clk)) {
@@ -937,24 +879,51 @@ static int msm_bus_init_clk(struct device *bus_dev,
				pdata->clk[ctx].reg_name, MAX_REG_NAME);
			node_dev->clk[ctx].reg = NULL;
			bus_get_reg(&node_dev->clk[ctx], bus_dev);
			MSM_BUS_ERR("%s: Valid node clk node %d ctx %d",
			pr_info("%s: Valid node clk node %d ctx %d\n",
				__func__, node_dev->node_info->id, ctx);
		}
	}

	if (!IS_ERR_OR_NULL(pdata->qos_clk.clk)) {
		node_dev->qos_clk.clk = pdata->qos_clk.clk;
		node_dev->qos_clk.enable_only_clk =
					pdata->qos_clk.enable_only_clk;
		node_dev->qos_clk.enable = false;
		strlcpy(node_dev->qos_clk.reg_name,
			pdata->qos_clk.reg_name, MAX_REG_NAME);
		node_dev->qos_clk.reg = NULL;
		MSM_BUS_ERR("%s: Valid Iface clk node %d", __func__,
	if (!IS_ERR_OR_NULL(pdata->bus_qos_clk.clk)) {
		node_dev->bus_qos_clk.clk = pdata->bus_qos_clk.clk;
		node_dev->bus_qos_clk.enable_only_clk =
					pdata->bus_qos_clk.enable_only_clk;
		node_dev->bus_qos_clk.enable = false;
		strlcpy(node_dev->bus_qos_clk.reg_name,
			pdata->bus_qos_clk.reg_name, MAX_REG_NAME);
		node_dev->bus_qos_clk.reg = NULL;
		pr_info("%s: Valid bus qos clk node %d\n", __func__,
						node_dev->node_info->id);
	}

	return ret;
	if (pdata->num_node_qos_clks) {
		node_dev->num_node_qos_clks = pdata->num_node_qos_clks;
		node_dev->node_qos_clks = devm_kzalloc(bus_dev,
			(node_dev->num_node_qos_clks * sizeof(struct nodeclk)),
			GFP_KERNEL);
		if (!node_dev->node_qos_clks) {
			dev_err(bus_dev, "Failed to alloc memory for qos clk");
			return -ENOMEM;
		}

		for (i = 0; i < pdata->num_node_qos_clks; i++) {
			node_dev->node_qos_clks[i].clk =
					pdata->node_qos_clks[i].clk;
			node_dev->node_qos_clks[i].enable_only_clk =
					pdata->node_qos_clks[i].enable_only_clk;
			node_dev->node_qos_clks[i].enable = false;
			strlcpy(node_dev->node_qos_clks[i].reg_name,
				pdata->node_qos_clks[i].reg_name, MAX_REG_NAME);
			node_dev->node_qos_clks[i].reg = NULL;
			pr_info("%s: Valid qos clk[%d] node %d %d Reg%s\n",
					__func__, i,
					node_dev->node_info->id,
					node_dev->num_node_qos_clks,
					node_dev->node_qos_clks[i].reg_name);
		}
	}

	return 0;
}

static int msm_bus_copy_node_info(struct msm_bus_node_device_type *pdata,
+76 −9
Original line number Diff line number Diff line
@@ -228,6 +228,62 @@ static void get_qos_params(

}

static int msm_bus_of_parse_clk_array(struct device_node *dev_node,
			struct platform_device *pdev, struct nodeclk **clk_arr,
			int *num_clks, int id)
{
	int ret = 0;
	int idx = 0;
	struct property *prop;
	const char *clk_name;
	int clks = 0;

	clks = of_property_count_strings(dev_node, "clock-names");
	if (clks < 0) {
		pr_info("%s: No qos clks node %d\n", __func__, id);
		ret = clks;
		goto exit_of_parse_clk_array;
	}

	*num_clks = clks;
	*clk_arr = devm_kzalloc(&pdev->dev,
			(clks * sizeof(struct nodeclk)), GFP_KERNEL);

	if (!(*clk_arr)) {
		pr_err("%s: Error allocating clk nodes for %d\n", __func__, id);
		ret = -ENOMEM;
		*num_clks = 0;
		goto exit_of_parse_clk_array;
	}

	of_property_for_each_string(dev_node, "clock-names", prop, clk_name) {
		char gdsc_string[MAX_REG_NAME];

		(*clk_arr)[idx].clk = of_clk_get_by_name(dev_node, clk_name);

		if (IS_ERR_OR_NULL((*clk_arr)[idx].clk)) {
			dev_err(&pdev->dev,
				"Failed to get clk %s for bus%d ", clk_name,
									id);
			continue;
		}
		if (strnstr(clk_name, "no-rate", strlen("no-rate")))
			(*clk_arr)[idx].enable_only_clk = true;

		scnprintf(gdsc_string, MAX_REG_NAME, "%s-supply", clk_name);

		if (of_find_property(dev_node, gdsc_string, NULL))
			scnprintf((*clk_arr)[idx].reg_name,
				MAX_REG_NAME, "%s", clk_name);
		else
			scnprintf((*clk_arr)[idx].reg_name,
					MAX_REG_NAME, "%c", '\0');

		idx++;
	}
exit_of_parse_clk_array:
	return ret;
}

static struct msm_bus_node_info_type *get_node_info_data(
		struct device_node * const dev_node,
@@ -378,6 +434,7 @@ static int get_bus_node_device_data(
							"qcom,ap-owned");

	if (node_device->node_info->is_fab_dev) {
		struct device_node *qos_clk_node;
		dev_err(&pdev->dev, "Dev %d\n", node_device->node_info->id);

		if (!node_device->node_info->virt_dev) {
@@ -436,49 +493,59 @@ static int get_bus_node_device_data(
			scnprintf(node_device->clk[ACTIVE_CTX].reg_name,
				MAX_REG_NAME, "%c", '\0');

		node_device->qos_clk.clk = of_clk_get_by_name(dev_node,
		node_device->bus_qos_clk.clk = of_clk_get_by_name(dev_node,
							"bus_qos_clk");

		if (IS_ERR_OR_NULL(node_device->qos_clk.clk)) {
		if (IS_ERR_OR_NULL(node_device->bus_qos_clk.clk)) {
			dev_dbg(&pdev->dev,
				"%s:Failed to get bus qos clk for %d",
				__func__, node_device->node_info->id);
			scnprintf(node_device->qos_clk.reg_name,
			scnprintf(node_device->bus_qos_clk.reg_name,
					MAX_REG_NAME, "%c", '\0');
		} else {
			if (of_find_property(dev_node, "bus-qos-gdsc-supply",
								NULL))
				scnprintf(node_device->qos_clk.reg_name,
				scnprintf(node_device->bus_qos_clk.reg_name,
					MAX_REG_NAME, "%s", "bus-qos-gdsc");
			else
				scnprintf(node_device->qos_clk.reg_name,
				scnprintf(node_device->bus_qos_clk.reg_name,
					MAX_REG_NAME, "%c", '\0');
		}

		qos_clk_node = of_find_node_by_name(dev_node,
						"qcom,node-qos-clks");

		if (qos_clk_node)
			msm_bus_of_parse_clk_array(qos_clk_node, pdev,
			&node_device->node_qos_clks,
			&node_device->num_node_qos_clks,
			node_device->node_info->id);

		if (msmbus_coresight_init_adhoc(pdev, dev_node))
			dev_warn(&pdev->dev,
				 "Coresight support absent for bus: %d\n",
				  node_device->node_info->id);
	} else {
		node_device->qos_clk.clk = of_clk_get_by_name(dev_node,
		node_device->bus_qos_clk.clk = of_clk_get_by_name(dev_node,
							"bus_qos_clk");

		if (IS_ERR_OR_NULL(node_device->qos_clk.clk))
		if (IS_ERR_OR_NULL(node_device->bus_qos_clk.clk))
			dev_dbg(&pdev->dev,
				"%s:Failed to get bus qos clk for mas%d",
				__func__, node_device->node_info->id);

		if (of_find_property(dev_node, "bus-qos-gdsc-supply",
									NULL))
			scnprintf(node_device->qos_clk.reg_name,
			scnprintf(node_device->bus_qos_clk.reg_name,
				MAX_REG_NAME, "%s", "bus-qos-gdsc");
		else
			scnprintf(node_device->qos_clk.reg_name,
			scnprintf(node_device->bus_qos_clk.reg_name,
				MAX_REG_NAME, "%c", '\0');

		enable_only = of_property_read_bool(dev_node,
							"qcom,enable-only-clk");
		node_device->clk[DUAL_CTX].enable_only_clk = enable_only;
		node_device->bus_qos_clk.enable_only_clk = enable_only;

		node_device->clk[DUAL_CTX].clk = of_clk_get_by_name(dev_node,
							"node_clk");