^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * System Control and Management Interface (SCMI) Performance Protocol
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2018-2020 ARM Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #define pr_fmt(fmt) "SCMI Notifications PERF - " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/bits.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/io-64-nonatomic-hi-lo.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/pm_opp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/scmi_protocol.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/sort.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include "common.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include "notify.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) enum scmi_performance_protocol_cmd {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) PERF_DOMAIN_ATTRIBUTES = 0x3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) PERF_DESCRIBE_LEVELS = 0x4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) PERF_LIMITS_SET = 0x5,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) PERF_LIMITS_GET = 0x6,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) PERF_LEVEL_SET = 0x7,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) PERF_LEVEL_GET = 0x8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) PERF_NOTIFY_LIMITS = 0x9,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) PERF_NOTIFY_LEVEL = 0xa,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) PERF_DESCRIBE_FASTCHANNEL = 0xb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) struct scmi_opp {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) u32 perf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) u32 power;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) u32 trans_latency_us;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) struct scmi_msg_resp_perf_attributes {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) __le16 num_domains;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) __le16 flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define POWER_SCALE_IN_MILLIWATT(x) ((x) & BIT(0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) __le32 stats_addr_low;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) __le32 stats_addr_high;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) __le32 stats_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) struct scmi_msg_resp_perf_domain_attributes {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) __le32 flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #define SUPPORTS_SET_LIMITS(x) ((x) & BIT(31))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #define SUPPORTS_SET_PERF_LVL(x) ((x) & BIT(30))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #define SUPPORTS_PERF_LIMIT_NOTIFY(x) ((x) & BIT(29))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #define SUPPORTS_PERF_LEVEL_NOTIFY(x) ((x) & BIT(28))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) #define SUPPORTS_PERF_FASTCHANNELS(x) ((x) & BIT(27))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) __le32 rate_limit_us;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) __le32 sustained_freq_khz;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) __le32 sustained_perf_level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) u8 name[SCMI_MAX_STR_SIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) struct scmi_msg_perf_describe_levels {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) __le32 domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) __le32 level_index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) struct scmi_perf_set_limits {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) __le32 domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) __le32 max_level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) __le32 min_level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) struct scmi_perf_get_limits {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) __le32 max_level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) __le32 min_level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) struct scmi_perf_set_level {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) __le32 domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) __le32 level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) struct scmi_perf_notify_level_or_limits {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) __le32 domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) __le32 notify_enable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) struct scmi_perf_limits_notify_payld {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) __le32 agent_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) __le32 domain_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) __le32 range_max;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) __le32 range_min;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) struct scmi_perf_level_notify_payld {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) __le32 agent_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) __le32 domain_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) __le32 performance_level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) struct scmi_msg_resp_perf_describe_levels {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) __le16 num_returned;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) __le16 num_remaining;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) __le32 perf_val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) __le32 power;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) __le16 transition_latency_us;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) __le16 reserved;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) } opp[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) struct scmi_perf_get_fc_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) __le32 domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) __le32 message_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) struct scmi_msg_resp_perf_desc_fc {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) __le32 attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) #define SUPPORTS_DOORBELL(x) ((x) & BIT(0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) #define DOORBELL_REG_WIDTH(x) FIELD_GET(GENMASK(2, 1), (x))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) __le32 rate_limit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) __le32 chan_addr_low;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) __le32 chan_addr_high;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) __le32 chan_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) __le32 db_addr_low;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) __le32 db_addr_high;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) __le32 db_set_lmask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) __le32 db_set_hmask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) __le32 db_preserve_lmask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) __le32 db_preserve_hmask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) struct scmi_fc_db_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) int width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) u64 set;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) u64 mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) void __iomem *addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) struct scmi_fc_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) void __iomem *level_set_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) void __iomem *limit_set_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) void __iomem *level_get_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) void __iomem *limit_get_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) struct scmi_fc_db_info *level_set_db;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) struct scmi_fc_db_info *limit_set_db;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) struct perf_dom_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) bool set_limits;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) bool set_perf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) bool perf_limit_notify;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) bool perf_level_notify;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) bool perf_fastchannels;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) u32 opp_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) u32 sustained_freq_khz;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) u32 sustained_perf_level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) u32 mult_factor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) char name[SCMI_MAX_STR_SIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) struct scmi_opp opp[MAX_OPPS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) struct scmi_fc_info *fc_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) struct scmi_perf_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) u32 version;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) int num_domains;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) bool power_scale_mw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) u64 stats_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) u32 stats_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) struct perf_dom_info *dom_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) static enum scmi_performance_protocol_cmd evt_2_cmd[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) PERF_NOTIFY_LIMITS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) PERF_NOTIFY_LEVEL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) static int scmi_perf_attributes_get(const struct scmi_protocol_handle *ph,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) struct scmi_perf_info *pi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) struct scmi_xfer *t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) struct scmi_msg_resp_perf_attributes *attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) sizeof(*attr), &t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) attr = t->rx.buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) ret = ph->xops->do_xfer(ph, t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) if (!ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) u16 flags = le16_to_cpu(attr->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) pi->num_domains = le16_to_cpu(attr->num_domains);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) pi->power_scale_mw = POWER_SCALE_IN_MILLIWATT(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) pi->stats_addr = le32_to_cpu(attr->stats_addr_low) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) (u64)le32_to_cpu(attr->stats_addr_high) << 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) pi->stats_size = le32_to_cpu(attr->stats_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) ph->xops->xfer_put(ph, t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) u32 domain, struct perf_dom_info *dom_info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) struct scmi_xfer *t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) struct scmi_msg_resp_perf_domain_attributes *attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) ret = ph->xops->xfer_get_init(ph, PERF_DOMAIN_ATTRIBUTES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) sizeof(domain), sizeof(*attr), &t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) put_unaligned_le32(domain, t->tx.buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) attr = t->rx.buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) ret = ph->xops->do_xfer(ph, t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) if (!ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) u32 flags = le32_to_cpu(attr->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) dom_info->set_limits = SUPPORTS_SET_LIMITS(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) dom_info->set_perf = SUPPORTS_SET_PERF_LVL(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) dom_info->perf_limit_notify = SUPPORTS_PERF_LIMIT_NOTIFY(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) dom_info->perf_level_notify = SUPPORTS_PERF_LEVEL_NOTIFY(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) dom_info->perf_fastchannels = SUPPORTS_PERF_FASTCHANNELS(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) dom_info->sustained_freq_khz =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) le32_to_cpu(attr->sustained_freq_khz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) dom_info->sustained_perf_level =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) le32_to_cpu(attr->sustained_perf_level);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) if (!dom_info->sustained_freq_khz ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) !dom_info->sustained_perf_level)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) /* CPUFreq converts to kHz, hence default 1000 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) dom_info->mult_factor = 1000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) dom_info->mult_factor =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) (dom_info->sustained_freq_khz * 1000) /
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) dom_info->sustained_perf_level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) strlcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) ph->xops->xfer_put(ph, t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) static int opp_cmp_func(const void *opp1, const void *opp2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) const struct scmi_opp *t1 = opp1, *t2 = opp2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) return t1->perf - t2->perf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) scmi_perf_describe_levels_get(const struct scmi_protocol_handle *ph, u32 domain,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) struct perf_dom_info *perf_dom)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) int ret, cnt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) u32 tot_opp_cnt = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) u16 num_returned, num_remaining;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) struct scmi_xfer *t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) struct scmi_opp *opp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) struct scmi_msg_perf_describe_levels *dom_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) struct scmi_msg_resp_perf_describe_levels *level_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) ret = ph->xops->xfer_get_init(ph, PERF_DESCRIBE_LEVELS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) sizeof(*dom_info), 0, &t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) dom_info = t->tx.buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) level_info = t->rx.buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) dom_info->domain = cpu_to_le32(domain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) /* Set the number of OPPs to be skipped/already read */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) dom_info->level_index = cpu_to_le32(tot_opp_cnt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) ret = ph->xops->do_xfer(ph, t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) num_returned = le16_to_cpu(level_info->num_returned);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) num_remaining = le16_to_cpu(level_info->num_remaining);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) if (tot_opp_cnt + num_returned > MAX_OPPS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) dev_err(ph->dev, "No. of OPPs exceeded MAX_OPPS");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) opp = &perf_dom->opp[tot_opp_cnt];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) for (cnt = 0; cnt < num_returned; cnt++, opp++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) opp->perf = le32_to_cpu(level_info->opp[cnt].perf_val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) opp->power = le32_to_cpu(level_info->opp[cnt].power);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) opp->trans_latency_us = le16_to_cpu
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) (level_info->opp[cnt].transition_latency_us);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) dev_dbg(ph->dev, "Level %d Power %d Latency %dus\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) opp->perf, opp->power, opp->trans_latency_us);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) tot_opp_cnt += num_returned;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) ph->xops->reset_rx_to_maxsz(ph, t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) * check for both returned and remaining to avoid infinite
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) * loop due to buggy firmware
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) } while (num_returned && num_remaining);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) perf_dom->opp_count = tot_opp_cnt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) ph->xops->xfer_put(ph, t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) sort(perf_dom->opp, tot_opp_cnt, sizeof(*opp), opp_cmp_func, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) #define SCMI_PERF_FC_RING_DB(w) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) do { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) u##w val = 0; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) if (db->mask) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) val = ioread##w(db->addr) & db->mask; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) iowrite##w((u##w)db->set | val, db->addr); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) } while (0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) static void scmi_perf_fc_ring_db(struct scmi_fc_db_info *db)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) if (!db || !db->addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) if (db->width == 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) SCMI_PERF_FC_RING_DB(8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) else if (db->width == 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) SCMI_PERF_FC_RING_DB(16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) else if (db->width == 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) SCMI_PERF_FC_RING_DB(32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) else /* db->width == 8 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) #ifdef CONFIG_64BIT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) SCMI_PERF_FC_RING_DB(64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) u64 val = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) if (db->mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) val = ioread64_hi_lo(db->addr) & db->mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) iowrite64_hi_lo(db->set | val, db->addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) static int scmi_perf_mb_limits_set(const struct scmi_protocol_handle *ph,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) u32 domain, u32 max_perf, u32 min_perf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) struct scmi_xfer *t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) struct scmi_perf_set_limits *limits;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) ret = ph->xops->xfer_get_init(ph, PERF_LIMITS_SET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) sizeof(*limits), 0, &t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) limits = t->tx.buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) limits->domain = cpu_to_le32(domain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) limits->max_level = cpu_to_le32(max_perf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) limits->min_level = cpu_to_le32(min_perf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) ret = ph->xops->do_xfer(ph, t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) ph->xops->xfer_put(ph, t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) static int scmi_perf_limits_set(const struct scmi_protocol_handle *ph,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) u32 domain, u32 max_perf, u32 min_perf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) struct scmi_perf_info *pi = ph->get_priv(ph);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) struct perf_dom_info *dom = pi->dom_info + domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) if (dom->fc_info && dom->fc_info->limit_set_addr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) iowrite32(max_perf, dom->fc_info->limit_set_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) iowrite32(min_perf, dom->fc_info->limit_set_addr + 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) scmi_perf_fc_ring_db(dom->fc_info->limit_set_db);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) return scmi_perf_mb_limits_set(ph, domain, max_perf, min_perf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) static int scmi_perf_mb_limits_get(const struct scmi_protocol_handle *ph,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) u32 domain, u32 *max_perf, u32 *min_perf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) struct scmi_xfer *t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) struct scmi_perf_get_limits *limits;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) ret = ph->xops->xfer_get_init(ph, PERF_LIMITS_GET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) sizeof(__le32), 0, &t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) put_unaligned_le32(domain, t->tx.buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) ret = ph->xops->do_xfer(ph, t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) if (!ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) limits = t->rx.buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) *max_perf = le32_to_cpu(limits->max_level);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) *min_perf = le32_to_cpu(limits->min_level);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) ph->xops->xfer_put(ph, t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) static int scmi_perf_limits_get(const struct scmi_protocol_handle *ph,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) u32 domain, u32 *max_perf, u32 *min_perf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) struct scmi_perf_info *pi = ph->get_priv(ph);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) struct perf_dom_info *dom = pi->dom_info + domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) if (dom->fc_info && dom->fc_info->limit_get_addr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) *max_perf = ioread32(dom->fc_info->limit_get_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) *min_perf = ioread32(dom->fc_info->limit_get_addr + 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) return scmi_perf_mb_limits_get(ph, domain, max_perf, min_perf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) static int scmi_perf_mb_level_set(const struct scmi_protocol_handle *ph,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) u32 domain, u32 level, bool poll)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) struct scmi_xfer *t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) struct scmi_perf_set_level *lvl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) ret = ph->xops->xfer_get_init(ph, PERF_LEVEL_SET, sizeof(*lvl), 0, &t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) t->hdr.poll_completion = poll;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) lvl = t->tx.buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) lvl->domain = cpu_to_le32(domain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) lvl->level = cpu_to_le32(level);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) ret = ph->xops->do_xfer(ph, t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) ph->xops->xfer_put(ph, t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) static int scmi_perf_level_set(const struct scmi_protocol_handle *ph,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) u32 domain, u32 level, bool poll)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) struct scmi_perf_info *pi = ph->get_priv(ph);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) struct perf_dom_info *dom = pi->dom_info + domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) if (dom->fc_info && dom->fc_info->level_set_addr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) iowrite32(level, dom->fc_info->level_set_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) scmi_perf_fc_ring_db(dom->fc_info->level_set_db);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) return scmi_perf_mb_level_set(ph, domain, level, poll);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) static int scmi_perf_mb_level_get(const struct scmi_protocol_handle *ph,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) u32 domain, u32 *level, bool poll)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) struct scmi_xfer *t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) ret = ph->xops->xfer_get_init(ph, PERF_LEVEL_GET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) sizeof(u32), sizeof(u32), &t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) t->hdr.poll_completion = poll;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) put_unaligned_le32(domain, t->tx.buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) ret = ph->xops->do_xfer(ph, t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) *level = get_unaligned_le32(t->rx.buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) ph->xops->xfer_put(ph, t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) static int scmi_perf_level_get(const struct scmi_protocol_handle *ph,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) u32 domain, u32 *level, bool poll)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) struct scmi_perf_info *pi = ph->get_priv(ph);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) struct perf_dom_info *dom = pi->dom_info + domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) if (dom->fc_info && dom->fc_info->level_get_addr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) *level = ioread32(dom->fc_info->level_get_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) return scmi_perf_mb_level_get(ph, domain, level, poll);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) static int scmi_perf_level_limits_notify(const struct scmi_protocol_handle *ph,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) u32 domain, int message_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) bool enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) struct scmi_xfer *t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) struct scmi_perf_notify_level_or_limits *notify;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) ret = ph->xops->xfer_get_init(ph, message_id, sizeof(*notify), 0, &t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) notify = t->tx.buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) notify->domain = cpu_to_le32(domain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) notify->notify_enable = enable ? cpu_to_le32(BIT(0)) : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) ret = ph->xops->do_xfer(ph, t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) ph->xops->xfer_put(ph, t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) static bool scmi_perf_fc_size_is_valid(u32 msg, u32 size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) if ((msg == PERF_LEVEL_GET || msg == PERF_LEVEL_SET) && size == 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) if ((msg == PERF_LIMITS_GET || msg == PERF_LIMITS_SET) && size == 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) scmi_perf_domain_desc_fc(const struct scmi_protocol_handle *ph, u32 domain,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) u32 message_id, void __iomem **p_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) struct scmi_fc_db_info **p_db)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) u32 flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) u64 phys_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) u8 size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) void __iomem *addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) struct scmi_xfer *t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) struct scmi_fc_db_info *db;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) struct scmi_perf_get_fc_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) struct scmi_msg_resp_perf_desc_fc *resp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) if (!p_addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) ret = ph->xops->xfer_get_init(ph, PERF_DESCRIBE_FASTCHANNEL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) sizeof(*info), sizeof(*resp), &t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) info = t->tx.buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) info->domain = cpu_to_le32(domain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) info->message_id = cpu_to_le32(message_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) ret = ph->xops->do_xfer(ph, t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) goto err_xfer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) resp = t->rx.buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) flags = le32_to_cpu(resp->attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) size = le32_to_cpu(resp->chan_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) if (!scmi_perf_fc_size_is_valid(message_id, size))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) goto err_xfer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) phys_addr = le32_to_cpu(resp->chan_addr_low);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) phys_addr |= (u64)le32_to_cpu(resp->chan_addr_high) << 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) addr = devm_ioremap(ph->dev, phys_addr, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) if (!addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) goto err_xfer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) *p_addr = addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) if (p_db && SUPPORTS_DOORBELL(flags)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) db = devm_kzalloc(ph->dev, sizeof(*db), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) if (!db)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) goto err_xfer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) size = 1 << DOORBELL_REG_WIDTH(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) phys_addr = le32_to_cpu(resp->db_addr_low);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) phys_addr |= (u64)le32_to_cpu(resp->db_addr_high) << 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) addr = devm_ioremap(ph->dev, phys_addr, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) if (!addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) goto err_xfer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) db->addr = addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) db->width = size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) db->set = le32_to_cpu(resp->db_set_lmask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) db->set |= (u64)le32_to_cpu(resp->db_set_hmask) << 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) db->mask = le32_to_cpu(resp->db_preserve_lmask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) db->mask |= (u64)le32_to_cpu(resp->db_preserve_hmask) << 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) *p_db = db;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) err_xfer:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) ph->xops->xfer_put(ph, t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) static void scmi_perf_domain_init_fc(const struct scmi_protocol_handle *ph,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) u32 domain, struct scmi_fc_info **p_fc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) struct scmi_fc_info *fc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) fc = devm_kzalloc(ph->dev, sizeof(*fc), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) if (!fc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) scmi_perf_domain_desc_fc(ph, domain, PERF_LEVEL_SET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) &fc->level_set_addr, &fc->level_set_db);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) scmi_perf_domain_desc_fc(ph, domain, PERF_LEVEL_GET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) &fc->level_get_addr, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) scmi_perf_domain_desc_fc(ph, domain, PERF_LIMITS_SET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) &fc->limit_set_addr, &fc->limit_set_db);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) scmi_perf_domain_desc_fc(ph, domain, PERF_LIMITS_GET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) &fc->limit_get_addr, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) *p_fc = fc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) /* Device specific ops */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) static int scmi_dev_domain_id(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) struct of_phandle_args clkspec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) if (of_parse_phandle_with_args(dev->of_node, "clocks", "#clock-cells",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) 0, &clkspec))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) return clkspec.args[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) static int scmi_dvfs_device_opps_add(const struct scmi_protocol_handle *ph,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) int idx, ret, domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) unsigned long freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) struct scmi_opp *opp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) struct perf_dom_info *dom;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) struct scmi_perf_info *pi = ph->get_priv(ph);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) domain = scmi_dev_domain_id(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) if (domain < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) return domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) dom = pi->dom_info + domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) for (opp = dom->opp, idx = 0; idx < dom->opp_count; idx++, opp++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) freq = opp->perf * dom->mult_factor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) ret = dev_pm_opp_add(dev, freq, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) dev_warn(dev, "failed to add opp %luHz\n", freq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) while (idx-- > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) freq = (--opp)->perf * dom->mult_factor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) dev_pm_opp_remove(dev, freq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) scmi_dvfs_transition_latency_get(const struct scmi_protocol_handle *ph,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) struct perf_dom_info *dom;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) struct scmi_perf_info *pi = ph->get_priv(ph);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) int domain = scmi_dev_domain_id(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) if (domain < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) return domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) dom = pi->dom_info + domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) /* uS to nS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) return dom->opp[dom->opp_count - 1].trans_latency_us * 1000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) static int scmi_dvfs_freq_set(const struct scmi_protocol_handle *ph, u32 domain,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) unsigned long freq, bool poll)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) struct scmi_perf_info *pi = ph->get_priv(ph);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) struct perf_dom_info *dom = pi->dom_info + domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) return scmi_perf_level_set(ph, domain, freq / dom->mult_factor, poll);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) static int scmi_dvfs_freq_get(const struct scmi_protocol_handle *ph, u32 domain,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) unsigned long *freq, bool poll)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) u32 level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) struct scmi_perf_info *pi = ph->get_priv(ph);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) struct perf_dom_info *dom = pi->dom_info + domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) ret = scmi_perf_level_get(ph, domain, &level, poll);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) *freq = level * dom->mult_factor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) static int scmi_dvfs_est_power_get(const struct scmi_protocol_handle *ph,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) u32 domain, unsigned long *freq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) unsigned long *power)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) struct scmi_perf_info *pi = ph->get_priv(ph);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) struct perf_dom_info *dom;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) unsigned long opp_freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) int idx, ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) struct scmi_opp *opp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) dom = pi->dom_info + domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) if (!dom)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) for (opp = dom->opp, idx = 0; idx < dom->opp_count; idx++, opp++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) opp_freq = opp->perf * dom->mult_factor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) if (opp_freq < *freq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) *freq = opp_freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) *power = opp->power;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) static bool scmi_fast_switch_possible(const struct scmi_protocol_handle *ph,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) struct perf_dom_info *dom;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) struct scmi_perf_info *pi = ph->get_priv(ph);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) dom = pi->dom_info + scmi_dev_domain_id(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) return dom->fc_info && dom->fc_info->level_set_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) static bool scmi_power_scale_mw_get(const struct scmi_protocol_handle *ph)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) struct scmi_perf_info *pi = ph->get_priv(ph);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) return pi->power_scale_mw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) static const struct scmi_perf_proto_ops perf_proto_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) .limits_set = scmi_perf_limits_set,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) .limits_get = scmi_perf_limits_get,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) .level_set = scmi_perf_level_set,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) .level_get = scmi_perf_level_get,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) .device_domain_id = scmi_dev_domain_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) .transition_latency_get = scmi_dvfs_transition_latency_get,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) .device_opps_add = scmi_dvfs_device_opps_add,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) .freq_set = scmi_dvfs_freq_set,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) .freq_get = scmi_dvfs_freq_get,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) .est_power_get = scmi_dvfs_est_power_get,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) .fast_switch_possible = scmi_fast_switch_possible,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) .power_scale_mw_get = scmi_power_scale_mw_get,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) static int scmi_perf_set_notify_enabled(const struct scmi_protocol_handle *ph,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) u8 evt_id, u32 src_id, bool enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) int ret, cmd_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) if (evt_id >= ARRAY_SIZE(evt_2_cmd))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) cmd_id = evt_2_cmd[evt_id];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) ret = scmi_perf_level_limits_notify(ph, src_id, cmd_id, enable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) evt_id, src_id, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) static void *scmi_perf_fill_custom_report(const struct scmi_protocol_handle *ph,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) u8 evt_id, ktime_t timestamp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) const void *payld, size_t payld_sz,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) void *report, u32 *src_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) void *rep = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) switch (evt_id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) case SCMI_EVENT_PERFORMANCE_LIMITS_CHANGED:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) const struct scmi_perf_limits_notify_payld *p = payld;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) struct scmi_perf_limits_report *r = report;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) if (sizeof(*p) != payld_sz)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) r->timestamp = timestamp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) r->agent_id = le32_to_cpu(p->agent_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) r->domain_id = le32_to_cpu(p->domain_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) r->range_max = le32_to_cpu(p->range_max);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) r->range_min = le32_to_cpu(p->range_min);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) *src_id = r->domain_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) rep = r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) case SCMI_EVENT_PERFORMANCE_LEVEL_CHANGED:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) const struct scmi_perf_level_notify_payld *p = payld;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) struct scmi_perf_level_report *r = report;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) if (sizeof(*p) != payld_sz)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) r->timestamp = timestamp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) r->agent_id = le32_to_cpu(p->agent_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) r->domain_id = le32_to_cpu(p->domain_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) r->performance_level = le32_to_cpu(p->performance_level);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) *src_id = r->domain_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) rep = r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) return rep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) static int scmi_perf_get_num_sources(const struct scmi_protocol_handle *ph)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) struct scmi_perf_info *pi = ph->get_priv(ph);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) if (!pi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) return pi->num_domains;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) static const struct scmi_event perf_events[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) .id = SCMI_EVENT_PERFORMANCE_LIMITS_CHANGED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) .max_payld_sz = sizeof(struct scmi_perf_limits_notify_payld),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) .max_report_sz = sizeof(struct scmi_perf_limits_report),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) .id = SCMI_EVENT_PERFORMANCE_LEVEL_CHANGED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) .max_payld_sz = sizeof(struct scmi_perf_level_notify_payld),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) .max_report_sz = sizeof(struct scmi_perf_level_report),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) static const struct scmi_event_ops perf_event_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) .get_num_sources = scmi_perf_get_num_sources,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) .set_notify_enabled = scmi_perf_set_notify_enabled,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) .fill_custom_report = scmi_perf_fill_custom_report,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) static const struct scmi_protocol_events perf_protocol_events = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) .queue_sz = SCMI_PROTO_QUEUE_SZ,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) .ops = &perf_event_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) .evts = perf_events,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) .num_events = ARRAY_SIZE(perf_events),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) static int scmi_perf_protocol_init(const struct scmi_protocol_handle *ph)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) int domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) u32 version;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) struct scmi_perf_info *pinfo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) ph->xops->version_get(ph, &version);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) dev_dbg(ph->dev, "Performance Version %d.%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) if (!pinfo)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) scmi_perf_attributes_get(ph, pinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) pinfo->dom_info = devm_kcalloc(ph->dev, pinfo->num_domains,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) sizeof(*pinfo->dom_info), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) if (!pinfo->dom_info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) for (domain = 0; domain < pinfo->num_domains; domain++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) struct perf_dom_info *dom = pinfo->dom_info + domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) scmi_perf_domain_attributes_get(ph, domain, dom);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) scmi_perf_describe_levels_get(ph, domain, dom);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) if (dom->perf_fastchannels)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) scmi_perf_domain_init_fc(ph, domain, &dom->fc_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) pinfo->version = version;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) return ph->set_priv(ph, pinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) static const struct scmi_protocol scmi_perf = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) .id = SCMI_PROTOCOL_PERF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) .init_instance = &scmi_perf_protocol_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) .ops = &perf_proto_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) .events = &perf_protocol_events,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(perf, scmi_perf)