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-bbm.c
26498 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* System Control and Management Interface (SCMI) NXP BBM Protocol
4
*
5
* Copyright 2024 NXP
6
*/
7
8
#define pr_fmt(fmt) "SCMI Notifications BBM - " fmt
9
10
#include <linux/bits.h>
11
#include <linux/io.h>
12
#include <linux/module.h>
13
#include <linux/of.h>
14
#include <linux/platform_device.h>
15
#include <linux/scmi_protocol.h>
16
#include <linux/scmi_imx_protocol.h>
17
18
#include "../../protocols.h"
19
#include "../../notify.h"
20
21
#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x10000
22
23
enum scmi_imx_bbm_protocol_cmd {
24
IMX_BBM_GPR_SET = 0x3,
25
IMX_BBM_GPR_GET = 0x4,
26
IMX_BBM_RTC_ATTRIBUTES = 0x5,
27
IMX_BBM_RTC_TIME_SET = 0x6,
28
IMX_BBM_RTC_TIME_GET = 0x7,
29
IMX_BBM_RTC_ALARM_SET = 0x8,
30
IMX_BBM_BUTTON_GET = 0x9,
31
IMX_BBM_RTC_NOTIFY = 0xA,
32
IMX_BBM_BUTTON_NOTIFY = 0xB,
33
};
34
35
#define GET_RTCS_NR(x) le32_get_bits((x), GENMASK(23, 16))
36
#define GET_GPRS_NR(x) le32_get_bits((x), GENMASK(15, 0))
37
38
#define SCMI_IMX_BBM_NOTIFY_RTC_UPDATED BIT(2)
39
#define SCMI_IMX_BBM_NOTIFY_RTC_ROLLOVER BIT(1)
40
#define SCMI_IMX_BBM_NOTIFY_RTC_ALARM BIT(0)
41
42
#define SCMI_IMX_BBM_RTC_ALARM_ENABLE_FLAG BIT(0)
43
44
#define SCMI_IMX_BBM_NOTIFY_RTC_FLAG \
45
(SCMI_IMX_BBM_NOTIFY_RTC_UPDATED | SCMI_IMX_BBM_NOTIFY_RTC_ROLLOVER | \
46
SCMI_IMX_BBM_NOTIFY_RTC_ALARM)
47
48
#define SCMI_IMX_BBM_EVENT_RTC_MASK GENMASK(31, 24)
49
50
struct scmi_imx_bbm_info {
51
u32 version;
52
int nr_rtc;
53
int nr_gpr;
54
};
55
56
struct scmi_msg_imx_bbm_protocol_attributes {
57
__le32 attributes;
58
};
59
60
struct scmi_imx_bbm_set_time {
61
__le32 id;
62
__le32 flags;
63
__le32 value_low;
64
__le32 value_high;
65
};
66
67
struct scmi_imx_bbm_get_time {
68
__le32 id;
69
__le32 flags;
70
};
71
72
struct scmi_imx_bbm_alarm_time {
73
__le32 id;
74
__le32 flags;
75
__le32 value_low;
76
__le32 value_high;
77
};
78
79
struct scmi_msg_imx_bbm_rtc_notify {
80
__le32 rtc_id;
81
__le32 flags;
82
};
83
84
struct scmi_msg_imx_bbm_button_notify {
85
__le32 flags;
86
};
87
88
struct scmi_imx_bbm_notify_payld {
89
__le32 flags;
90
};
91
92
static int scmi_imx_bbm_attributes_get(const struct scmi_protocol_handle *ph,
93
struct scmi_imx_bbm_info *pi)
94
{
95
int ret;
96
struct scmi_xfer *t;
97
struct scmi_msg_imx_bbm_protocol_attributes *attr;
98
99
ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0, sizeof(*attr), &t);
100
if (ret)
101
return ret;
102
103
attr = t->rx.buf;
104
105
ret = ph->xops->do_xfer(ph, t);
106
if (!ret) {
107
pi->nr_rtc = GET_RTCS_NR(attr->attributes);
108
pi->nr_gpr = GET_GPRS_NR(attr->attributes);
109
}
110
111
ph->xops->xfer_put(ph, t);
112
113
return ret;
114
}
115
116
static int scmi_imx_bbm_notify(const struct scmi_protocol_handle *ph,
117
u32 src_id, int message_id, bool enable)
118
{
119
int ret;
120
struct scmi_xfer *t;
121
122
if (message_id == IMX_BBM_RTC_NOTIFY) {
123
struct scmi_msg_imx_bbm_rtc_notify *rtc_notify;
124
125
ret = ph->xops->xfer_get_init(ph, message_id,
126
sizeof(*rtc_notify), 0, &t);
127
if (ret)
128
return ret;
129
130
rtc_notify = t->tx.buf;
131
rtc_notify->rtc_id = cpu_to_le32(0);
132
rtc_notify->flags =
133
cpu_to_le32(enable ? SCMI_IMX_BBM_NOTIFY_RTC_FLAG : 0);
134
} else if (message_id == IMX_BBM_BUTTON_NOTIFY) {
135
struct scmi_msg_imx_bbm_button_notify *button_notify;
136
137
ret = ph->xops->xfer_get_init(ph, message_id,
138
sizeof(*button_notify), 0, &t);
139
if (ret)
140
return ret;
141
142
button_notify = t->tx.buf;
143
button_notify->flags = cpu_to_le32(enable ? 1 : 0);
144
} else {
145
return -EINVAL;
146
}
147
148
ret = ph->xops->do_xfer(ph, t);
149
150
ph->xops->xfer_put(ph, t);
151
return ret;
152
}
153
154
static enum scmi_imx_bbm_protocol_cmd evt_2_cmd[] = {
155
IMX_BBM_RTC_NOTIFY,
156
IMX_BBM_BUTTON_NOTIFY
157
};
158
159
static int scmi_imx_bbm_set_notify_enabled(const struct scmi_protocol_handle *ph,
160
u8 evt_id, u32 src_id, bool enable)
161
{
162
int ret, cmd_id;
163
164
if (evt_id >= ARRAY_SIZE(evt_2_cmd))
165
return -EINVAL;
166
167
cmd_id = evt_2_cmd[evt_id];
168
ret = scmi_imx_bbm_notify(ph, src_id, cmd_id, enable);
169
if (ret)
170
pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n",
171
evt_id, src_id, ret);
172
173
return ret;
174
}
175
176
static void *scmi_imx_bbm_fill_custom_report(const struct scmi_protocol_handle *ph,
177
u8 evt_id, ktime_t timestamp,
178
const void *payld, size_t payld_sz,
179
void *report, u32 *src_id)
180
{
181
const struct scmi_imx_bbm_notify_payld *p = payld;
182
struct scmi_imx_bbm_notif_report *r = report;
183
184
if (sizeof(*p) != payld_sz)
185
return NULL;
186
187
if (evt_id == SCMI_EVENT_IMX_BBM_RTC) {
188
r->is_rtc = true;
189
r->is_button = false;
190
r->timestamp = timestamp;
191
r->rtc_id = le32_get_bits(p->flags, SCMI_IMX_BBM_EVENT_RTC_MASK);
192
r->rtc_evt = le32_get_bits(p->flags, SCMI_IMX_BBM_NOTIFY_RTC_FLAG);
193
dev_dbg(ph->dev, "RTC: %d evt: %x\n", r->rtc_id, r->rtc_evt);
194
*src_id = r->rtc_evt;
195
} else if (evt_id == SCMI_EVENT_IMX_BBM_BUTTON) {
196
r->is_rtc = false;
197
r->is_button = true;
198
r->timestamp = timestamp;
199
dev_dbg(ph->dev, "BBM Button\n");
200
*src_id = 0;
201
} else {
202
WARN_ON_ONCE(1);
203
return NULL;
204
}
205
206
return r;
207
}
208
209
static const struct scmi_event scmi_imx_bbm_events[] = {
210
{
211
.id = SCMI_EVENT_IMX_BBM_RTC,
212
.max_payld_sz = sizeof(struct scmi_imx_bbm_notify_payld),
213
.max_report_sz = sizeof(struct scmi_imx_bbm_notif_report),
214
},
215
{
216
.id = SCMI_EVENT_IMX_BBM_BUTTON,
217
.max_payld_sz = sizeof(struct scmi_imx_bbm_notify_payld),
218
.max_report_sz = sizeof(struct scmi_imx_bbm_notif_report),
219
},
220
};
221
222
static const struct scmi_event_ops scmi_imx_bbm_event_ops = {
223
.set_notify_enabled = scmi_imx_bbm_set_notify_enabled,
224
.fill_custom_report = scmi_imx_bbm_fill_custom_report,
225
};
226
227
static const struct scmi_protocol_events scmi_imx_bbm_protocol_events = {
228
.queue_sz = SCMI_PROTO_QUEUE_SZ,
229
.ops = &scmi_imx_bbm_event_ops,
230
.evts = scmi_imx_bbm_events,
231
.num_events = ARRAY_SIZE(scmi_imx_bbm_events),
232
.num_sources = 1,
233
};
234
235
static int scmi_imx_bbm_rtc_time_set(const struct scmi_protocol_handle *ph,
236
u32 rtc_id, u64 sec)
237
{
238
struct scmi_imx_bbm_info *pi = ph->get_priv(ph);
239
struct scmi_imx_bbm_set_time *cfg;
240
struct scmi_xfer *t;
241
int ret;
242
243
if (rtc_id >= pi->nr_rtc)
244
return -EINVAL;
245
246
ret = ph->xops->xfer_get_init(ph, IMX_BBM_RTC_TIME_SET, sizeof(*cfg), 0, &t);
247
if (ret)
248
return ret;
249
250
cfg = t->tx.buf;
251
cfg->id = cpu_to_le32(rtc_id);
252
cfg->flags = 0;
253
cfg->value_low = cpu_to_le32(lower_32_bits(sec));
254
cfg->value_high = cpu_to_le32(upper_32_bits(sec));
255
256
ret = ph->xops->do_xfer(ph, t);
257
258
ph->xops->xfer_put(ph, t);
259
260
return ret;
261
}
262
263
static int scmi_imx_bbm_rtc_time_get(const struct scmi_protocol_handle *ph,
264
u32 rtc_id, u64 *value)
265
{
266
struct scmi_imx_bbm_info *pi = ph->get_priv(ph);
267
struct scmi_imx_bbm_get_time *cfg;
268
struct scmi_xfer *t;
269
int ret;
270
271
if (rtc_id >= pi->nr_rtc)
272
return -EINVAL;
273
274
ret = ph->xops->xfer_get_init(ph, IMX_BBM_RTC_TIME_GET, sizeof(*cfg),
275
sizeof(u64), &t);
276
if (ret)
277
return ret;
278
279
cfg = t->tx.buf;
280
cfg->id = cpu_to_le32(rtc_id);
281
cfg->flags = 0;
282
283
ret = ph->xops->do_xfer(ph, t);
284
if (!ret)
285
*value = get_unaligned_le64(t->rx.buf);
286
287
ph->xops->xfer_put(ph, t);
288
289
return ret;
290
}
291
292
static int scmi_imx_bbm_rtc_alarm_set(const struct scmi_protocol_handle *ph,
293
u32 rtc_id, bool enable, u64 sec)
294
{
295
struct scmi_imx_bbm_info *pi = ph->get_priv(ph);
296
struct scmi_imx_bbm_alarm_time *cfg;
297
struct scmi_xfer *t;
298
int ret;
299
300
if (rtc_id >= pi->nr_rtc)
301
return -EINVAL;
302
303
ret = ph->xops->xfer_get_init(ph, IMX_BBM_RTC_ALARM_SET, sizeof(*cfg), 0, &t);
304
if (ret)
305
return ret;
306
307
cfg = t->tx.buf;
308
cfg->id = cpu_to_le32(rtc_id);
309
cfg->flags = enable ?
310
cpu_to_le32(SCMI_IMX_BBM_RTC_ALARM_ENABLE_FLAG) : 0;
311
cfg->value_low = cpu_to_le32(lower_32_bits(sec));
312
cfg->value_high = cpu_to_le32(upper_32_bits(sec));
313
314
ret = ph->xops->do_xfer(ph, t);
315
316
ph->xops->xfer_put(ph, t);
317
318
return ret;
319
}
320
321
static int scmi_imx_bbm_button_get(const struct scmi_protocol_handle *ph, u32 *state)
322
{
323
struct scmi_xfer *t;
324
int ret;
325
326
ret = ph->xops->xfer_get_init(ph, IMX_BBM_BUTTON_GET, 0, sizeof(u32), &t);
327
if (ret)
328
return ret;
329
330
ret = ph->xops->do_xfer(ph, t);
331
if (!ret)
332
*state = get_unaligned_le32(t->rx.buf);
333
334
ph->xops->xfer_put(ph, t);
335
336
return ret;
337
}
338
339
static const struct scmi_imx_bbm_proto_ops scmi_imx_bbm_proto_ops = {
340
.rtc_time_get = scmi_imx_bbm_rtc_time_get,
341
.rtc_time_set = scmi_imx_bbm_rtc_time_set,
342
.rtc_alarm_set = scmi_imx_bbm_rtc_alarm_set,
343
.button_get = scmi_imx_bbm_button_get,
344
};
345
346
static int scmi_imx_bbm_protocol_init(const struct scmi_protocol_handle *ph)
347
{
348
u32 version;
349
int ret;
350
struct scmi_imx_bbm_info *binfo;
351
352
ret = ph->xops->version_get(ph, &version);
353
if (ret)
354
return ret;
355
356
dev_info(ph->dev, "NXP SM BBM Version %d.%d\n",
357
PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
358
359
binfo = devm_kzalloc(ph->dev, sizeof(*binfo), GFP_KERNEL);
360
if (!binfo)
361
return -ENOMEM;
362
363
ret = scmi_imx_bbm_attributes_get(ph, binfo);
364
if (ret)
365
return ret;
366
367
return ph->set_priv(ph, binfo, version);
368
}
369
370
static const struct scmi_protocol scmi_imx_bbm = {
371
.id = SCMI_PROTOCOL_IMX_BBM,
372
.owner = THIS_MODULE,
373
.instance_init = &scmi_imx_bbm_protocol_init,
374
.ops = &scmi_imx_bbm_proto_ops,
375
.events = &scmi_imx_bbm_protocol_events,
376
.supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,
377
.vendor_id = SCMI_IMX_VENDOR,
378
.sub_vendor_id = SCMI_IMX_SUBVENDOR,
379
};
380
module_scmi_protocol(scmi_imx_bbm);
381
382
MODULE_ALIAS("scmi-protocol-" __stringify(SCMI_PROTOCOL_IMX_BBM) "-" SCMI_IMX_VENDOR);
383
MODULE_DESCRIPTION("i.MX SCMI BBM driver");
384
MODULE_LICENSE("GPL");
385
386