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 = dev_err_probe(provider->dev, PTR_ERR(node), 188 "failed to add %s\n", node_desc->name); 189 goto err; 190 } 191 provider_data->nodes[node->id] = node; 192 193 for (j = 0; j < node_desc->num_links; j++) { 194 ret = icc_link_create(node, node_desc->links[j]); 195 if (ret) { 196 dev_err(provider->dev, "failed to link node %d to %d: %d\n", 197 node->id, node_desc->links[j], ret); 198 goto err; 199 } 200 } 201 } 202 203 return 0; 204 205 err: 206 imx_icc_unregister_nodes(provider); 207 208 return ret; 209 } 210 211 static int get_max_node_id(struct imx_icc_node_desc *nodes, int nodes_count) 212 { 213 int i, ret = 0; 214 215 for (i = 0; i < nodes_count; ++i) 216 if (nodes[i].id > ret) 217 ret = nodes[i].id; 218 219 return ret; 220 } 221 222 int imx_icc_register(struct platform_device *pdev, 223 struct imx_icc_node_desc *nodes, int nodes_count) 224 { 225 struct device *dev = &pdev->dev; 226 struct icc_onecell_data *data; 227 struct icc_provider *provider; 228 int max_node_id; 229 int ret; 230 231 /* icc_onecell_data is indexed by node_id, unlike nodes param */ 232 max_node_id = get_max_node_id(nodes, nodes_count); 233 data = devm_kzalloc(dev, struct_size(data, nodes, max_node_id), 234 GFP_KERNEL); 235 if (!data) 236 return -ENOMEM; 237 data->num_nodes = max_node_id; 238 239 provider = devm_kzalloc(dev, sizeof(*provider), GFP_KERNEL); 240 if (!provider) 241 return -ENOMEM; 242 provider->set = imx_icc_set; 243 provider->aggregate = icc_std_aggregate; 244 provider->xlate = of_icc_xlate_onecell; 245 provider->data = data; 246 provider->dev = dev->parent; 247 platform_set_drvdata(pdev, provider); 248 249 ret = icc_provider_add(provider); 250 if (ret) { 251 dev_err(dev, "error adding interconnect provider: %d\n", ret); 252 return ret; 253 } 254 255 ret = imx_icc_register_nodes(provider, nodes, nodes_count); 256 if (ret) 257 goto provider_del; 258 259 return 0; 260 261 provider_del: 262 icc_provider_del(provider); 263 return ret; 264 } 265 EXPORT_SYMBOL_GPL(imx_icc_register); 266 267 int imx_icc_unregister(struct platform_device *pdev) 268 { 269 struct icc_provider *provider = platform_get_drvdata(pdev); 270 271 imx_icc_unregister_nodes(provider); 272 273 return icc_provider_del(provider); 274 } 275 EXPORT_SYMBOL_GPL(imx_icc_unregister); 276 277 MODULE_LICENSE("GPL v2"); 278