blob: de2ba4755acfcc411463890109d5e7e1f06f5800 [file] [log] [blame]
AKASHI Takahiro8f00d022023-10-16 14:39:43 +09001// 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
16int 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
44int 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
72int 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
104int 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
134int 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
161int 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}