0001
0002
0003
0004
0005
0006 #include <linux/interconnect.h>
0007 #include <linux/interconnect-provider.h>
0008 #include <linux/module.h>
0009 #include <linux/of.h>
0010 #include <linux/of_device.h>
0011 #include <linux/slab.h>
0012
0013 #include "bcm-voter.h"
0014 #include "icc-common.h"
0015 #include "icc-rpmh.h"
0016
0017
0018
0019
0020
0021 void qcom_icc_pre_aggregate(struct icc_node *node)
0022 {
0023 size_t i;
0024 struct qcom_icc_node *qn;
0025 struct qcom_icc_provider *qp;
0026
0027 qn = node->data;
0028 qp = to_qcom_provider(node->provider);
0029
0030 for (i = 0; i < QCOM_ICC_NUM_BUCKETS; i++) {
0031 qn->sum_avg[i] = 0;
0032 qn->max_peak[i] = 0;
0033 }
0034
0035 for (i = 0; i < qn->num_bcms; i++)
0036 qcom_icc_bcm_voter_add(qp->voter, qn->bcms[i]);
0037 }
0038 EXPORT_SYMBOL_GPL(qcom_icc_pre_aggregate);
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049 int qcom_icc_aggregate(struct icc_node *node, u32 tag, u32 avg_bw,
0050 u32 peak_bw, u32 *agg_avg, u32 *agg_peak)
0051 {
0052 size_t i;
0053 struct qcom_icc_node *qn;
0054
0055 qn = node->data;
0056
0057 if (!tag)
0058 tag = QCOM_ICC_TAG_ALWAYS;
0059
0060 for (i = 0; i < QCOM_ICC_NUM_BUCKETS; i++) {
0061 if (tag & BIT(i)) {
0062 qn->sum_avg[i] += avg_bw;
0063 qn->max_peak[i] = max_t(u32, qn->max_peak[i], peak_bw);
0064 }
0065
0066 if (node->init_avg || node->init_peak) {
0067 qn->sum_avg[i] = max_t(u64, qn->sum_avg[i], node->init_avg);
0068 qn->max_peak[i] = max_t(u64, qn->max_peak[i], node->init_peak);
0069 }
0070 }
0071
0072 *agg_avg += avg_bw;
0073 *agg_peak = max_t(u32, *agg_peak, peak_bw);
0074
0075 return 0;
0076 }
0077 EXPORT_SYMBOL_GPL(qcom_icc_aggregate);
0078
0079
0080
0081
0082
0083
0084
0085
0086 int qcom_icc_set(struct icc_node *src, struct icc_node *dst)
0087 {
0088 struct qcom_icc_provider *qp;
0089 struct icc_node *node;
0090
0091 if (!src)
0092 node = dst;
0093 else
0094 node = src;
0095
0096 qp = to_qcom_provider(node->provider);
0097
0098 qcom_icc_bcm_voter_commit(qp->voter);
0099
0100 return 0;
0101 }
0102 EXPORT_SYMBOL_GPL(qcom_icc_set);
0103
0104
0105
0106
0107
0108
0109
0110
0111 int qcom_icc_bcm_init(struct qcom_icc_bcm *bcm, struct device *dev)
0112 {
0113 struct qcom_icc_node *qn;
0114 const struct bcm_db *data;
0115 size_t data_count;
0116 int i;
0117
0118
0119 if (bcm->addr)
0120 return 0;
0121
0122 bcm->addr = cmd_db_read_addr(bcm->name);
0123 if (!bcm->addr) {
0124 dev_err(dev, "%s could not find RPMh address\n",
0125 bcm->name);
0126 return -EINVAL;
0127 }
0128
0129 data = cmd_db_read_aux_data(bcm->name, &data_count);
0130 if (IS_ERR(data)) {
0131 dev_err(dev, "%s command db read error (%ld)\n",
0132 bcm->name, PTR_ERR(data));
0133 return PTR_ERR(data);
0134 }
0135 if (!data_count) {
0136 dev_err(dev, "%s command db missing or partial aux data\n",
0137 bcm->name);
0138 return -EINVAL;
0139 }
0140
0141 bcm->aux_data.unit = le32_to_cpu(data->unit);
0142 bcm->aux_data.width = le16_to_cpu(data->width);
0143 bcm->aux_data.vcd = data->vcd;
0144 bcm->aux_data.reserved = data->reserved;
0145 INIT_LIST_HEAD(&bcm->list);
0146 INIT_LIST_HEAD(&bcm->ws_list);
0147
0148 if (!bcm->vote_scale)
0149 bcm->vote_scale = 1000;
0150
0151
0152 for (i = 0; i < bcm->num_nodes; i++) {
0153 qn = bcm->nodes[i];
0154 qn->bcms[qn->num_bcms] = bcm;
0155 qn->num_bcms++;
0156 }
0157
0158 return 0;
0159 }
0160 EXPORT_SYMBOL_GPL(qcom_icc_bcm_init);
0161
0162 int qcom_icc_rpmh_probe(struct platform_device *pdev)
0163 {
0164 const struct qcom_icc_desc *desc;
0165 struct device *dev = &pdev->dev;
0166 struct icc_onecell_data *data;
0167 struct icc_provider *provider;
0168 struct qcom_icc_node * const *qnodes, *qn;
0169 struct qcom_icc_provider *qp;
0170 struct icc_node *node;
0171 size_t num_nodes, i, j;
0172 int ret;
0173
0174 desc = of_device_get_match_data(dev);
0175 if (!desc)
0176 return -EINVAL;
0177
0178 qnodes = desc->nodes;
0179 num_nodes = desc->num_nodes;
0180
0181 qp = devm_kzalloc(dev, sizeof(*qp), GFP_KERNEL);
0182 if (!qp)
0183 return -ENOMEM;
0184
0185 data = devm_kzalloc(dev, struct_size(data, nodes, num_nodes), GFP_KERNEL);
0186 if (!data)
0187 return -ENOMEM;
0188
0189 provider = &qp->provider;
0190 provider->dev = dev;
0191 provider->set = qcom_icc_set;
0192 provider->pre_aggregate = qcom_icc_pre_aggregate;
0193 provider->aggregate = qcom_icc_aggregate;
0194 provider->xlate_extended = qcom_icc_xlate_extended;
0195 INIT_LIST_HEAD(&provider->nodes);
0196 provider->data = data;
0197
0198 qp->dev = dev;
0199 qp->bcms = desc->bcms;
0200 qp->num_bcms = desc->num_bcms;
0201
0202 qp->voter = of_bcm_voter_get(qp->dev, NULL);
0203 if (IS_ERR(qp->voter))
0204 return PTR_ERR(qp->voter);
0205
0206 ret = icc_provider_add(provider);
0207 if (ret)
0208 return ret;
0209
0210 for (i = 0; i < qp->num_bcms; i++)
0211 qcom_icc_bcm_init(qp->bcms[i], dev);
0212
0213 for (i = 0; i < num_nodes; i++) {
0214 qn = qnodes[i];
0215 if (!qn)
0216 continue;
0217
0218 node = icc_node_create(qn->id);
0219 if (IS_ERR(node)) {
0220 ret = PTR_ERR(node);
0221 goto err;
0222 }
0223
0224 node->name = qn->name;
0225 node->data = qn;
0226 icc_node_add(node, provider);
0227
0228 for (j = 0; j < qn->num_links; j++)
0229 icc_link_create(node, qn->links[j]);
0230
0231 data->nodes[i] = node;
0232 }
0233
0234 data->num_nodes = num_nodes;
0235 platform_set_drvdata(pdev, qp);
0236
0237
0238 if (of_get_child_count(dev->of_node) > 0)
0239 return of_platform_populate(dev->of_node, NULL, NULL, dev);
0240
0241 return 0;
0242 err:
0243 icc_nodes_remove(provider);
0244 icc_provider_del(provider);
0245 return ret;
0246 }
0247 EXPORT_SYMBOL_GPL(qcom_icc_rpmh_probe);
0248
0249 int qcom_icc_rpmh_remove(struct platform_device *pdev)
0250 {
0251 struct qcom_icc_provider *qp = platform_get_drvdata(pdev);
0252
0253 icc_nodes_remove(&qp->provider);
0254 return icc_provider_del(&qp->provider);
0255 }
0256 EXPORT_SYMBOL_GPL(qcom_icc_rpmh_remove);
0257
0258 MODULE_LICENSE("GPL v2");