1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * SCMI Power domain management protocol
4  *
5  * Copyright (C) 2023 Linaro Limited
6  *		author: AKASHI Takahiro <takahiro.akashi@linaro.org>
7  */
8 
9 #include <dm.h>
10 #include <malloc.h>
11 #include <scmi_agent.h>
12 #include <scmi_protocols.h>
13 #include <string.h>
14 #include <asm/types.h>
15 
scmi_pwd_protocol_attrs(struct udevice * dev,int * num_pwdoms,u64 * stats_addr,size_t * stats_len)16 int scmi_pwd_protocol_attrs(struct udevice *dev, int *num_pwdoms,
17 			    u64 *stats_addr, size_t *stats_len)
18 {
19 	struct scmi_pwd_protocol_attrs_out out;
20 	struct scmi_msg msg = {
21 		.protocol_id = SCMI_PROTOCOL_ID_POWER_DOMAIN,
22 		.message_id = SCMI_PROTOCOL_ATTRIBUTES,
23 		.out_msg = (u8 *)&out,
24 		.out_msg_sz = sizeof(out),
25 	};
26 	int ret;
27 
28 	if (!dev || !num_pwdoms || !stats_addr || !stats_len)
29 		return -EINVAL;
30 
31 	ret = devm_scmi_process_msg(dev, &msg);
32 	if (ret)
33 		return ret;
34 	if (out.status)
35 		return scmi_to_linux_errno(out.status);
36 
37 	*num_pwdoms = SCMI_PWD_PROTO_ATTRS_NUM_PWD(out.attributes);
38 	*stats_addr = ((u64)out.stats_addr_high << 32) + out.stats_addr_low;
39 	*stats_len = out.stats_len;
40 
41 	return 0;
42 }
43 
scmi_pwd_protocol_message_attrs(struct udevice * dev,s32 message_id,u32 * attributes)44 int scmi_pwd_protocol_message_attrs(struct udevice *dev, s32 message_id,
45 				    u32 *attributes)
46 {
47 	struct scmi_pwd_protocol_msg_attrs_out out;
48 	struct scmi_msg msg = {
49 		.protocol_id = SCMI_PROTOCOL_ID_POWER_DOMAIN,
50 		.message_id = SCMI_PROTOCOL_MESSAGE_ATTRIBUTES,
51 		.in_msg = (u8 *)&message_id,
52 		.in_msg_sz = sizeof(message_id),
53 		.out_msg = (u8 *)&out,
54 		.out_msg_sz = sizeof(out),
55 	};
56 	int ret;
57 
58 	if (!dev || !attributes)
59 		return -EINVAL;
60 
61 	ret = devm_scmi_process_msg(dev, &msg);
62 	if (ret)
63 		return ret;
64 	if (out.status)
65 		return scmi_to_linux_errno(out.status);
66 
67 	*attributes = out.attributes;
68 
69 	return 0;
70 }
71 
scmi_pwd_attrs(struct udevice * dev,u32 domain_id,u32 * attributes,u8 ** name)72 int scmi_pwd_attrs(struct udevice *dev, u32 domain_id, u32 *attributes,
73 		   u8 **name)
74 {
75 	struct scmi_pwd_attrs_out out;
76 	struct scmi_msg msg = {
77 		.protocol_id = SCMI_PROTOCOL_ID_POWER_DOMAIN,
78 		.message_id = SCMI_PWD_ATTRIBUTES,
79 		.in_msg = (u8 *)&domain_id,
80 		.in_msg_sz = sizeof(domain_id),
81 		.out_msg = (u8 *)&out,
82 		.out_msg_sz = sizeof(out),
83 	};
84 	int ret;
85 
86 	if (!dev || !attributes || !name)
87 		return -EINVAL;
88 
89 	ret = devm_scmi_process_msg(dev, &msg);
90 	if (ret)
91 		return ret;
92 	if (out.status)
93 		return scmi_to_linux_errno(out.status);
94 
95 	*name = strdup(out.name);
96 	if (!*name)
97 		return -ENOMEM;
98 
99 	*attributes = out.attributes;
100 
101 	return 0;
102 }
103 
scmi_pwd_state_set(struct udevice * dev,u32 flags,u32 domain_id,u32 pstate)104 int scmi_pwd_state_set(struct udevice *dev, u32 flags, u32 domain_id,
105 		       u32 pstate)
106 {
107 	struct scmi_pwd_state_set_in in;
108 	s32 status;
109 	struct scmi_msg msg = {
110 		.protocol_id = SCMI_PROTOCOL_ID_POWER_DOMAIN,
111 		.message_id = SCMI_PWD_STATE_SET,
112 		.in_msg = (u8 *)&in,
113 		.in_msg_sz = sizeof(in),
114 		.out_msg = (u8 *)&status,
115 		.out_msg_sz = sizeof(status),
116 	};
117 	int ret;
118 
119 	if (!dev)
120 		return -EINVAL;
121 
122 	in.flags = flags;
123 	in.domain_id = domain_id;
124 	in.pstate = pstate;
125 	ret = devm_scmi_process_msg(dev, &msg);
126 	if (ret)
127 		return ret;
128 	if (status)
129 		return scmi_to_linux_errno(status);
130 
131 	return 0;
132 }
133 
scmi_pwd_state_get(struct udevice * dev,u32 domain_id,u32 * pstate)134 int scmi_pwd_state_get(struct udevice *dev, u32 domain_id, u32 *pstate)
135 {
136 	struct scmi_pwd_state_get_out out;
137 	struct scmi_msg msg = {
138 		.protocol_id = SCMI_PROTOCOL_ID_POWER_DOMAIN,
139 		.message_id = SCMI_PWD_STATE_GET,
140 		.in_msg = (u8 *)&domain_id,
141 		.in_msg_sz = sizeof(domain_id),
142 		.out_msg = (u8 *)&out,
143 		.out_msg_sz = sizeof(out),
144 	};
145 	int ret;
146 
147 	if (!dev || !pstate)
148 		return -EINVAL;
149 
150 	ret = devm_scmi_process_msg(dev, &msg);
151 	if (ret)
152 		return ret;
153 	if (out.status)
154 		return scmi_to_linux_errno(out.status);
155 
156 	*pstate = out.pstate;
157 
158 	return 0;
159 }
160 
scmi_pwd_name_get(struct udevice * dev,u32 domain_id,u8 ** name)161 int scmi_pwd_name_get(struct udevice *dev, u32 domain_id, u8 **name)
162 {
163 	struct scmi_pwd_name_get_out out;
164 	struct scmi_msg msg = {
165 		.protocol_id = SCMI_PROTOCOL_ID_POWER_DOMAIN,
166 		.message_id = SCMI_PWD_NAME_GET,
167 		.in_msg = (u8 *)&domain_id,
168 		.in_msg_sz = sizeof(domain_id),
169 		.out_msg = (u8 *)&out,
170 		.out_msg_sz = sizeof(out),
171 	};
172 	int ret;
173 
174 	if (!dev || !name)
175 		return -EINVAL;
176 
177 	ret = devm_scmi_process_msg(dev, &msg);
178 	if (ret)
179 		return ret;
180 	if (out.status)
181 		return scmi_to_linux_errno(out.status);
182 
183 	*name = strdup(out.extended_name);
184 	if (!*name)
185 		return -ENOMEM;
186 
187 	return 0;
188 }
189