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 (!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; 104 } 105 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; 112 } 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); 116 } 117 118 return dev_pm_qos_add_request(node_data->qos_dev, 119 &node_data->qos_req, 120 DEV_PM_QOS_MIN_FREQUENCY, 0); 121 } 122 123 static struct icc_node *imx_icc_node_add(struct icc_provider *provider, 124 const struct imx_icc_node_desc *node_desc) 125 { 126 struct device *dev = provider->dev; 127 struct imx_icc_node *node_data; 128 struct icc_node *node; 129 int ret; 130 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; 135 } 136 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); 141 } 142 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); 147 } 148 149 node->name = node_desc->name; 150 node->data = node_data; 151 node_data->desc = node_desc; 152 icc_node_add(node, provider); 153 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); 159 } 160 } 161 162 return node; 163 } 164 165 static void imx_icc_unregister_nodes(struct icc_provider *provider) 166 { 167 struct icc_node *node, *tmp; 168 169 list_for_each_entry_safe(node, tmp, &provider->nodes, node_list) 170 imx_icc_node_destroy(node); 171 } 172 173 static int imx_icc_register_nodes(struct icc_provider *provider, 174 const struct imx_icc_node_desc *descs, 175 int count) 176 { 177 struct icc_onecell_data *provider_data = provider->data; 178 int ret; 179 int i; 180 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; 185 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; 191 } 192 provider_data->nodes[node->id] = node; 193 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; 200 } 201 } 202 } 203 204 return 0; 205 206 err: 207 imx_icc_unregister_nodes(provider); 208 209 return ret; 210 } 211 212 static int get_max_node_id(struct imx_icc_node_desc *nodes, int nodes_count) 213 { 214 int i, ret = 0; 215 216 for (i = 0; i < nodes_count; ++i) 217 if (nodes[i].id > ret) 218 ret = nodes[i].id; 219 220 return ret; 221 } 222 223 int imx_icc_register(struct platform_device *pdev, 224 struct imx_icc_node_desc *nodes, int nodes_count) 225 { 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; 231 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; 239 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); 249 250 ret = icc_provider_add(provider); 251 if (ret) { 252 dev_err(dev, "error adding interconnect provider: %d\n", ret); 253 return ret; 254 } 255 256 ret = imx_icc_register_nodes(provider, nodes, nodes_count); 257 if (ret) 258 goto provider_del; 259 260 return 0; 261 262 provider_del: 263 icc_provider_del(provider); 264 return ret; 265 } 266 EXPORT_SYMBOL_GPL(imx_icc_register); 267 268 int imx_icc_unregister(struct platform_device *pdev) 269 { 270 struct icc_provider *provider = platform_get_drvdata(pdev); 271 272 imx_icc_unregister_nodes(provider); 273 274 return icc_provider_del(provider); 275 } 276 EXPORT_SYMBOL_GPL(imx_icc_unregister); 277 278 MODULE_LICENSE("GPL v2"); 279