Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/firmware/arm_scmi/vendors/imx/imx-sm-lmm.c
26498 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* System control and Management Interface (SCMI) NXP LMM Protocol
4
*
5
* Copyright 2025 NXP
6
*/
7
8
#include <linux/bits.h>
9
#include <linux/io.h>
10
#include <linux/module.h>
11
#include <linux/of.h>
12
#include <linux/platform_device.h>
13
#include <linux/scmi_protocol.h>
14
#include <linux/scmi_imx_protocol.h>
15
16
#include "../../protocols.h"
17
#include "../../notify.h"
18
19
#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x10000
20
21
enum scmi_imx_lmm_protocol_cmd {
22
SCMI_IMX_LMM_ATTRIBUTES = 0x3,
23
SCMI_IMX_LMM_BOOT = 0x4,
24
SCMI_IMX_LMM_RESET = 0x5,
25
SCMI_IMX_LMM_SHUTDOWN = 0x6,
26
SCMI_IMX_LMM_WAKE = 0x7,
27
SCMI_IMX_LMM_SUSPEND = 0x8,
28
SCMI_IMX_LMM_NOTIFY = 0x9,
29
SCMI_IMX_LMM_RESET_REASON = 0xA,
30
SCMI_IMX_LMM_POWER_ON = 0xB,
31
SCMI_IMX_LMM_RESET_VECTOR_SET = 0xC,
32
};
33
34
struct scmi_imx_lmm_priv {
35
u32 nr_lmm;
36
};
37
38
#define SCMI_IMX_LMM_NR_LM_MASK GENMASK(5, 0)
39
#define SCMI_IMX_LMM_NR_MAX 16
40
struct scmi_msg_imx_lmm_protocol_attributes {
41
__le32 attributes;
42
};
43
44
struct scmi_msg_imx_lmm_attributes_out {
45
__le32 lmid;
46
__le32 attributes;
47
__le32 state;
48
__le32 errstatus;
49
u8 name[LMM_MAX_NAME];
50
};
51
52
struct scmi_imx_lmm_reset_vector_set_in {
53
__le32 lmid;
54
__le32 cpuid;
55
__le32 flags; /* reserved for future extension */
56
__le32 resetvectorlow;
57
__le32 resetvectorhigh;
58
};
59
60
struct scmi_imx_lmm_shutdown_in {
61
__le32 lmid;
62
#define SCMI_IMX_LMM_SHUTDOWN_GRACEFUL BIT(0)
63
__le32 flags;
64
};
65
66
static int scmi_imx_lmm_validate_lmid(const struct scmi_protocol_handle *ph, u32 lmid)
67
{
68
struct scmi_imx_lmm_priv *priv = ph->get_priv(ph);
69
70
if (lmid >= priv->nr_lmm)
71
return -EINVAL;
72
73
return 0;
74
}
75
76
static int scmi_imx_lmm_attributes(const struct scmi_protocol_handle *ph,
77
u32 lmid, struct scmi_imx_lmm_info *info)
78
{
79
struct scmi_msg_imx_lmm_attributes_out *out;
80
struct scmi_xfer *t;
81
int ret;
82
83
ret = ph->xops->xfer_get_init(ph, SCMI_IMX_LMM_ATTRIBUTES, sizeof(u32), 0, &t);
84
if (ret)
85
return ret;
86
87
put_unaligned_le32(lmid, t->tx.buf);
88
ret = ph->xops->do_xfer(ph, t);
89
if (!ret) {
90
out = t->rx.buf;
91
info->lmid = le32_to_cpu(out->lmid);
92
info->state = le32_to_cpu(out->state);
93
info->errstatus = le32_to_cpu(out->errstatus);
94
strscpy(info->name, out->name);
95
dev_dbg(ph->dev, "i.MX LMM: Logical Machine(%d), name: %s\n",
96
info->lmid, info->name);
97
} else {
98
dev_err(ph->dev, "i.MX LMM: Failed to get info of Logical Machine(%u)\n", lmid);
99
}
100
101
ph->xops->xfer_put(ph, t);
102
103
return ret;
104
}
105
106
static int
107
scmi_imx_lmm_power_boot(const struct scmi_protocol_handle *ph, u32 lmid, bool boot)
108
{
109
struct scmi_xfer *t;
110
u8 msg_id;
111
int ret;
112
113
ret = scmi_imx_lmm_validate_lmid(ph, lmid);
114
if (ret)
115
return ret;
116
117
if (boot)
118
msg_id = SCMI_IMX_LMM_BOOT;
119
else
120
msg_id = SCMI_IMX_LMM_POWER_ON;
121
122
ret = ph->xops->xfer_get_init(ph, msg_id, sizeof(u32), 0, &t);
123
if (ret)
124
return ret;
125
126
put_unaligned_le32(lmid, t->tx.buf);
127
ret = ph->xops->do_xfer(ph, t);
128
129
ph->xops->xfer_put(ph, t);
130
131
return ret;
132
}
133
134
static int scmi_imx_lmm_reset_vector_set(const struct scmi_protocol_handle *ph,
135
u32 lmid, u32 cpuid, u32 flags, u64 vector)
136
{
137
struct scmi_imx_lmm_reset_vector_set_in *in;
138
struct scmi_xfer *t;
139
int ret;
140
141
ret = ph->xops->xfer_get_init(ph, SCMI_IMX_LMM_RESET_VECTOR_SET, sizeof(*in),
142
0, &t);
143
if (ret)
144
return ret;
145
146
in = t->tx.buf;
147
in->lmid = cpu_to_le32(lmid);
148
in->cpuid = cpu_to_le32(cpuid);
149
in->flags = cpu_to_le32(0);
150
in->resetvectorlow = cpu_to_le32(lower_32_bits(vector));
151
in->resetvectorhigh = cpu_to_le32(upper_32_bits(vector));
152
ret = ph->xops->do_xfer(ph, t);
153
154
ph->xops->xfer_put(ph, t);
155
156
return ret;
157
}
158
159
static int scmi_imx_lmm_shutdown(const struct scmi_protocol_handle *ph, u32 lmid,
160
u32 flags)
161
{
162
struct scmi_imx_lmm_shutdown_in *in;
163
struct scmi_xfer *t;
164
int ret;
165
166
ret = scmi_imx_lmm_validate_lmid(ph, lmid);
167
if (ret)
168
return ret;
169
170
ret = ph->xops->xfer_get_init(ph, SCMI_IMX_LMM_SHUTDOWN, sizeof(*in),
171
0, &t);
172
if (ret)
173
return ret;
174
175
in = t->tx.buf;
176
in->lmid = cpu_to_le32(lmid);
177
if (flags & SCMI_IMX_LMM_SHUTDOWN_GRACEFUL)
178
in->flags = cpu_to_le32(SCMI_IMX_LMM_SHUTDOWN_GRACEFUL);
179
else
180
in->flags = cpu_to_le32(0);
181
ret = ph->xops->do_xfer(ph, t);
182
183
ph->xops->xfer_put(ph, t);
184
185
return ret;
186
}
187
188
static const struct scmi_imx_lmm_proto_ops scmi_imx_lmm_proto_ops = {
189
.lmm_power_boot = scmi_imx_lmm_power_boot,
190
.lmm_info = scmi_imx_lmm_attributes,
191
.lmm_reset_vector_set = scmi_imx_lmm_reset_vector_set,
192
.lmm_shutdown = scmi_imx_lmm_shutdown,
193
};
194
195
static int scmi_imx_lmm_protocol_attributes_get(const struct scmi_protocol_handle *ph,
196
struct scmi_imx_lmm_priv *priv)
197
{
198
struct scmi_msg_imx_lmm_protocol_attributes *attr;
199
struct scmi_xfer *t;
200
int ret;
201
202
ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0,
203
sizeof(*attr), &t);
204
if (ret)
205
return ret;
206
207
attr = t->rx.buf;
208
209
ret = ph->xops->do_xfer(ph, t);
210
if (!ret) {
211
priv->nr_lmm = le32_get_bits(attr->attributes, SCMI_IMX_LMM_NR_LM_MASK);
212
if (priv->nr_lmm > SCMI_IMX_LMM_NR_MAX) {
213
dev_err(ph->dev, "i.MX LMM: %d:Exceed max supported Logical Machines\n",
214
priv->nr_lmm);
215
ret = -EINVAL;
216
} else {
217
dev_info(ph->dev, "i.MX LMM: %d Logical Machines\n", priv->nr_lmm);
218
}
219
}
220
221
ph->xops->xfer_put(ph, t);
222
223
return ret;
224
}
225
226
static int scmi_imx_lmm_protocol_init(const struct scmi_protocol_handle *ph)
227
{
228
struct scmi_imx_lmm_priv *info;
229
u32 version;
230
int ret;
231
232
ret = ph->xops->version_get(ph, &version);
233
if (ret)
234
return ret;
235
236
dev_info(ph->dev, "NXP SM LMM Version %d.%d\n",
237
PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
238
239
info = devm_kzalloc(ph->dev, sizeof(*info), GFP_KERNEL);
240
if (!info)
241
return -ENOMEM;
242
243
ret = scmi_imx_lmm_protocol_attributes_get(ph, info);
244
if (ret)
245
return ret;
246
247
return ph->set_priv(ph, info, version);
248
}
249
250
static const struct scmi_protocol scmi_imx_lmm = {
251
.id = SCMI_PROTOCOL_IMX_LMM,
252
.owner = THIS_MODULE,
253
.instance_init = &scmi_imx_lmm_protocol_init,
254
.ops = &scmi_imx_lmm_proto_ops,
255
.supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,
256
.vendor_id = SCMI_IMX_VENDOR,
257
.sub_vendor_id = SCMI_IMX_SUBVENDOR,
258
};
259
module_scmi_protocol(scmi_imx_lmm);
260
261
MODULE_ALIAS("scmi-protocol-" __stringify(SCMI_PROTOCOL_IMX_LMM) "-" SCMI_IMX_VENDOR);
262
MODULE_DESCRIPTION("i.MX SCMI LMM driver");
263
MODULE_LICENSE("GPL");
264
265