gpio: rcar: Fix runtime PM imbalance on error
[linux/fpc-iii.git] / drivers / interconnect / qcom / icc-rpmh.c
blob3ac5182c9ab2103bcc557e0f49b9f9fb0bf90b81
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2020, The Linux Foundation. All rights reserved.
4 */
6 #include <linux/interconnect.h>
7 #include <linux/interconnect-provider.h>
8 #include <linux/module.h>
10 #include "bcm-voter.h"
11 #include "icc-rpmh.h"
13 /**
14 * qcom_icc_pre_aggregate - cleans up stale values from prior icc_set
15 * @node: icc node to operate on
17 void qcom_icc_pre_aggregate(struct icc_node *node)
19 size_t i;
20 struct qcom_icc_node *qn;
22 qn = node->data;
24 for (i = 0; i < QCOM_ICC_NUM_BUCKETS; i++) {
25 qn->sum_avg[i] = 0;
26 qn->max_peak[i] = 0;
29 EXPORT_SYMBOL_GPL(qcom_icc_pre_aggregate);
31 /**
32 * qcom_icc_aggregate - aggregate bw for buckets indicated by tag
33 * @node: node to aggregate
34 * @tag: tag to indicate which buckets to aggregate
35 * @avg_bw: new bw to sum aggregate
36 * @peak_bw: new bw to max aggregate
37 * @agg_avg: existing aggregate avg bw val
38 * @agg_peak: existing aggregate peak bw val
40 int qcom_icc_aggregate(struct icc_node *node, u32 tag, u32 avg_bw,
41 u32 peak_bw, u32 *agg_avg, u32 *agg_peak)
43 size_t i;
44 struct qcom_icc_node *qn;
45 struct qcom_icc_provider *qp;
47 qn = node->data;
48 qp = to_qcom_provider(node->provider);
50 if (!tag)
51 tag = QCOM_ICC_TAG_ALWAYS;
53 for (i = 0; i < QCOM_ICC_NUM_BUCKETS; i++) {
54 if (tag & BIT(i)) {
55 qn->sum_avg[i] += avg_bw;
56 qn->max_peak[i] = max_t(u32, qn->max_peak[i], peak_bw);
60 *agg_avg += avg_bw;
61 *agg_peak = max_t(u32, *agg_peak, peak_bw);
63 for (i = 0; i < qn->num_bcms; i++)
64 qcom_icc_bcm_voter_add(qp->voter, qn->bcms[i]);
66 return 0;
68 EXPORT_SYMBOL_GPL(qcom_icc_aggregate);
70 /**
71 * qcom_icc_set - set the constraints based on path
72 * @src: source node for the path to set constraints on
73 * @dst: destination node for the path to set constraints on
75 * Return: 0 on success, or an error code otherwise
77 int qcom_icc_set(struct icc_node *src, struct icc_node *dst)
79 struct qcom_icc_provider *qp;
80 struct icc_node *node;
82 if (!src)
83 node = dst;
84 else
85 node = src;
87 qp = to_qcom_provider(node->provider);
89 qcom_icc_bcm_voter_commit(qp->voter);
91 return 0;
93 EXPORT_SYMBOL_GPL(qcom_icc_set);
95 /**
96 * qcom_icc_bcm_init - populates bcm aux data and connect qnodes
97 * @bcm: bcm to be initialized
98 * @dev: associated provider device
100 * Return: 0 on success, or an error code otherwise
102 int qcom_icc_bcm_init(struct qcom_icc_bcm *bcm, struct device *dev)
104 struct qcom_icc_node *qn;
105 const struct bcm_db *data;
106 size_t data_count;
107 int i;
109 /* BCM is already initialised*/
110 if (bcm->addr)
111 return 0;
113 bcm->addr = cmd_db_read_addr(bcm->name);
114 if (!bcm->addr) {
115 dev_err(dev, "%s could not find RPMh address\n",
116 bcm->name);
117 return -EINVAL;
120 data = cmd_db_read_aux_data(bcm->name, &data_count);
121 if (IS_ERR(data)) {
122 dev_err(dev, "%s command db read error (%ld)\n",
123 bcm->name, PTR_ERR(data));
124 return PTR_ERR(data);
126 if (!data_count) {
127 dev_err(dev, "%s command db missing or partial aux data\n",
128 bcm->name);
129 return -EINVAL;
132 bcm->aux_data.unit = le32_to_cpu(data->unit);
133 bcm->aux_data.width = le16_to_cpu(data->width);
134 bcm->aux_data.vcd = data->vcd;
135 bcm->aux_data.reserved = data->reserved;
136 INIT_LIST_HEAD(&bcm->list);
137 INIT_LIST_HEAD(&bcm->ws_list);
139 /* Link Qnodes to their respective BCMs */
140 for (i = 0; i < bcm->num_nodes; i++) {
141 qn = bcm->nodes[i];
142 qn->bcms[qn->num_bcms] = bcm;
143 qn->num_bcms++;
146 return 0;
148 EXPORT_SYMBOL_GPL(qcom_icc_bcm_init);
150 MODULE_LICENSE("GPL v2");