1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Interconnect framework driver for i.MX SoC 4 * 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 */ 10 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> 18 19 #include "imx.h" 20 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; 26 }; 27 28 static int imx_icc_node_set(struct icc_node *node) 29 { 30 struct device *dev = node->provider->dev; 31 struct imx_icc_node *node_data = node->data; 32 u64 freq; 33 34 if (!node_data->qos_dev) 35 return 0; 36 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); 42 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; 47 } 48 49 dev_pm_qos_update_request(&node_data->qos_req, freq); 50 51 return 0; 52 } 53 54 static int imx_icc_set(struct icc_node *src, struct icc_node *dst) 55 { 56 return imx_icc_node_set(dst); 57 } 58 59 /* imx_icc_node_destroy() - Destroy an imx icc_node, including private data */ 60 static void imx_icc_node_destroy(struct icc_node *node) 61 { 62 struct imx_icc_node *node_data = node->data; 63 int ret; 64 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)); 71 } 72 73 put_device(node_data->qos_dev); 74 icc_node_del(node); 75 icc_node_destroy(node->id); 76 } 77 78 static int imx_icc_node_init_qos(struct icc_provider *provider, 79 struct icc_node *node) 80 { 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; 86 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; 97 } 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); 102 return 0; 103 } 104 105 pdev = of_find_device_by_node(dn); 106 of_node_put(dn); 107 if (!pdev) { 108 dev_warn(dev, "node %s[%d] missing device for %pOF\n", 109 node->name, node->id, dn); 110 return -EPROBE_DEFER; 111 } 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); 115 } 116 117 return dev_pm_qos_add_request(node_data->qos_dev, 118 &node_data->qos_req, 119 DEV_PM_QOS_MIN_FREQUENCY, 0); 120 } 121 122 static struct icc_node *imx_icc_node_add(struct icc_provider *provider, 123 const struct imx_icc_node_desc *node_desc) 124 { 125 struct device *dev = provider->dev; 126 struct imx_icc_node *node_data; 127 struct icc_node *node; 128 int ret; 129 130 node = icc_node_create(node_desc->id); 131 if (IS_ERR(node)) { 132 dev_err(dev, "failed to create node %d\n", node_desc->id); 133 return node; 134 } 135 136 if (node->data) { 137 dev_err(dev, "already created node %s id=%d\n", 138 node_desc->name, node_desc->id); 139 return ERR_PTR(-EEXIST); 140 } 141 142 node_data = devm_kzalloc(dev, sizeof(*node_data), GFP_KERNEL); 143 if (!node_data) { 144 icc_node_destroy(node->id); 145 return ERR_PTR(-ENOMEM); 146 } 147 148 node->name = node_desc->name; 149 node->data = node_data; 150 node_data->desc = node_desc; 151 icc_node_add(node, provider); 152 153 if (node_desc->adj) { 154 ret = imx_icc_node_init_qos(provider, node); 155 if (ret < 0) { 156 imx_icc_node_destroy(node); 157 return ERR_PTR(ret); 158 } 159 } 160 161 return node; 162 } 163 164 static void imx_icc_unregister_nodes(struct icc_provider *provider) 165 { 166 struct icc_node *node, *tmp; 167 168 list_for_each_entry_safe(node, tmp, &provider->nodes, node_list) 169 imx_icc_node_destroy(node); 170 } 171 172 static int imx_icc_register_nodes(struct icc_provider *provider, 173 const struct imx_icc_node_desc *descs, 174 int count) 175 { 176 struct icc_onecell_data *provider_data = provider->data; 177 int ret; 178 int i; 179 180 for (i = 0; i < count; i++) { 181 struct icc_node *node; 182 const struct imx_icc_node_desc *node_desc = &descs[i]; 183 size_t j; 184 185 node = imx_icc_node_add(provider, node_desc); 186 if (IS_ERR(node)) { 187 ret = PTR_ERR(node); 188 if (ret != -EPROBE_DEFER) 189 dev_err(provider->dev, "failed to add %s: %d\n", 190 node_desc->name, ret); 191 goto err; 192 } 193 provider_data->nodes[node->id] = node; 194 195 for (j = 0; j < node_desc->num_links; j++) { 196 ret = icc_link_create(node, node_desc->links[j]); 197 if (ret) { 198 dev_err(provider->dev, "failed to link node %d to %d: %d\n", 199 node->id, node_desc->links[j], ret); 200 goto err; 201 } 202 } 203 } 204 205 return 0; 206 207 err: 208 imx_icc_unregister_nodes(provider); 209 210 return ret; 211 } 212 213 static int get_max_node_id(struct imx_icc_node_desc *nodes, int nodes_count) 214 { 215 int i, ret = 0; 216 217 for (i = 0; i < nodes_count; ++i) 218 if (nodes[i].id > ret) 219 ret = nodes[i].id; 220 221 return ret; 222 } 223 224 int imx_icc_register(struct platform_device *pdev, 225 struct imx_icc_node_desc *nodes, int nodes_count) 226 { 227 struct device *dev = &pdev->dev; 228 struct icc_onecell_data *data; 229 struct icc_provider *provider; 230 int max_node_id; 231 int ret; 232 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), 236 GFP_KERNEL); 237 if (!data) 238 return -ENOMEM; 239 data->num_nodes = max_node_id; 240 241 provider = devm_kzalloc(dev, sizeof(*provider), GFP_KERNEL); 242 if (!provider) 243 return -ENOMEM; 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); 250 251 ret = icc_provider_add(provider); 252 if (ret) { 253 dev_err(dev, "error adding interconnect provider: %d\n", ret); 254 return ret; 255 } 256 257 ret = imx_icc_register_nodes(provider, nodes, nodes_count); 258 if (ret) 259 goto provider_del; 260 261 return 0; 262 263 provider_del: 264 icc_provider_del(provider); 265 return ret; 266 } 267 EXPORT_SYMBOL_GPL(imx_icc_register); 268 269 int imx_icc_unregister(struct platform_device *pdev) 270 { 271 struct icc_provider *provider = platform_get_drvdata(pdev); 272 int ret; 273 274 imx_icc_unregister_nodes(provider); 275 276 ret = icc_provider_del(provider); 277 if (ret) 278 return ret; 279 280 return 0; 281 } 282 EXPORT_SYMBOL_GPL(imx_icc_unregister); 283 284 MODULE_LICENSE("GPL v2"); 285