1 // SPDX-License-Identifier: GPL-2.0
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>
11 #include <linux/device.h>
12 #include <linux/interconnect-provider.h>
13 #include <linux/module.h>
15 #include <linux/of_platform.h>
16 #include <linux/platform_device.h>
17 #include <linux/pm_qos.h>
21 /* private icc_node data */
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
;
34 if (!node_data
->qos_dev
)
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
);
44 dev_err(dev
, "%s can't request more than S32_MAX freq\n",
49 dev_pm_qos_update_request(&node_data
->qos_req
, freq
);
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
;
65 if (dev_pm_qos_request_active(&node_data
->qos_req
)) {
66 ret
= dev_pm_qos_remove_request(&node_data
->qos_req
);
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
);
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
;
88 node_data
->qos_dev
= dev
;
89 dev_dbg(dev
, "icc node %s[%d] is main noc itself\n",
90 node
->name
, node
->id
);
92 dn
= of_parse_phandle(dev
->of_node
, adj
->phandle_name
, 0);
94 dev_warn(dev
, "Failed to parse %s\n",
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
);
106 pdev
= of_find_device_by_node(dn
);
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
,
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
;
131 node
= icc_node_create(node_desc
->id
);
133 dev_err(dev
, "failed to create node %d\n", node_desc
->id
);
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
);
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
);
157 imx_icc_node_destroy(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
,
177 struct icc_onecell_data
*provider_data
= provider
->data
;
181 for (i
= 0; i
< count
; i
++) {
182 struct icc_node
*node
;
183 const struct imx_icc_node_desc
*node_desc
= &descs
[i
];
186 node
= imx_icc_node_add(provider
, node_desc
);
188 ret
= dev_err_probe(provider
->dev
, PTR_ERR(node
),
189 "failed to add %s\n", node_desc
->name
);
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
]);
197 dev_err(provider
->dev
, "failed to link node %d to %d: %d\n",
198 node
->id
, node_desc
->links
[j
], ret
);
207 imx_icc_unregister_nodes(provider
);
212 static int get_max_node_id(struct imx_icc_node_desc
*nodes
, int nodes_count
)
216 for (i
= 0; i
< nodes_count
; ++i
)
217 if (nodes
[i
].id
> 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
;
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
),
238 data
->num_nodes
= max_node_id
;
240 provider
= devm_kzalloc(dev
, sizeof(*provider
), GFP_KERNEL
);
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
);
252 dev_err(dev
, "error adding interconnect provider: %d\n", ret
);
256 ret
= imx_icc_register_nodes(provider
, nodes
, nodes_count
);
263 icc_provider_del(provider
);
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");