Merge tag 'block-5.11-2021-01-10' of git://git.kernel.dk/linux-block
[linux/fpc-iii.git] / drivers / interconnect / imx / imx.c
blobc770951a909c905475ae1d81d1aa3150806d3cd5
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Interconnect framework driver for i.MX SoC
5 * Copyright (c) 2019, BayLibre
6 * Copyright (c) 2019-2020, NXP
7 * Author: Alexandre Bailon <abailon@baylibre.com>
8 * Author: Leonard Crestez <leonard.crestez@nxp.com>
9 */
11 #include <linux/device.h>
12 #include <linux/interconnect-provider.h>
13 #include <linux/module.h>
14 #include <linux/of.h>
15 #include <linux/of_platform.h>
16 #include <linux/platform_device.h>
17 #include <linux/pm_qos.h>
19 #include "imx.h"
21 /* private icc_node data */
22 struct imx_icc_node {
23 const struct imx_icc_node_desc *desc;
24 struct device *qos_dev;
25 struct dev_pm_qos_request qos_req;
28 static int imx_icc_node_set(struct icc_node *node)
30 struct device *dev = node->provider->dev;
31 struct imx_icc_node *node_data = node->data;
32 u64 freq;
34 if (!node_data->qos_dev)
35 return 0;
37 freq = (node->avg_bw + node->peak_bw) * node_data->desc->adj->bw_mul;
38 do_div(freq, node_data->desc->adj->bw_div);
39 dev_dbg(dev, "node %s device %s avg_bw %ukBps peak_bw %ukBps min_freq %llukHz\n",
40 node->name, dev_name(node_data->qos_dev),
41 node->avg_bw, node->peak_bw, freq);
43 if (freq > S32_MAX) {
44 dev_err(dev, "%s can't request more than S32_MAX freq\n",
45 node->name);
46 return -ERANGE;
49 dev_pm_qos_update_request(&node_data->qos_req, freq);
51 return 0;
54 static int imx_icc_set(struct icc_node *src, struct icc_node *dst)
56 return imx_icc_node_set(dst);
59 /* imx_icc_node_destroy() - Destroy an imx icc_node, including private data */
60 static void imx_icc_node_destroy(struct icc_node *node)
62 struct imx_icc_node *node_data = node->data;
63 int ret;
65 if (dev_pm_qos_request_active(&node_data->qos_req)) {
66 ret = dev_pm_qos_remove_request(&node_data->qos_req);
67 if (ret)
68 dev_warn(node->provider->dev,
69 "failed to remove qos request for %s\n",
70 dev_name(node_data->qos_dev));
73 put_device(node_data->qos_dev);
74 icc_node_del(node);
75 icc_node_destroy(node->id);
78 static int imx_icc_node_init_qos(struct icc_provider *provider,
79 struct icc_node *node)
81 struct imx_icc_node *node_data = node->data;
82 const struct imx_icc_node_adj_desc *adj = node_data->desc->adj;
83 struct device *dev = provider->dev;
84 struct device_node *dn = NULL;
85 struct platform_device *pdev;
87 if (adj->main_noc) {
88 node_data->qos_dev = dev;
89 dev_dbg(dev, "icc node %s[%d] is main noc itself\n",
90 node->name, node->id);
91 } else {
92 dn = of_parse_phandle(dev->of_node, adj->phandle_name, 0);
93 if (!dn) {
94 dev_warn(dev, "Failed to parse %s\n",
95 adj->phandle_name);
96 return -ENODEV;
98 /* Allow scaling to be disabled on a per-node basis */
99 if (!of_device_is_available(dn)) {
100 dev_warn(dev, "Missing property %s, skip scaling %s\n",
101 adj->phandle_name, node->name);
102 of_node_put(dn);
103 return 0;
106 pdev = of_find_device_by_node(dn);
107 of_node_put(dn);
108 if (!pdev) {
109 dev_warn(dev, "node %s[%d] missing device for %pOF\n",
110 node->name, node->id, dn);
111 return -EPROBE_DEFER;
113 node_data->qos_dev = &pdev->dev;
114 dev_dbg(dev, "node %s[%d] has device node %pOF\n",
115 node->name, node->id, dn);
118 return dev_pm_qos_add_request(node_data->qos_dev,
119 &node_data->qos_req,
120 DEV_PM_QOS_MIN_FREQUENCY, 0);
123 static struct icc_node *imx_icc_node_add(struct icc_provider *provider,
124 const struct imx_icc_node_desc *node_desc)
126 struct device *dev = provider->dev;
127 struct imx_icc_node *node_data;
128 struct icc_node *node;
129 int ret;
131 node = icc_node_create(node_desc->id);
132 if (IS_ERR(node)) {
133 dev_err(dev, "failed to create node %d\n", node_desc->id);
134 return node;
137 if (node->data) {
138 dev_err(dev, "already created node %s id=%d\n",
139 node_desc->name, node_desc->id);
140 return ERR_PTR(-EEXIST);
143 node_data = devm_kzalloc(dev, sizeof(*node_data), GFP_KERNEL);
144 if (!node_data) {
145 icc_node_destroy(node->id);
146 return ERR_PTR(-ENOMEM);
149 node->name = node_desc->name;
150 node->data = node_data;
151 node_data->desc = node_desc;
152 icc_node_add(node, provider);
154 if (node_desc->adj) {
155 ret = imx_icc_node_init_qos(provider, node);
156 if (ret < 0) {
157 imx_icc_node_destroy(node);
158 return ERR_PTR(ret);
162 return node;
165 static void imx_icc_unregister_nodes(struct icc_provider *provider)
167 struct icc_node *node, *tmp;
169 list_for_each_entry_safe(node, tmp, &provider->nodes, node_list)
170 imx_icc_node_destroy(node);
173 static int imx_icc_register_nodes(struct icc_provider *provider,
174 const struct imx_icc_node_desc *descs,
175 int count)
177 struct icc_onecell_data *provider_data = provider->data;
178 int ret;
179 int i;
181 for (i = 0; i < count; i++) {
182 struct icc_node *node;
183 const struct imx_icc_node_desc *node_desc = &descs[i];
184 size_t j;
186 node = imx_icc_node_add(provider, node_desc);
187 if (IS_ERR(node)) {
188 ret = dev_err_probe(provider->dev, PTR_ERR(node),
189 "failed to add %s\n", node_desc->name);
190 goto err;
192 provider_data->nodes[node->id] = node;
194 for (j = 0; j < node_desc->num_links; j++) {
195 ret = icc_link_create(node, node_desc->links[j]);
196 if (ret) {
197 dev_err(provider->dev, "failed to link node %d to %d: %d\n",
198 node->id, node_desc->links[j], ret);
199 goto err;
204 return 0;
206 err:
207 imx_icc_unregister_nodes(provider);
209 return ret;
212 static int get_max_node_id(struct imx_icc_node_desc *nodes, int nodes_count)
214 int i, ret = 0;
216 for (i = 0; i < nodes_count; ++i)
217 if (nodes[i].id > ret)
218 ret = nodes[i].id;
220 return ret;
223 int imx_icc_register(struct platform_device *pdev,
224 struct imx_icc_node_desc *nodes, int nodes_count)
226 struct device *dev = &pdev->dev;
227 struct icc_onecell_data *data;
228 struct icc_provider *provider;
229 int max_node_id;
230 int ret;
232 /* icc_onecell_data is indexed by node_id, unlike nodes param */
233 max_node_id = get_max_node_id(nodes, nodes_count);
234 data = devm_kzalloc(dev, struct_size(data, nodes, max_node_id),
235 GFP_KERNEL);
236 if (!data)
237 return -ENOMEM;
238 data->num_nodes = max_node_id;
240 provider = devm_kzalloc(dev, sizeof(*provider), GFP_KERNEL);
241 if (!provider)
242 return -ENOMEM;
243 provider->set = imx_icc_set;
244 provider->aggregate = icc_std_aggregate;
245 provider->xlate = of_icc_xlate_onecell;
246 provider->data = data;
247 provider->dev = dev->parent;
248 platform_set_drvdata(pdev, provider);
250 ret = icc_provider_add(provider);
251 if (ret) {
252 dev_err(dev, "error adding interconnect provider: %d\n", ret);
253 return ret;
256 ret = imx_icc_register_nodes(provider, nodes, nodes_count);
257 if (ret)
258 goto provider_del;
260 return 0;
262 provider_del:
263 icc_provider_del(provider);
264 return ret;
266 EXPORT_SYMBOL_GPL(imx_icc_register);
268 int imx_icc_unregister(struct platform_device *pdev)
270 struct icc_provider *provider = platform_get_drvdata(pdev);
272 imx_icc_unregister_nodes(provider);
274 return icc_provider_del(provider);
276 EXPORT_SYMBOL_GPL(imx_icc_unregister);
278 MODULE_LICENSE("GPL v2");