Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

interconnect: qcom: Consolidate interconnect RPM support

Add RPM based interconnect driver implements the set and aggregate
functionalities that translates bandwidth requests into RPM messages.
These modules provide a common set of functionalities for all
Qualcomm RPM based interconnect providers and should help reduce code
duplication when adding new providers.

Signed-off-by: Jun Nie <jun.nie@linaro.org>
Link: https://lore.kernel.org/r/20201204075345.5161-2-jun.nie@linaro.org
Signed-off-by: Georgi Djakov <georgi.djakov@linaro.org>

authored by

Jun Nie and committed by
Georgi Djakov
62feb14e 5c8fe583

+275 -232
+1 -1
drivers/interconnect/qcom/Makefile
··· 10 10 qnoc-sdm845-objs := sdm845.o 11 11 qnoc-sm8150-objs := sm8150.o 12 12 qnoc-sm8250-objs := sm8250.o 13 - icc-smd-rpm-objs := smd-rpm.o 13 + icc-smd-rpm-objs := smd-rpm.o icc-rpm.o 14 14 15 15 obj-$(CONFIG_INTERCONNECT_QCOM_BCM_VOTER) += icc-bcm-voter.o 16 16 obj-$(CONFIG_INTERCONNECT_QCOM_MSM8916) += qnoc-msm8916.o
+191
drivers/interconnect/qcom/icc-rpm.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (C) 2020 Linaro Ltd 4 + */ 5 + 6 + #include <linux/clk.h> 7 + #include <linux/device.h> 8 + #include <linux/interconnect-provider.h> 9 + #include <linux/io.h> 10 + #include <linux/module.h> 11 + #include <linux/of_device.h> 12 + #include <linux/of_platform.h> 13 + #include <linux/platform_device.h> 14 + #include <linux/slab.h> 15 + 16 + #include "smd-rpm.h" 17 + #include "icc-rpm.h" 18 + 19 + static int qcom_icc_set(struct icc_node *src, struct icc_node *dst) 20 + { 21 + struct qcom_icc_provider *qp; 22 + struct qcom_icc_node *qn; 23 + struct icc_provider *provider; 24 + struct icc_node *n; 25 + u64 sum_bw; 26 + u64 max_peak_bw; 27 + u64 rate; 28 + u32 agg_avg = 0; 29 + u32 agg_peak = 0; 30 + int ret, i; 31 + 32 + qn = src->data; 33 + provider = src->provider; 34 + qp = to_qcom_provider(provider); 35 + 36 + list_for_each_entry(n, &provider->nodes, node_list) 37 + provider->aggregate(n, 0, n->avg_bw, n->peak_bw, 38 + &agg_avg, &agg_peak); 39 + 40 + sum_bw = icc_units_to_bps(agg_avg); 41 + max_peak_bw = icc_units_to_bps(agg_peak); 42 + 43 + /* send bandwidth request message to the RPM processor */ 44 + if (qn->mas_rpm_id != -1) { 45 + ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE, 46 + RPM_BUS_MASTER_REQ, 47 + qn->mas_rpm_id, 48 + sum_bw); 49 + if (ret) { 50 + pr_err("qcom_icc_rpm_smd_send mas %d error %d\n", 51 + qn->mas_rpm_id, ret); 52 + return ret; 53 + } 54 + } 55 + 56 + if (qn->slv_rpm_id != -1) { 57 + ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE, 58 + RPM_BUS_SLAVE_REQ, 59 + qn->slv_rpm_id, 60 + sum_bw); 61 + if (ret) { 62 + pr_err("qcom_icc_rpm_smd_send slv error %d\n", 63 + ret); 64 + return ret; 65 + } 66 + } 67 + 68 + rate = max(sum_bw, max_peak_bw); 69 + 70 + do_div(rate, qn->buswidth); 71 + 72 + if (qn->rate == rate) 73 + return 0; 74 + 75 + for (i = 0; i < qp->num_clks; i++) { 76 + ret = clk_set_rate(qp->bus_clks[i].clk, rate); 77 + if (ret) { 78 + pr_err("%s clk_set_rate error: %d\n", 79 + qp->bus_clks[i].id, ret); 80 + return ret; 81 + } 82 + } 83 + 84 + qn->rate = rate; 85 + 86 + return 0; 87 + } 88 + 89 + int qnoc_probe(struct platform_device *pdev, size_t cd_size, int cd_num, 90 + const struct clk_bulk_data *cd) 91 + { 92 + struct device *dev = &pdev->dev; 93 + const struct qcom_icc_desc *desc; 94 + struct icc_onecell_data *data; 95 + struct icc_provider *provider; 96 + struct qcom_icc_node **qnodes; 97 + struct qcom_icc_provider *qp; 98 + struct icc_node *node; 99 + size_t num_nodes, i; 100 + int ret; 101 + 102 + /* wait for the RPM proxy */ 103 + if (!qcom_icc_rpm_smd_available()) 104 + return -EPROBE_DEFER; 105 + 106 + desc = of_device_get_match_data(dev); 107 + if (!desc) 108 + return -EINVAL; 109 + 110 + qnodes = desc->nodes; 111 + num_nodes = desc->num_nodes; 112 + 113 + qp = devm_kzalloc(dev, sizeof(*qp), GFP_KERNEL); 114 + if (!qp) 115 + return -ENOMEM; 116 + 117 + data = devm_kzalloc(dev, struct_size(data, nodes, num_nodes), 118 + GFP_KERNEL); 119 + if (!data) 120 + return -ENOMEM; 121 + 122 + qp->bus_clks = devm_kmemdup(dev, cd, cd_size, 123 + GFP_KERNEL); 124 + if (!qp->bus_clks) 125 + return -ENOMEM; 126 + 127 + qp->num_clks = cd_num; 128 + ret = devm_clk_bulk_get(dev, qp->num_clks, qp->bus_clks); 129 + if (ret) 130 + return ret; 131 + 132 + ret = clk_bulk_prepare_enable(qp->num_clks, qp->bus_clks); 133 + if (ret) 134 + return ret; 135 + 136 + provider = &qp->provider; 137 + INIT_LIST_HEAD(&provider->nodes); 138 + provider->dev = dev; 139 + provider->set = qcom_icc_set; 140 + provider->aggregate = icc_std_aggregate; 141 + provider->xlate = of_icc_xlate_onecell; 142 + provider->data = data; 143 + 144 + ret = icc_provider_add(provider); 145 + if (ret) { 146 + dev_err(dev, "error adding interconnect provider: %d\n", ret); 147 + clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks); 148 + return ret; 149 + } 150 + 151 + for (i = 0; i < num_nodes; i++) { 152 + size_t j; 153 + 154 + node = icc_node_create(qnodes[i]->id); 155 + if (IS_ERR(node)) { 156 + ret = PTR_ERR(node); 157 + goto err; 158 + } 159 + 160 + node->name = qnodes[i]->name; 161 + node->data = qnodes[i]; 162 + icc_node_add(node, provider); 163 + 164 + for (j = 0; j < qnodes[i]->num_links; j++) 165 + icc_link_create(node, qnodes[i]->links[j]); 166 + 167 + data->nodes[i] = node; 168 + } 169 + data->num_nodes = num_nodes; 170 + 171 + platform_set_drvdata(pdev, qp); 172 + 173 + return 0; 174 + err: 175 + icc_nodes_remove(provider); 176 + clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks); 177 + icc_provider_del(provider); 178 + 179 + return ret; 180 + } 181 + EXPORT_SYMBOL(qnoc_probe); 182 + 183 + int qnoc_remove(struct platform_device *pdev) 184 + { 185 + struct qcom_icc_provider *qp = platform_get_drvdata(pdev); 186 + 187 + icc_nodes_remove(&qp->provider); 188 + clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks); 189 + return icc_provider_del(&qp->provider); 190 + } 191 + EXPORT_SYMBOL(qnoc_remove);
+73
drivers/interconnect/qcom/icc-rpm.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (C) 2020 Linaro Ltd 4 + */ 5 + 6 + #ifndef __DRIVERS_INTERCONNECT_QCOM_ICC_RPM_H 7 + #define __DRIVERS_INTERCONNECT_QCOM_ICC_RPM_H 8 + 9 + #define RPM_BUS_MASTER_REQ 0x73616d62 10 + #define RPM_BUS_SLAVE_REQ 0x766c7362 11 + 12 + #define QCOM_MAX_LINKS 12 13 + 14 + #define to_qcom_provider(_provider) \ 15 + container_of(_provider, struct qcom_icc_provider, provider) 16 + 17 + /** 18 + * struct qcom_icc_provider - Qualcomm specific interconnect provider 19 + * @provider: generic interconnect provider 20 + * @bus_clks: the clk_bulk_data table of bus clocks 21 + * @num_clks: the total number of clk_bulk_data entries 22 + */ 23 + struct qcom_icc_provider { 24 + struct icc_provider provider; 25 + struct clk_bulk_data *bus_clks; 26 + int num_clks; 27 + }; 28 + 29 + /** 30 + * struct qcom_icc_node - Qualcomm specific interconnect nodes 31 + * @name: the node name used in debugfs 32 + * @id: a unique node identifier 33 + * @links: an array of nodes where we can go next while traversing 34 + * @num_links: the total number of @links 35 + * @buswidth: width of the interconnect between a node and the bus (bytes) 36 + * @mas_rpm_id: RPM id for devices that are bus masters 37 + * @slv_rpm_id: RPM id for devices that are bus slaves 38 + * @rate: current bus clock rate in Hz 39 + */ 40 + struct qcom_icc_node { 41 + unsigned char *name; 42 + u16 id; 43 + u16 links[QCOM_MAX_LINKS]; 44 + u16 num_links; 45 + u16 buswidth; 46 + int mas_rpm_id; 47 + int slv_rpm_id; 48 + u64 rate; 49 + }; 50 + 51 + struct qcom_icc_desc { 52 + struct qcom_icc_node **nodes; 53 + size_t num_nodes; 54 + }; 55 + 56 + #define DEFINE_QNODE(_name, _id, _buswidth, _mas_rpm_id, _slv_rpm_id, \ 57 + ...) \ 58 + static struct qcom_icc_node _name = { \ 59 + .name = #_name, \ 60 + .id = _id, \ 61 + .buswidth = _buswidth, \ 62 + .mas_rpm_id = _mas_rpm_id, \ 63 + .slv_rpm_id = _slv_rpm_id, \ 64 + .num_links = ARRAY_SIZE(((int[]){ __VA_ARGS__ })), \ 65 + .links = { __VA_ARGS__ }, \ 66 + } 67 + 68 + 69 + int qnoc_probe(struct platform_device *pdev, size_t cd_size, int cd_num, 70 + const struct clk_bulk_data *cd); 71 + int qnoc_remove(struct platform_device *pdev); 72 + 73 + #endif
+10 -231
drivers/interconnect/qcom/msm8916.c
··· 15 15 #include <dt-bindings/interconnect/qcom,msm8916.h> 16 16 17 17 #include "smd-rpm.h" 18 - 19 - #define RPM_BUS_MASTER_REQ 0x73616d62 20 - #define RPM_BUS_SLAVE_REQ 0x766c7362 18 + #include "icc-rpm.h" 21 19 22 20 enum { 23 21 MSM8916_BIMC_SNOC_MAS = 1, ··· 105 107 MSM8916_SNOC_PNOC_SLV, 106 108 }; 107 109 108 - #define to_msm8916_provider(_provider) \ 109 - container_of(_provider, struct msm8916_icc_provider, provider) 110 - 111 110 static const struct clk_bulk_data msm8916_bus_clocks[] = { 112 111 { .id = "bus" }, 113 112 { .id = "bus_a" }, 114 113 }; 115 - 116 - /** 117 - * struct msm8916_icc_provider - Qualcomm specific interconnect provider 118 - * @provider: generic interconnect provider 119 - * @bus_clks: the clk_bulk_data table of bus clocks 120 - * @num_clks: the total number of clk_bulk_data entries 121 - */ 122 - struct msm8916_icc_provider { 123 - struct icc_provider provider; 124 - struct clk_bulk_data *bus_clks; 125 - int num_clks; 126 - }; 127 - 128 - #define MSM8916_MAX_LINKS 8 129 - 130 - /** 131 - * struct msm8916_icc_node - Qualcomm specific interconnect nodes 132 - * @name: the node name used in debugfs 133 - * @id: a unique node identifier 134 - * @links: an array of nodes where we can go next while traversing 135 - * @num_links: the total number of @links 136 - * @buswidth: width of the interconnect between a node and the bus (bytes) 137 - * @mas_rpm_id: RPM ID for devices that are bus masters 138 - * @slv_rpm_id: RPM ID for devices that are bus slaves 139 - * @rate: current bus clock rate in Hz 140 - */ 141 - struct msm8916_icc_node { 142 - unsigned char *name; 143 - u16 id; 144 - u16 links[MSM8916_MAX_LINKS]; 145 - u16 num_links; 146 - u16 buswidth; 147 - int mas_rpm_id; 148 - int slv_rpm_id; 149 - u64 rate; 150 - }; 151 - 152 - struct msm8916_icc_desc { 153 - struct msm8916_icc_node **nodes; 154 - size_t num_nodes; 155 - }; 156 - 157 - #define DEFINE_QNODE(_name, _id, _buswidth, _mas_rpm_id, _slv_rpm_id, \ 158 - ...) \ 159 - static struct msm8916_icc_node _name = { \ 160 - .name = #_name, \ 161 - .id = _id, \ 162 - .buswidth = _buswidth, \ 163 - .mas_rpm_id = _mas_rpm_id, \ 164 - .slv_rpm_id = _slv_rpm_id, \ 165 - .num_links = ARRAY_SIZE(((int[]){ __VA_ARGS__ })), \ 166 - .links = { __VA_ARGS__ }, \ 167 - } 168 114 169 115 DEFINE_QNODE(bimc_snoc_mas, MSM8916_BIMC_SNOC_MAS, 8, -1, -1, MSM8916_BIMC_SNOC_SLV); 170 116 DEFINE_QNODE(bimc_snoc_slv, MSM8916_BIMC_SNOC_SLV, 8, -1, -1, MSM8916_SNOC_INT_0, MSM8916_SNOC_INT_1); ··· 196 254 DEFINE_QNODE(snoc_pcnoc_mas, MSM8916_SNOC_PNOC_MAS, 8, -1, -1, MSM8916_SNOC_PNOC_SLV); 197 255 DEFINE_QNODE(snoc_pcnoc_slv, MSM8916_SNOC_PNOC_SLV, 8, -1, -1, MSM8916_PNOC_INT_0); 198 256 199 - static struct msm8916_icc_node *msm8916_snoc_nodes[] = { 257 + static struct qcom_icc_node *msm8916_snoc_nodes[] = { 200 258 [BIMC_SNOC_SLV] = &bimc_snoc_slv, 201 259 [MASTER_JPEG] = &mas_jpeg, 202 260 [MASTER_MDP_PORT0] = &mas_mdp, ··· 225 283 [SNOC_QDSS_INT] = &qdss_int, 226 284 }; 227 285 228 - static struct msm8916_icc_desc msm8916_snoc = { 286 + static struct qcom_icc_desc msm8916_snoc = { 229 287 .nodes = msm8916_snoc_nodes, 230 288 .num_nodes = ARRAY_SIZE(msm8916_snoc_nodes), 231 289 }; 232 290 233 - static struct msm8916_icc_node *msm8916_bimc_nodes[] = { 291 + static struct qcom_icc_node *msm8916_bimc_nodes[] = { 234 292 [BIMC_SNOC_MAS] = &bimc_snoc_mas, 235 293 [MASTER_AMPSS_M0] = &mas_apss, 236 294 [MASTER_GRAPHICS_3D] = &mas_gfx, ··· 242 300 [SNOC_BIMC_1_SLV] = &snoc_bimc_1_slv, 243 301 }; 244 302 245 - static struct msm8916_icc_desc msm8916_bimc = { 303 + static struct qcom_icc_desc msm8916_bimc = { 246 304 .nodes = msm8916_bimc_nodes, 247 305 .num_nodes = ARRAY_SIZE(msm8916_bimc_nodes), 248 306 }; 249 307 250 - static struct msm8916_icc_node *msm8916_pcnoc_nodes[] = { 308 + static struct qcom_icc_node *msm8916_pcnoc_nodes[] = { 251 309 [MASTER_BLSP_1] = &mas_blsp_1, 252 310 [MASTER_DEHR] = &mas_dehr, 253 311 [MASTER_LPASS] = &mas_audio, ··· 300 358 [SNOC_PCNOC_SLV] = &snoc_pcnoc_slv, 301 359 }; 302 360 303 - static struct msm8916_icc_desc msm8916_pcnoc = { 361 + static struct qcom_icc_desc msm8916_pcnoc = { 304 362 .nodes = msm8916_pcnoc_nodes, 305 363 .num_nodes = ARRAY_SIZE(msm8916_pcnoc_nodes), 306 364 }; 307 365 308 - static int msm8916_icc_set(struct icc_node *src, struct icc_node *dst) 309 - { 310 - struct msm8916_icc_provider *qp; 311 - struct msm8916_icc_node *qn; 312 - u64 sum_bw, max_peak_bw, rate; 313 - u32 agg_avg = 0, agg_peak = 0; 314 - struct icc_provider *provider; 315 - struct icc_node *n; 316 - int ret, i; 317 - 318 - qn = src->data; 319 - provider = src->provider; 320 - qp = to_msm8916_provider(provider); 321 - 322 - list_for_each_entry(n, &provider->nodes, node_list) 323 - provider->aggregate(n, 0, n->avg_bw, n->peak_bw, 324 - &agg_avg, &agg_peak); 325 - 326 - sum_bw = icc_units_to_bps(agg_avg); 327 - max_peak_bw = icc_units_to_bps(agg_peak); 328 - 329 - /* send bandwidth request message to the RPM processor */ 330 - if (qn->mas_rpm_id != -1) { 331 - ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE, 332 - RPM_BUS_MASTER_REQ, 333 - qn->mas_rpm_id, 334 - sum_bw); 335 - if (ret) { 336 - pr_err("qcom_icc_rpm_smd_send mas %d error %d\n", 337 - qn->mas_rpm_id, ret); 338 - return ret; 339 - } 340 - } 341 - 342 - if (qn->slv_rpm_id != -1) { 343 - ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE, 344 - RPM_BUS_SLAVE_REQ, 345 - qn->slv_rpm_id, 346 - sum_bw); 347 - if (ret) { 348 - pr_err("qcom_icc_rpm_smd_send slv error %d\n", 349 - ret); 350 - return ret; 351 - } 352 - } 353 - 354 - rate = max(sum_bw, max_peak_bw); 355 - 356 - do_div(rate, qn->buswidth); 357 - 358 - if (qn->rate == rate) 359 - return 0; 360 - 361 - for (i = 0; i < qp->num_clks; i++) { 362 - ret = clk_set_rate(qp->bus_clks[i].clk, rate); 363 - if (ret) { 364 - pr_err("%s clk_set_rate error: %d\n", 365 - qp->bus_clks[i].id, ret); 366 - return ret; 367 - } 368 - } 369 - 370 - qn->rate = rate; 371 - 372 - return 0; 373 - } 374 - 375 366 static int msm8916_qnoc_probe(struct platform_device *pdev) 376 367 { 377 - const struct msm8916_icc_desc *desc; 378 - struct msm8916_icc_node **qnodes; 379 - struct msm8916_icc_provider *qp; 380 - struct device *dev = &pdev->dev; 381 - struct icc_onecell_data *data; 382 - struct icc_provider *provider; 383 - struct icc_node *node; 384 - size_t num_nodes, i; 385 - int ret; 386 - 387 - /* wait for the RPM proxy */ 388 - if (!qcom_icc_rpm_smd_available()) 389 - return -EPROBE_DEFER; 390 - 391 - desc = of_device_get_match_data(dev); 392 - if (!desc) 393 - return -EINVAL; 394 - 395 - qnodes = desc->nodes; 396 - num_nodes = desc->num_nodes; 397 - 398 - qp = devm_kzalloc(dev, sizeof(*qp), GFP_KERNEL); 399 - if (!qp) 400 - return -ENOMEM; 401 - 402 - data = devm_kzalloc(dev, struct_size(data, nodes, num_nodes), 403 - GFP_KERNEL); 404 - if (!data) 405 - return -ENOMEM; 406 - 407 - qp->bus_clks = devm_kmemdup(dev, msm8916_bus_clocks, 408 - sizeof(msm8916_bus_clocks), GFP_KERNEL); 409 - if (!qp->bus_clks) 410 - return -ENOMEM; 411 - 412 - qp->num_clks = ARRAY_SIZE(msm8916_bus_clocks); 413 - ret = devm_clk_bulk_get(dev, qp->num_clks, qp->bus_clks); 414 - if (ret) 415 - return ret; 416 - 417 - ret = clk_bulk_prepare_enable(qp->num_clks, qp->bus_clks); 418 - if (ret) 419 - return ret; 420 - 421 - provider = &qp->provider; 422 - INIT_LIST_HEAD(&provider->nodes); 423 - provider->dev = dev; 424 - provider->set = msm8916_icc_set; 425 - provider->aggregate = icc_std_aggregate; 426 - provider->xlate = of_icc_xlate_onecell; 427 - provider->data = data; 428 - 429 - ret = icc_provider_add(provider); 430 - if (ret) { 431 - dev_err(dev, "error adding interconnect provider: %d\n", ret); 432 - clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks); 433 - return ret; 434 - } 435 - 436 - for (i = 0; i < num_nodes; i++) { 437 - size_t j; 438 - 439 - node = icc_node_create(qnodes[i]->id); 440 - if (IS_ERR(node)) { 441 - ret = PTR_ERR(node); 442 - goto err; 443 - } 444 - 445 - node->name = qnodes[i]->name; 446 - node->data = qnodes[i]; 447 - icc_node_add(node, provider); 448 - 449 - for (j = 0; j < qnodes[i]->num_links; j++) 450 - icc_link_create(node, qnodes[i]->links[j]); 451 - 452 - data->nodes[i] = node; 453 - } 454 - data->num_nodes = num_nodes; 455 - 456 - platform_set_drvdata(pdev, qp); 457 - 458 - return 0; 459 - 460 - err: 461 - icc_nodes_remove(provider); 462 - icc_provider_del(provider); 463 - clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks); 464 - 465 - return ret; 466 - } 467 - 468 - static int msm8916_qnoc_remove(struct platform_device *pdev) 469 - { 470 - struct msm8916_icc_provider *qp = platform_get_drvdata(pdev); 471 - 472 - icc_nodes_remove(&qp->provider); 473 - clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks); 474 - return icc_provider_del(&qp->provider); 368 + return qnoc_probe(pdev, sizeof(msm8916_bus_clocks), 369 + ARRAY_SIZE(msm8916_bus_clocks), msm8916_bus_clocks); 475 370 } 476 371 477 372 static const struct of_device_id msm8916_noc_of_match[] = { ··· 321 542 322 543 static struct platform_driver msm8916_noc_driver = { 323 544 .probe = msm8916_qnoc_probe, 324 - .remove = msm8916_qnoc_remove, 545 + .remove = qnoc_remove, 325 546 .driver = { 326 547 .name = "qnoc-msm8916", 327 548 .of_match_table = msm8916_noc_of_match,