blob: b45d3e9cee12983c3e8419c5182cef60b48137e6 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * System Control and Management Interface (SCMI) Reset Protocol
4 *
5 * Copyright (C) 2019 ARM Ltd.
6 */
7
8#include "common.h"
9
10enum scmi_reset_protocol_cmd {
11 RESET_DOMAIN_ATTRIBUTES = 0x3,
12 RESET = 0x4,
13 RESET_NOTIFY = 0x5,
14};
15
16enum scmi_reset_protocol_notify {
17 RESET_ISSUED = 0x0,
18};
19
20#define NUM_RESET_DOMAIN_MASK 0xffff
21#define RESET_NOTIFY_ENABLE BIT(0)
22
23struct scmi_msg_resp_reset_domain_attributes {
24 __le32 attributes;
25#define SUPPORTS_ASYNC_RESET(x) ((x) & BIT(31))
26#define SUPPORTS_NOTIFY_RESET(x) ((x) & BIT(30))
27 __le32 latency;
28 u8 name[SCMI_MAX_STR_SIZE];
29};
30
31struct scmi_msg_reset_domain_reset {
32 __le32 domain_id;
33 __le32 flags;
34#define AUTONOMOUS_RESET BIT(0)
35#define EXPLICIT_RESET_ASSERT BIT(1)
36#define ASYNCHRONOUS_RESET BIT(2)
37 __le32 reset_state;
38#define ARCH_COLD_RESET 0
39};
40
41struct reset_dom_info {
42 bool async_reset;
43 bool reset_notify;
44 u32 latency_us;
45 char name[SCMI_MAX_STR_SIZE];
46};
47
48struct scmi_reset_info {
49 int num_domains;
50 struct reset_dom_info *dom_info;
51};
52
53static int scmi_reset_attributes_get(const struct scmi_handle *handle,
54 struct scmi_reset_info *pi)
55{
56 int ret;
57 struct scmi_xfer *t;
58 u32 attr;
59
60 ret = scmi_xfer_get_init(handle, PROTOCOL_ATTRIBUTES,
61 SCMI_PROTOCOL_RESET, 0, sizeof(attr), &t);
62 if (ret)
63 return ret;
64
65 ret = scmi_do_xfer(handle, t);
66 if (!ret) {
67 attr = get_unaligned_le32(t->rx.buf);
68 pi->num_domains = attr & NUM_RESET_DOMAIN_MASK;
69 }
70
71 scmi_xfer_put(handle, t);
72 return ret;
73}
74
75static int
76scmi_reset_domain_attributes_get(const struct scmi_handle *handle, u32 domain,
77 struct reset_dom_info *dom_info)
78{
79 int ret;
80 struct scmi_xfer *t;
81 struct scmi_msg_resp_reset_domain_attributes *attr;
82
83 ret = scmi_xfer_get_init(handle, RESET_DOMAIN_ATTRIBUTES,
84 SCMI_PROTOCOL_RESET, sizeof(domain),
85 sizeof(*attr), &t);
86 if (ret)
87 return ret;
88
89 put_unaligned_le32(domain, t->tx.buf);
90 attr = t->rx.buf;
91
92 ret = scmi_do_xfer(handle, t);
93 if (!ret) {
94 u32 attributes = le32_to_cpu(attr->attributes);
95
96 dom_info->async_reset = SUPPORTS_ASYNC_RESET(attributes);
97 dom_info->reset_notify = SUPPORTS_NOTIFY_RESET(attributes);
98 dom_info->latency_us = le32_to_cpu(attr->latency);
99 if (dom_info->latency_us == U32_MAX)
100 dom_info->latency_us = 0;
101 strlcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE);
102 }
103
104 scmi_xfer_put(handle, t);
105 return ret;
106}
107
108static int scmi_reset_num_domains_get(const struct scmi_handle *handle)
109{
110 struct scmi_reset_info *pi = handle->reset_priv;
111
112 return pi->num_domains;
113}
114
115static char *scmi_reset_name_get(const struct scmi_handle *handle, u32 domain)
116{
117 struct scmi_reset_info *pi = handle->reset_priv;
118 struct reset_dom_info *dom = pi->dom_info + domain;
119
120 return dom->name;
121}
122
123static int scmi_reset_latency_get(const struct scmi_handle *handle, u32 domain)
124{
125 struct scmi_reset_info *pi = handle->reset_priv;
126 struct reset_dom_info *dom = pi->dom_info + domain;
127
128 return dom->latency_us;
129}
130
131static int scmi_domain_reset(const struct scmi_handle *handle, u32 domain,
132 u32 flags, u32 state)
133{
134 int ret;
135 struct scmi_xfer *t;
136 struct scmi_msg_reset_domain_reset *dom;
137 struct scmi_reset_info *pi = handle->reset_priv;
138 struct reset_dom_info *rdom;
139
140 if (domain >= pi->num_domains)
141 return -EINVAL;
142
143 rdom = pi->dom_info + domain;
144 if (rdom->async_reset)
145 flags |= ASYNCHRONOUS_RESET;
146
147 ret = scmi_xfer_get_init(handle, RESET, SCMI_PROTOCOL_RESET,
148 sizeof(*dom), 0, &t);
149 if (ret)
150 return ret;
151
152 dom = t->tx.buf;
153 dom->domain_id = cpu_to_le32(domain);
154 dom->flags = cpu_to_le32(flags);
155 dom->reset_state = cpu_to_le32(state);
156
157 if (rdom->async_reset)
158 ret = scmi_do_xfer_with_response(handle, t);
159 else
160 ret = scmi_do_xfer(handle, t);
161
162 scmi_xfer_put(handle, t);
163 return ret;
164}
165
166static int scmi_reset_domain_reset(const struct scmi_handle *handle, u32 domain)
167{
168 return scmi_domain_reset(handle, domain, AUTONOMOUS_RESET,
169 ARCH_COLD_RESET);
170}
171
172static int
173scmi_reset_domain_assert(const struct scmi_handle *handle, u32 domain)
174{
175 return scmi_domain_reset(handle, domain, EXPLICIT_RESET_ASSERT,
176 ARCH_COLD_RESET);
177}
178
179static int
180scmi_reset_domain_deassert(const struct scmi_handle *handle, u32 domain)
181{
182 return scmi_domain_reset(handle, domain, 0, ARCH_COLD_RESET);
183}
184
185static struct scmi_reset_ops reset_ops = {
186 .num_domains_get = scmi_reset_num_domains_get,
187 .name_get = scmi_reset_name_get,
188 .latency_get = scmi_reset_latency_get,
189 .reset = scmi_reset_domain_reset,
190 .assert = scmi_reset_domain_assert,
191 .deassert = scmi_reset_domain_deassert,
192};
193
194static int scmi_reset_protocol_init(struct scmi_handle *handle)
195{
196 int domain;
197 u32 version;
198 struct scmi_reset_info *pinfo;
199
200 scmi_version_get(handle, SCMI_PROTOCOL_RESET, &version);
201
202 dev_dbg(handle->dev, "Reset Version %d.%d\n",
203 PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
204
205 pinfo = devm_kzalloc(handle->dev, sizeof(*pinfo), GFP_KERNEL);
206 if (!pinfo)
207 return -ENOMEM;
208
209 scmi_reset_attributes_get(handle, pinfo);
210
211 pinfo->dom_info = devm_kcalloc(handle->dev, pinfo->num_domains,
212 sizeof(*pinfo->dom_info), GFP_KERNEL);
213 if (!pinfo->dom_info)
214 return -ENOMEM;
215
216 for (domain = 0; domain < pinfo->num_domains; domain++) {
217 struct reset_dom_info *dom = pinfo->dom_info + domain;
218
219 scmi_reset_domain_attributes_get(handle, domain, dom);
220 }
221
222 handle->reset_ops = &reset_ops;
223 handle->reset_priv = pinfo;
224
225 return 0;
226}
227
228static int __init scmi_reset_init(void)
229{
230 return scmi_protocol_register(SCMI_PROTOCOL_RESET,
231 &scmi_reset_protocol_init);
232}
233subsys_initcall(scmi_reset_init);