Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^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)