Lines Matching +full:opp +full:- +full:level
1 // SPDX-License-Identifier: GPL-2.0
5 * Copyright (C) 2018-2021 ARM Ltd.
8 #define pr_fmt(fmt) "SCMI Notifications PERF - " fmt
13 #include <linux/io-64-nonatomic-hi-lo.h>
81 __le32 level; member
110 } opp[]; member
161 struct scmi_opp opp[MAX_OPPS]; member
186 ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0, in scmi_perf_attributes_get()
191 attr = t->rx.buf; in scmi_perf_attributes_get()
193 ret = ph->xops->do_xfer(ph, t); in scmi_perf_attributes_get()
195 u16 flags = le16_to_cpu(attr->flags); in scmi_perf_attributes_get()
197 pi->num_domains = le16_to_cpu(attr->num_domains); in scmi_perf_attributes_get()
198 pi->power_scale_mw = POWER_SCALE_IN_MILLIWATT(flags); in scmi_perf_attributes_get()
199 pi->stats_addr = le32_to_cpu(attr->stats_addr_low) | in scmi_perf_attributes_get()
200 (u64)le32_to_cpu(attr->stats_addr_high) << 32; in scmi_perf_attributes_get()
201 pi->stats_size = le32_to_cpu(attr->stats_size); in scmi_perf_attributes_get()
204 ph->xops->xfer_put(ph, t); in scmi_perf_attributes_get()
216 ret = ph->xops->xfer_get_init(ph, PERF_DOMAIN_ATTRIBUTES, in scmi_perf_domain_attributes_get()
221 put_unaligned_le32(domain, t->tx.buf); in scmi_perf_domain_attributes_get()
222 attr = t->rx.buf; in scmi_perf_domain_attributes_get()
224 ret = ph->xops->do_xfer(ph, t); in scmi_perf_domain_attributes_get()
226 u32 flags = le32_to_cpu(attr->flags); in scmi_perf_domain_attributes_get()
228 dom_info->set_limits = SUPPORTS_SET_LIMITS(flags); in scmi_perf_domain_attributes_get()
229 dom_info->set_perf = SUPPORTS_SET_PERF_LVL(flags); in scmi_perf_domain_attributes_get()
230 dom_info->perf_limit_notify = SUPPORTS_PERF_LIMIT_NOTIFY(flags); in scmi_perf_domain_attributes_get()
231 dom_info->perf_level_notify = SUPPORTS_PERF_LEVEL_NOTIFY(flags); in scmi_perf_domain_attributes_get()
232 dom_info->perf_fastchannels = SUPPORTS_PERF_FASTCHANNELS(flags); in scmi_perf_domain_attributes_get()
233 dom_info->sustained_freq_khz = in scmi_perf_domain_attributes_get()
234 le32_to_cpu(attr->sustained_freq_khz); in scmi_perf_domain_attributes_get()
235 dom_info->sustained_perf_level = in scmi_perf_domain_attributes_get()
236 le32_to_cpu(attr->sustained_perf_level); in scmi_perf_domain_attributes_get()
237 if (!dom_info->sustained_freq_khz || in scmi_perf_domain_attributes_get()
238 !dom_info->sustained_perf_level) in scmi_perf_domain_attributes_get()
240 dom_info->mult_factor = 1000; in scmi_perf_domain_attributes_get()
242 dom_info->mult_factor = in scmi_perf_domain_attributes_get()
243 (dom_info->sustained_freq_khz * 1000) / in scmi_perf_domain_attributes_get()
244 dom_info->sustained_perf_level; in scmi_perf_domain_attributes_get()
245 strlcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE); in scmi_perf_domain_attributes_get()
248 ph->xops->xfer_put(ph, t); in scmi_perf_domain_attributes_get()
256 return t1->perf - t2->perf; in opp_cmp_func()
267 struct scmi_opp *opp; in scmi_perf_describe_levels_get() local
271 ret = ph->xops->xfer_get_init(ph, PERF_DESCRIBE_LEVELS, in scmi_perf_describe_levels_get()
276 dom_info = t->tx.buf; in scmi_perf_describe_levels_get()
277 level_info = t->rx.buf; in scmi_perf_describe_levels_get()
280 dom_info->domain = cpu_to_le32(domain); in scmi_perf_describe_levels_get()
282 dom_info->level_index = cpu_to_le32(tot_opp_cnt); in scmi_perf_describe_levels_get()
284 ret = ph->xops->do_xfer(ph, t); in scmi_perf_describe_levels_get()
288 num_returned = le16_to_cpu(level_info->num_returned); in scmi_perf_describe_levels_get()
289 num_remaining = le16_to_cpu(level_info->num_remaining); in scmi_perf_describe_levels_get()
291 dev_err(ph->dev, "No. of OPPs exceeded MAX_OPPS"); in scmi_perf_describe_levels_get()
295 opp = &perf_dom->opp[tot_opp_cnt]; in scmi_perf_describe_levels_get()
296 for (cnt = 0; cnt < num_returned; cnt++, opp++) { in scmi_perf_describe_levels_get()
297 opp->perf = le32_to_cpu(level_info->opp[cnt].perf_val); in scmi_perf_describe_levels_get()
298 opp->power = le32_to_cpu(level_info->opp[cnt].power); in scmi_perf_describe_levels_get()
299 opp->trans_latency_us = le16_to_cpu in scmi_perf_describe_levels_get()
300 (level_info->opp[cnt].transition_latency_us); in scmi_perf_describe_levels_get()
302 dev_dbg(ph->dev, "Level %d Power %d Latency %dus\n", in scmi_perf_describe_levels_get()
303 opp->perf, opp->power, opp->trans_latency_us); in scmi_perf_describe_levels_get()
308 ph->xops->reset_rx_to_maxsz(ph, t); in scmi_perf_describe_levels_get()
315 perf_dom->opp_count = tot_opp_cnt; in scmi_perf_describe_levels_get()
316 ph->xops->xfer_put(ph, t); in scmi_perf_describe_levels_get()
318 sort(perf_dom->opp, tot_opp_cnt, sizeof(*opp), opp_cmp_func, NULL); in scmi_perf_describe_levels_get()
326 if (db->mask) \
327 val = ioread##w(db->addr) & db->mask; \
328 iowrite##w((u##w)db->set | val, db->addr); \
333 if (!db || !db->addr) in scmi_perf_fc_ring_db()
336 if (db->width == 1) in scmi_perf_fc_ring_db()
338 else if (db->width == 2) in scmi_perf_fc_ring_db()
340 else if (db->width == 4) in scmi_perf_fc_ring_db()
342 else /* db->width == 8 */ in scmi_perf_fc_ring_db()
349 if (db->mask) in scmi_perf_fc_ring_db()
350 val = ioread64_hi_lo(db->addr) & db->mask; in scmi_perf_fc_ring_db()
351 iowrite64_hi_lo(db->set | val, db->addr); in scmi_perf_fc_ring_db()
363 ret = ph->xops->xfer_get_init(ph, PERF_LIMITS_SET, in scmi_perf_mb_limits_set()
368 limits = t->tx.buf; in scmi_perf_mb_limits_set()
369 limits->domain = cpu_to_le32(domain); in scmi_perf_mb_limits_set()
370 limits->max_level = cpu_to_le32(max_perf); in scmi_perf_mb_limits_set()
371 limits->min_level = cpu_to_le32(min_perf); in scmi_perf_mb_limits_set()
373 ret = ph->xops->do_xfer(ph, t); in scmi_perf_mb_limits_set()
375 ph->xops->xfer_put(ph, t); in scmi_perf_mb_limits_set()
382 struct scmi_perf_info *pi = ph->get_priv(ph); in scmi_perf_limits_set()
383 struct perf_dom_info *dom = pi->dom_info + domain; in scmi_perf_limits_set()
385 if (dom->fc_info && dom->fc_info->limit_set_addr) { in scmi_perf_limits_set()
386 iowrite32(max_perf, dom->fc_info->limit_set_addr); in scmi_perf_limits_set()
387 iowrite32(min_perf, dom->fc_info->limit_set_addr + 4); in scmi_perf_limits_set()
388 scmi_perf_fc_ring_db(dom->fc_info->limit_set_db); in scmi_perf_limits_set()
402 ret = ph->xops->xfer_get_init(ph, PERF_LIMITS_GET, in scmi_perf_mb_limits_get()
407 put_unaligned_le32(domain, t->tx.buf); in scmi_perf_mb_limits_get()
409 ret = ph->xops->do_xfer(ph, t); in scmi_perf_mb_limits_get()
411 limits = t->rx.buf; in scmi_perf_mb_limits_get()
413 *max_perf = le32_to_cpu(limits->max_level); in scmi_perf_mb_limits_get()
414 *min_perf = le32_to_cpu(limits->min_level); in scmi_perf_mb_limits_get()
417 ph->xops->xfer_put(ph, t); in scmi_perf_mb_limits_get()
424 struct scmi_perf_info *pi = ph->get_priv(ph); in scmi_perf_limits_get()
425 struct perf_dom_info *dom = pi->dom_info + domain; in scmi_perf_limits_get()
427 if (dom->fc_info && dom->fc_info->limit_get_addr) { in scmi_perf_limits_get()
428 *max_perf = ioread32(dom->fc_info->limit_get_addr); in scmi_perf_limits_get()
429 *min_perf = ioread32(dom->fc_info->limit_get_addr + 4); in scmi_perf_limits_get()
437 u32 domain, u32 level, bool poll) in scmi_perf_mb_level_set() argument
443 ret = ph->xops->xfer_get_init(ph, PERF_LEVEL_SET, sizeof(*lvl), 0, &t); in scmi_perf_mb_level_set()
447 t->hdr.poll_completion = poll; in scmi_perf_mb_level_set()
448 lvl = t->tx.buf; in scmi_perf_mb_level_set()
449 lvl->domain = cpu_to_le32(domain); in scmi_perf_mb_level_set()
450 lvl->level = cpu_to_le32(level); in scmi_perf_mb_level_set()
452 ret = ph->xops->do_xfer(ph, t); in scmi_perf_mb_level_set()
454 ph->xops->xfer_put(ph, t); in scmi_perf_mb_level_set()
459 u32 domain, u32 level, bool poll) in scmi_perf_level_set() argument
461 struct scmi_perf_info *pi = ph->get_priv(ph); in scmi_perf_level_set()
462 struct perf_dom_info *dom = pi->dom_info + domain; in scmi_perf_level_set()
464 if (dom->fc_info && dom->fc_info->level_set_addr) { in scmi_perf_level_set()
465 iowrite32(level, dom->fc_info->level_set_addr); in scmi_perf_level_set()
466 scmi_perf_fc_ring_db(dom->fc_info->level_set_db); in scmi_perf_level_set()
470 return scmi_perf_mb_level_set(ph, domain, level, poll); in scmi_perf_level_set()
474 u32 domain, u32 *level, bool poll) in scmi_perf_mb_level_get() argument
479 ret = ph->xops->xfer_get_init(ph, PERF_LEVEL_GET, in scmi_perf_mb_level_get()
484 t->hdr.poll_completion = poll; in scmi_perf_mb_level_get()
485 put_unaligned_le32(domain, t->tx.buf); in scmi_perf_mb_level_get()
487 ret = ph->xops->do_xfer(ph, t); in scmi_perf_mb_level_get()
489 *level = get_unaligned_le32(t->rx.buf); in scmi_perf_mb_level_get()
491 ph->xops->xfer_put(ph, t); in scmi_perf_mb_level_get()
496 u32 domain, u32 *level, bool poll) in scmi_perf_level_get() argument
498 struct scmi_perf_info *pi = ph->get_priv(ph); in scmi_perf_level_get()
499 struct perf_dom_info *dom = pi->dom_info + domain; in scmi_perf_level_get()
501 if (dom->fc_info && dom->fc_info->level_get_addr) { in scmi_perf_level_get()
502 *level = ioread32(dom->fc_info->level_get_addr); in scmi_perf_level_get()
506 return scmi_perf_mb_level_get(ph, domain, level, poll); in scmi_perf_level_get()
517 ret = ph->xops->xfer_get_init(ph, message_id, sizeof(*notify), 0, &t); in scmi_perf_level_limits_notify()
521 notify = t->tx.buf; in scmi_perf_level_limits_notify()
522 notify->domain = cpu_to_le32(domain); in scmi_perf_level_limits_notify()
523 notify->notify_enable = enable ? cpu_to_le32(BIT(0)) : 0; in scmi_perf_level_limits_notify()
525 ret = ph->xops->do_xfer(ph, t); in scmi_perf_level_limits_notify()
527 ph->xops->xfer_put(ph, t); in scmi_perf_level_limits_notify()
558 ret = ph->xops->xfer_get_init(ph, PERF_DESCRIBE_FASTCHANNEL, in scmi_perf_domain_desc_fc()
563 info = t->tx.buf; in scmi_perf_domain_desc_fc()
564 info->domain = cpu_to_le32(domain); in scmi_perf_domain_desc_fc()
565 info->message_id = cpu_to_le32(message_id); in scmi_perf_domain_desc_fc()
567 ret = ph->xops->do_xfer(ph, t); in scmi_perf_domain_desc_fc()
571 resp = t->rx.buf; in scmi_perf_domain_desc_fc()
572 flags = le32_to_cpu(resp->attr); in scmi_perf_domain_desc_fc()
573 size = le32_to_cpu(resp->chan_size); in scmi_perf_domain_desc_fc()
577 phys_addr = le32_to_cpu(resp->chan_addr_low); in scmi_perf_domain_desc_fc()
578 phys_addr |= (u64)le32_to_cpu(resp->chan_addr_high) << 32; in scmi_perf_domain_desc_fc()
579 addr = devm_ioremap(ph->dev, phys_addr, size); in scmi_perf_domain_desc_fc()
585 db = devm_kzalloc(ph->dev, sizeof(*db), GFP_KERNEL); in scmi_perf_domain_desc_fc()
590 phys_addr = le32_to_cpu(resp->db_addr_low); in scmi_perf_domain_desc_fc()
591 phys_addr |= (u64)le32_to_cpu(resp->db_addr_high) << 32; in scmi_perf_domain_desc_fc()
592 addr = devm_ioremap(ph->dev, phys_addr, size); in scmi_perf_domain_desc_fc()
596 db->addr = addr; in scmi_perf_domain_desc_fc()
597 db->width = size; in scmi_perf_domain_desc_fc()
598 db->set = le32_to_cpu(resp->db_set_lmask); in scmi_perf_domain_desc_fc()
599 db->set |= (u64)le32_to_cpu(resp->db_set_hmask) << 32; in scmi_perf_domain_desc_fc()
600 db->mask = le32_to_cpu(resp->db_preserve_lmask); in scmi_perf_domain_desc_fc()
601 db->mask |= (u64)le32_to_cpu(resp->db_preserve_hmask) << 32; in scmi_perf_domain_desc_fc()
605 ph->xops->xfer_put(ph, t); in scmi_perf_domain_desc_fc()
613 fc = devm_kzalloc(ph->dev, sizeof(*fc), GFP_KERNEL); in scmi_perf_domain_init_fc()
618 &fc->level_set_addr, &fc->level_set_db); in scmi_perf_domain_init_fc()
620 &fc->level_get_addr, NULL); in scmi_perf_domain_init_fc()
622 &fc->limit_set_addr, &fc->limit_set_db); in scmi_perf_domain_init_fc()
624 &fc->limit_get_addr, NULL); in scmi_perf_domain_init_fc()
633 if (of_parse_phandle_with_args(dev->of_node, "clocks", "#clock-cells", in scmi_dev_domain_id()
635 return -EINVAL; in scmi_dev_domain_id()
645 struct scmi_opp *opp; in scmi_dvfs_device_opps_add() local
647 struct scmi_perf_info *pi = ph->get_priv(ph); in scmi_dvfs_device_opps_add()
653 dom = pi->dom_info + domain; in scmi_dvfs_device_opps_add()
655 for (opp = dom->opp, idx = 0; idx < dom->opp_count; idx++, opp++) { in scmi_dvfs_device_opps_add()
656 freq = opp->perf * dom->mult_factor; in scmi_dvfs_device_opps_add()
660 dev_warn(dev, "failed to add opp %luHz\n", freq); in scmi_dvfs_device_opps_add()
662 while (idx-- > 0) { in scmi_dvfs_device_opps_add()
663 freq = (--opp)->perf * dom->mult_factor; in scmi_dvfs_device_opps_add()
677 struct scmi_perf_info *pi = ph->get_priv(ph); in scmi_dvfs_transition_latency_get()
683 dom = pi->dom_info + domain; in scmi_dvfs_transition_latency_get()
685 return dom->opp[dom->opp_count - 1].trans_latency_us * 1000; in scmi_dvfs_transition_latency_get()
691 struct scmi_perf_info *pi = ph->get_priv(ph); in scmi_dvfs_freq_set()
692 struct perf_dom_info *dom = pi->dom_info + domain; in scmi_dvfs_freq_set()
694 return scmi_perf_level_set(ph, domain, freq / dom->mult_factor, poll); in scmi_dvfs_freq_set()
701 u32 level; in scmi_dvfs_freq_get() local
702 struct scmi_perf_info *pi = ph->get_priv(ph); in scmi_dvfs_freq_get()
703 struct perf_dom_info *dom = pi->dom_info + domain; in scmi_dvfs_freq_get()
705 ret = scmi_perf_level_get(ph, domain, &level, poll); in scmi_dvfs_freq_get()
707 *freq = level * dom->mult_factor; in scmi_dvfs_freq_get()
716 struct scmi_perf_info *pi = ph->get_priv(ph); in scmi_dvfs_est_power_get()
719 int idx, ret = -EINVAL; in scmi_dvfs_est_power_get()
720 struct scmi_opp *opp; in scmi_dvfs_est_power_get() local
722 dom = pi->dom_info + domain; in scmi_dvfs_est_power_get()
724 return -EIO; in scmi_dvfs_est_power_get()
726 for (opp = dom->opp, idx = 0; idx < dom->opp_count; idx++, opp++) { in scmi_dvfs_est_power_get()
727 opp_freq = opp->perf * dom->mult_factor; in scmi_dvfs_est_power_get()
732 *power = opp->power; in scmi_dvfs_est_power_get()
744 struct scmi_perf_info *pi = ph->get_priv(ph); in scmi_fast_switch_possible()
746 dom = pi->dom_info + scmi_dev_domain_id(dev); in scmi_fast_switch_possible()
748 return dom->fc_info && dom->fc_info->level_set_addr; in scmi_fast_switch_possible()
753 struct scmi_perf_info *pi = ph->get_priv(ph); in scmi_power_scale_mw_get()
755 return pi->power_scale_mw; in scmi_power_scale_mw_get()
779 return -EINVAL; in scmi_perf_set_notify_enabled()
784 pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n", in scmi_perf_set_notify_enabled()
806 r->timestamp = timestamp; in scmi_perf_fill_custom_report()
807 r->agent_id = le32_to_cpu(p->agent_id); in scmi_perf_fill_custom_report()
808 r->domain_id = le32_to_cpu(p->domain_id); in scmi_perf_fill_custom_report()
809 r->range_max = le32_to_cpu(p->range_max); in scmi_perf_fill_custom_report()
810 r->range_min = le32_to_cpu(p->range_min); in scmi_perf_fill_custom_report()
811 *src_id = r->domain_id; in scmi_perf_fill_custom_report()
823 r->timestamp = timestamp; in scmi_perf_fill_custom_report()
824 r->agent_id = le32_to_cpu(p->agent_id); in scmi_perf_fill_custom_report()
825 r->domain_id = le32_to_cpu(p->domain_id); in scmi_perf_fill_custom_report()
826 r->performance_level = le32_to_cpu(p->performance_level); in scmi_perf_fill_custom_report()
827 *src_id = r->domain_id; in scmi_perf_fill_custom_report()
840 struct scmi_perf_info *pi = ph->get_priv(ph); in scmi_perf_get_num_sources()
843 return -EINVAL; in scmi_perf_get_num_sources()
845 return pi->num_domains; in scmi_perf_get_num_sources()
880 ph->xops->version_get(ph, &version); in scmi_perf_protocol_init()
882 dev_dbg(ph->dev, "Performance Version %d.%d\n", in scmi_perf_protocol_init()
885 pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL); in scmi_perf_protocol_init()
887 return -ENOMEM; in scmi_perf_protocol_init()
891 pinfo->dom_info = devm_kcalloc(ph->dev, pinfo->num_domains, in scmi_perf_protocol_init()
892 sizeof(*pinfo->dom_info), GFP_KERNEL); in scmi_perf_protocol_init()
893 if (!pinfo->dom_info) in scmi_perf_protocol_init()
894 return -ENOMEM; in scmi_perf_protocol_init()
896 for (domain = 0; domain < pinfo->num_domains; domain++) { in scmi_perf_protocol_init()
897 struct perf_dom_info *dom = pinfo->dom_info + domain; in scmi_perf_protocol_init()
902 if (dom->perf_fastchannels) in scmi_perf_protocol_init()
903 scmi_perf_domain_init_fc(ph, domain, &dom->fc_info); in scmi_perf_protocol_init()
906 pinfo->version = version; in scmi_perf_protocol_init()
908 return ph->set_priv(ph, pinfo); in scmi_perf_protocol_init()