Commit 23145465 authored by Georgi Djakov's avatar Georgi Djakov
Browse files

Merge branch 'icc-msm8939' into icc-next



Split shared RPM based interconnect operation code and add support for
MSM8939 interconnect.

* icc-msm8939
  interconnect: qcom: Consolidate interconnect RPM support
  interconnect: qcom: qcs404: use shared code
  dt-bindings: interconnect: single yaml file for RPM interconnect drivers
  dt-bindings: interconnect: Add Qualcomm MSM8939 DT bindings
  interconnect: qcom: Add MSM8939 interconnect provider driver

Signed-off-by: default avatarGeorgi Djakov <georgi.djakov@linaro.org>
parents 4b1a60a1 6c6fe5d3
Loading
Loading
Loading
Loading
+0 −77
Original line number Diff line number Diff line
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/interconnect/qcom,qcs404.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: Qualcomm QCS404 Network-On-Chip interconnect

maintainers:
  - Georgi Djakov <georgi.djakov@linaro.org>

description: |
  The Qualcomm QCS404 interconnect providers support adjusting the
  bandwidth requirements between the various NoC fabrics.

properties:
  reg:
    maxItems: 1

  compatible:
    enum:
      - qcom,qcs404-bimc
      - qcom,qcs404-pcnoc
      - qcom,qcs404-snoc

  '#interconnect-cells':
    const: 1

  clock-names:
    items:
      - const: bus
      - const: bus_a

  clocks:
    items:
      - description: Bus Clock
      - description: Bus A Clock

required:
  - compatible
  - reg
  - '#interconnect-cells'
  - clock-names
  - clocks

additionalProperties: false

examples:
  - |
      #include <dt-bindings/clock/qcom,rpmcc.h>

      bimc: interconnect@400000 {
              reg = <0x00400000 0x80000>;
              compatible = "qcom,qcs404-bimc";
              #interconnect-cells = <1>;
              clock-names = "bus", "bus_a";
              clocks = <&rpmcc RPM_SMD_BIMC_CLK>,
                       <&rpmcc RPM_SMD_BIMC_A_CLK>;
      };

      pnoc: interconnect@500000 {
             reg = <0x00500000 0x15080>;
             compatible = "qcom,qcs404-pcnoc";
             #interconnect-cells = <1>;
             clock-names = "bus", "bus_a";
             clocks = <&rpmcc RPM_SMD_PNOC_CLK>,
                      <&rpmcc RPM_SMD_PNOC_A_CLK>;
      };

      snoc: interconnect@580000 {
            reg = <0x00580000 0x23080>;
            compatible = "qcom,qcs404-snoc";
            #interconnect-cells = <1>;
            clock-names = "bus", "bus_a";
            clocks = <&rpmcc RPM_SMD_SNOC_CLK>,
                     <&rpmcc RPM_SMD_SNOC_A_CLK>;
      };
+15 −7
Original line number Diff line number Diff line
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/interconnect/qcom,msm8916.yaml#
$id: http://devicetree.org/schemas/interconnect/qcom,rpm.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: Qualcomm MSM8916 Network-On-Chip interconnect
title: Qualcomm RPM Network-On-Chip Interconnect

maintainers:
  - Georgi Djakov <georgi.djakov@linaro.org>

description: |
  The Qualcomm MSM8916 interconnect providers support adjusting the
  bandwidth requirements between the various NoC fabrics.
  RPM interconnect providers support system bandwidth requirements through
  RPM processor. The provider is able to communicate with the RPM through
  the RPM shared memory device.

properties:
  reg:
    maxItems: 1

  compatible:
    enum:
      - qcom,msm8916-bimc
      - qcom,msm8916-pcnoc
      - qcom,msm8916-snoc

  reg:
    maxItems: 1
      - qcom,msm8939-bimc
      - qcom,msm8939-pcnoc
      - qcom,msm8939-snoc
      - qcom,msm8939-snoc-mm
      - qcom,qcs404-bimc
      - qcom,qcs404-pcnoc
      - qcom,qcs404-snoc

  '#interconnect-cells':
    const: 1
+9 −0
Original line number Diff line number Diff line
@@ -17,6 +17,15 @@ config INTERCONNECT_QCOM_MSM8916
	  This is a driver for the Qualcomm Network-on-Chip on msm8916-based
	  platforms.

config INTERCONNECT_QCOM_MSM8939
	tristate "Qualcomm MSM8939 interconnect driver"
	depends on INTERCONNECT_QCOM
	depends on QCOM_SMD_RPM
	select INTERCONNECT_QCOM_SMD_RPM
	help
	  This is a driver for the Qualcomm Network-on-Chip on msm8939-based
	  platforms.

config INTERCONNECT_QCOM_MSM8974
	tristate "Qualcomm MSM8974 interconnect driver"
	depends on INTERCONNECT_QCOM
+3 −1
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@

icc-bcm-voter-objs			:= bcm-voter.o
qnoc-msm8916-objs			:= msm8916.o
qnoc-msm8939-objs			:= msm8939.o
qnoc-msm8974-objs			:= msm8974.o
icc-osm-l3-objs				:= osm-l3.o
qnoc-qcs404-objs			:= qcs404.o
@@ -10,10 +11,11 @@ qnoc-sc7180-objs := sc7180.o
qnoc-sdm845-objs			:= sdm845.o
qnoc-sm8150-objs			:= sm8150.o
qnoc-sm8250-objs			:= sm8250.o
icc-smd-rpm-objs			:= smd-rpm.o
icc-smd-rpm-objs			:= smd-rpm.o icc-rpm.o

obj-$(CONFIG_INTERCONNECT_QCOM_BCM_VOTER) += icc-bcm-voter.o
obj-$(CONFIG_INTERCONNECT_QCOM_MSM8916) += qnoc-msm8916.o
obj-$(CONFIG_INTERCONNECT_QCOM_MSM8939) += qnoc-msm8939.o
obj-$(CONFIG_INTERCONNECT_QCOM_MSM8974) += qnoc-msm8974.o
obj-$(CONFIG_INTERCONNECT_QCOM_OSM_L3) += icc-osm-l3.o
obj-$(CONFIG_INTERCONNECT_QCOM_QCS404) += qnoc-qcs404.o
+191 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2020 Linaro Ltd
 */

#include <linux/clk.h>
#include <linux/device.h>
#include <linux/interconnect-provider.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/slab.h>

#include "smd-rpm.h"
#include "icc-rpm.h"

static int qcom_icc_set(struct icc_node *src, struct icc_node *dst)
{
	struct qcom_icc_provider *qp;
	struct qcom_icc_node *qn;
	struct icc_provider *provider;
	struct icc_node *n;
	u64 sum_bw;
	u64 max_peak_bw;
	u64 rate;
	u32 agg_avg = 0;
	u32 agg_peak = 0;
	int ret, i;

	qn = src->data;
	provider = src->provider;
	qp = to_qcom_provider(provider);

	list_for_each_entry(n, &provider->nodes, node_list)
		provider->aggregate(n, 0, n->avg_bw, n->peak_bw,
				    &agg_avg, &agg_peak);

	sum_bw = icc_units_to_bps(agg_avg);
	max_peak_bw = icc_units_to_bps(agg_peak);

	/* send bandwidth request message to the RPM processor */
	if (qn->mas_rpm_id != -1) {
		ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE,
					    RPM_BUS_MASTER_REQ,
					    qn->mas_rpm_id,
					    sum_bw);
		if (ret) {
			pr_err("qcom_icc_rpm_smd_send mas %d error %d\n",
			       qn->mas_rpm_id, ret);
			return ret;
		}
	}

	if (qn->slv_rpm_id != -1) {
		ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE,
					    RPM_BUS_SLAVE_REQ,
					    qn->slv_rpm_id,
					    sum_bw);
		if (ret) {
			pr_err("qcom_icc_rpm_smd_send slv error %d\n",
			       ret);
			return ret;
		}
	}

	rate = max(sum_bw, max_peak_bw);

	do_div(rate, qn->buswidth);

	if (qn->rate == rate)
		return 0;

	for (i = 0; i < qp->num_clks; i++) {
		ret = clk_set_rate(qp->bus_clks[i].clk, rate);
		if (ret) {
			pr_err("%s clk_set_rate error: %d\n",
			       qp->bus_clks[i].id, ret);
			return ret;
		}
	}

	qn->rate = rate;

	return 0;
}

int qnoc_probe(struct platform_device *pdev, size_t cd_size, int cd_num,
	       const struct clk_bulk_data *cd)
{
	struct device *dev = &pdev->dev;
	const struct qcom_icc_desc *desc;
	struct icc_onecell_data *data;
	struct icc_provider *provider;
	struct qcom_icc_node **qnodes;
	struct qcom_icc_provider *qp;
	struct icc_node *node;
	size_t num_nodes, i;
	int ret;

	/* wait for the RPM proxy */
	if (!qcom_icc_rpm_smd_available())
		return -EPROBE_DEFER;

	desc = of_device_get_match_data(dev);
	if (!desc)
		return -EINVAL;

	qnodes = desc->nodes;
	num_nodes = desc->num_nodes;

	qp = devm_kzalloc(dev, sizeof(*qp), GFP_KERNEL);
	if (!qp)
		return -ENOMEM;

	data = devm_kzalloc(dev, struct_size(data, nodes, num_nodes),
			    GFP_KERNEL);
	if (!data)
		return -ENOMEM;

	qp->bus_clks = devm_kmemdup(dev, cd, cd_size,
				    GFP_KERNEL);
	if (!qp->bus_clks)
		return -ENOMEM;

	qp->num_clks = cd_num;
	ret = devm_clk_bulk_get(dev, qp->num_clks, qp->bus_clks);
	if (ret)
		return ret;

	ret = clk_bulk_prepare_enable(qp->num_clks, qp->bus_clks);
	if (ret)
		return ret;

	provider = &qp->provider;
	INIT_LIST_HEAD(&provider->nodes);
	provider->dev = dev;
	provider->set = qcom_icc_set;
	provider->aggregate = icc_std_aggregate;
	provider->xlate = of_icc_xlate_onecell;
	provider->data = data;

	ret = icc_provider_add(provider);
	if (ret) {
		dev_err(dev, "error adding interconnect provider: %d\n", ret);
		clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
		return ret;
	}

	for (i = 0; i < num_nodes; i++) {
		size_t j;

		node = icc_node_create(qnodes[i]->id);
		if (IS_ERR(node)) {
			ret = PTR_ERR(node);
			goto err;
		}

		node->name = qnodes[i]->name;
		node->data = qnodes[i];
		icc_node_add(node, provider);

		for (j = 0; j < qnodes[i]->num_links; j++)
			icc_link_create(node, qnodes[i]->links[j]);

		data->nodes[i] = node;
	}
	data->num_nodes = num_nodes;

	platform_set_drvdata(pdev, qp);

	return 0;
err:
	icc_nodes_remove(provider);
	clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
	icc_provider_del(provider);

	return ret;
}
EXPORT_SYMBOL(qnoc_probe);

int qnoc_remove(struct platform_device *pdev)
{
	struct qcom_icc_provider *qp = platform_get_drvdata(pdev);

	icc_nodes_remove(&qp->provider);
	clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
	return icc_provider_del(&qp->provider);
}
EXPORT_SYMBOL(qnoc_remove);
Loading