1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2020 Linaro Ltd
7 #include <linux/device.h>
8 #include <linux/interconnect-provider.h>
10 #include <linux/module.h>
11 #include <linux/of_device.h>
12 #include <linux/of_platform.h>
13 #include <linux/platform_device.h>
14 #include <linux/slab.h>
19 static int qcom_icc_set(struct icc_node *src, struct icc_node *dst)
21 struct qcom_icc_provider *qp;
22 struct qcom_icc_node *qn;
23 struct icc_provider *provider;
33 provider = src->provider;
34 qp = to_qcom_provider(provider);
36 list_for_each_entry(n, &provider->nodes, node_list)
37 provider->aggregate(n, 0, n->avg_bw, n->peak_bw,
40 sum_bw = icc_units_to_bps(agg_avg);
41 max_peak_bw = icc_units_to_bps(agg_peak);
43 /* send bandwidth request message to the RPM processor */
44 if (qn->mas_rpm_id != -1) {
45 ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE,
50 pr_err("qcom_icc_rpm_smd_send mas %d error %d\n",
56 if (qn->slv_rpm_id != -1) {
57 ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE,
62 pr_err("qcom_icc_rpm_smd_send slv %d error %d\n",
68 rate = max(sum_bw, max_peak_bw);
70 do_div(rate, qn->buswidth);
75 for (i = 0; i < qp->num_clks; i++) {
76 ret = clk_set_rate(qp->bus_clks[i].clk, rate);
78 pr_err("%s clk_set_rate error: %d\n",
79 qp->bus_clks[i].id, ret);
89 int qnoc_probe(struct platform_device *pdev, size_t cd_size, int cd_num,
90 const struct clk_bulk_data *cd)
92 struct device *dev = &pdev->dev;
93 const struct qcom_icc_desc *desc;
94 struct icc_onecell_data *data;
95 struct icc_provider *provider;
96 struct qcom_icc_node **qnodes;
97 struct qcom_icc_provider *qp;
98 struct icc_node *node;
102 /* wait for the RPM proxy */
103 if (!qcom_icc_rpm_smd_available())
104 return -EPROBE_DEFER;
106 desc = of_device_get_match_data(dev);
110 qnodes = desc->nodes;
111 num_nodes = desc->num_nodes;
113 qp = devm_kzalloc(dev, sizeof(*qp), GFP_KERNEL);
117 data = devm_kzalloc(dev, struct_size(data, nodes, num_nodes),
122 qp->bus_clks = devm_kmemdup(dev, cd, cd_size,
127 qp->num_clks = cd_num;
128 ret = devm_clk_bulk_get(dev, qp->num_clks, qp->bus_clks);
132 ret = clk_bulk_prepare_enable(qp->num_clks, qp->bus_clks);
136 provider = &qp->provider;
137 INIT_LIST_HEAD(&provider->nodes);
139 provider->set = qcom_icc_set;
140 provider->aggregate = icc_std_aggregate;
141 provider->xlate = of_icc_xlate_onecell;
142 provider->data = data;
144 ret = icc_provider_add(provider);
146 dev_err(dev, "error adding interconnect provider: %d\n", ret);
147 clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
151 for (i = 0; i < num_nodes; i++) {
154 node = icc_node_create(qnodes[i]->id);
160 node->name = qnodes[i]->name;
161 node->data = qnodes[i];
162 icc_node_add(node, provider);
164 for (j = 0; j < qnodes[i]->num_links; j++)
165 icc_link_create(node, qnodes[i]->links[j]);
167 data->nodes[i] = node;
169 data->num_nodes = num_nodes;
171 platform_set_drvdata(pdev, qp);
175 icc_nodes_remove(provider);
176 clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
177 icc_provider_del(provider);
181 EXPORT_SYMBOL(qnoc_probe);
183 int qnoc_remove(struct platform_device *pdev)
185 struct qcom_icc_provider *qp = platform_get_drvdata(pdev);
187 icc_nodes_remove(&qp->provider);
188 clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
189 return icc_provider_del(&qp->provider);
191 EXPORT_SYMBOL(qnoc_remove);