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 (!dn
|| !of_device_is_available(dn
)) {
100 dev_warn(dev
, "Missing property %s, skip scaling %s\n",
101 adj
->phandle_name
, node
->name
);
105 pdev
= of_find_device_by_node(dn
);
108 dev_warn(dev
, "node %s[%d] missing device for %pOF\n",
109 node
->name
, node
->id
, dn
);
110 return -EPROBE_DEFER
;
112 node_data
->qos_dev
= &pdev
->dev
;
113 dev_dbg(dev
, "node %s[%d] has device node %pOF\n",
114 node
->name
, node
->id
, dn
);
117 return dev_pm_qos_add_request(node_data
->qos_dev
,
119 DEV_PM_QOS_MIN_FREQUENCY
, 0);
122 static struct icc_node
*imx_icc_node_add(struct icc_provider
*provider
,
123 const struct imx_icc_node_desc
*node_desc
)
125 struct device
*dev
= provider
->dev
;
126 struct imx_icc_node
*node_data
;
127 struct icc_node
*node
;
130 node
= icc_node_create(node_desc
->id
);
132 dev_err(dev
, "failed to create node %d\n", node_desc
->id
);
137 dev_err(dev
, "already created node %s id=%d\n",
138 node_desc
->name
, node_desc
->id
);
139 return ERR_PTR(-EEXIST
);
142 node_data
= devm_kzalloc(dev
, sizeof(*node_data
), GFP_KERNEL
);
144 icc_node_destroy(node
->id
);
145 return ERR_PTR(-ENOMEM
);
148 node
->name
= node_desc
->name
;
149 node
->data
= node_data
;
150 node_data
->desc
= node_desc
;
151 icc_node_add(node
, provider
);
153 if (node_desc
->adj
) {
154 ret
= imx_icc_node_init_qos(provider
, node
);
156 imx_icc_node_destroy(node
);
164 static void imx_icc_unregister_nodes(struct icc_provider
*provider
)
166 struct icc_node
*node
, *tmp
;
168 list_for_each_entry_safe(node
, tmp
, &provider
->nodes
, node_list
)
169 imx_icc_node_destroy(node
);
172 static int imx_icc_register_nodes(struct icc_provider
*provider
,
173 const struct imx_icc_node_desc
*descs
,
176 struct icc_onecell_data
*provider_data
= provider
->data
;
180 for (i
= 0; i
< count
; i
++) {
181 struct icc_node
*node
;
182 const struct imx_icc_node_desc
*node_desc
= &descs
[i
];
185 node
= imx_icc_node_add(provider
, node_desc
);
188 if (ret
!= -EPROBE_DEFER
)
189 dev_err(provider
->dev
, "failed to add %s: %d\n",
190 node_desc
->name
, ret
);
193 provider_data
->nodes
[node
->id
] = node
;
195 for (j
= 0; j
< node_desc
->num_links
; j
++) {
196 ret
= icc_link_create(node
, node_desc
->links
[j
]);
198 dev_err(provider
->dev
, "failed to link node %d to %d: %d\n",
199 node
->id
, node_desc
->links
[j
], ret
);
208 imx_icc_unregister_nodes(provider
);
213 static int get_max_node_id(struct imx_icc_node_desc
*nodes
, int nodes_count
)
217 for (i
= 0; i
< nodes_count
; ++i
)
218 if (nodes
[i
].id
> ret
)
224 int imx_icc_register(struct platform_device
*pdev
,
225 struct imx_icc_node_desc
*nodes
, int nodes_count
)
227 struct device
*dev
= &pdev
->dev
;
228 struct icc_onecell_data
*data
;
229 struct icc_provider
*provider
;
233 /* icc_onecell_data is indexed by node_id, unlike nodes param */
234 max_node_id
= get_max_node_id(nodes
, nodes_count
);
235 data
= devm_kzalloc(dev
, struct_size(data
, nodes
, max_node_id
),
239 data
->num_nodes
= max_node_id
;
241 provider
= devm_kzalloc(dev
, sizeof(*provider
), GFP_KERNEL
);
244 provider
->set
= imx_icc_set
;
245 provider
->aggregate
= icc_std_aggregate
;
246 provider
->xlate
= of_icc_xlate_onecell
;
247 provider
->data
= data
;
248 provider
->dev
= dev
->parent
;
249 platform_set_drvdata(pdev
, provider
);
251 ret
= icc_provider_add(provider
);
253 dev_err(dev
, "error adding interconnect provider: %d\n", ret
);
257 ret
= imx_icc_register_nodes(provider
, nodes
, nodes_count
);
264 icc_provider_del(provider
);
267 EXPORT_SYMBOL_GPL(imx_icc_register
);
269 int imx_icc_unregister(struct platform_device
*pdev
)
271 struct icc_provider
*provider
= platform_get_drvdata(pdev
);
274 imx_icc_unregister_nodes(provider
);
276 ret
= icc_provider_del(provider
);
282 EXPORT_SYMBOL_GPL(imx_icc_unregister
);
284 MODULE_LICENSE("GPL v2");