1 // SPDX-License-Identifier: GPL-2.0
3 * System control and Management Interface (SCMI) NXP MISC Protocol
8 #define pr_fmt(fmt) "SCMI Notifications MISC - " fmt
10 #include <linux/bits.h>
12 #include <linux/module.h>
14 #include <linux/platform_device.h>
15 #include <linux/scmi_protocol.h>
16 #include <linux/scmi_imx_protocol.h>
18 #include "../../protocols.h"
19 #include "../../notify.h"
21 #define SCMI_PROTOCOL_SUPPORTED_VERSION 0x10000
23 #define MAX_MISC_CTRL_SOURCES GENMASK(15, 0)
25 enum scmi_imx_misc_protocol_cmd
{
26 SCMI_IMX_MISC_CTRL_SET
= 0x3,
27 SCMI_IMX_MISC_CTRL_GET
= 0x4,
28 SCMI_IMX_MISC_CTRL_NOTIFY
= 0x8,
31 struct scmi_imx_misc_info
{
38 struct scmi_msg_imx_misc_protocol_attributes
{
42 #define GET_BRD_CTRLS_NR(x) le32_get_bits((x), GENMASK(31, 24))
43 #define GET_REASONS_NR(x) le32_get_bits((x), GENMASK(23, 16))
44 #define GET_DEV_CTRLS_NR(x) le32_get_bits((x), GENMASK(15, 0))
45 #define BRD_CTRL_START_ID BIT(15)
47 struct scmi_imx_misc_ctrl_set_in
{
53 struct scmi_imx_misc_ctrl_notify_in
{
58 struct scmi_imx_misc_ctrl_notify_payld
{
63 struct scmi_imx_misc_ctrl_get_out
{
68 static int scmi_imx_misc_attributes_get(const struct scmi_protocol_handle
*ph
,
69 struct scmi_imx_misc_info
*mi
)
73 struct scmi_msg_imx_misc_protocol_attributes
*attr
;
75 ret
= ph
->xops
->xfer_get_init(ph
, PROTOCOL_ATTRIBUTES
, 0,
82 ret
= ph
->xops
->do_xfer(ph
, t
);
84 mi
->nr_dev_ctrl
= GET_DEV_CTRLS_NR(attr
->attributes
);
85 mi
->nr_brd_ctrl
= GET_BRD_CTRLS_NR(attr
->attributes
);
86 mi
->nr_reason
= GET_REASONS_NR(attr
->attributes
);
87 dev_info(ph
->dev
, "i.MX MISC NUM DEV CTRL: %d, NUM BRD CTRL: %d,NUM Reason: %d\n",
88 mi
->nr_dev_ctrl
, mi
->nr_brd_ctrl
, mi
->nr_reason
);
91 ph
->xops
->xfer_put(ph
, t
);
96 static int scmi_imx_misc_ctrl_validate_id(const struct scmi_protocol_handle
*ph
,
99 struct scmi_imx_misc_info
*mi
= ph
->get_priv(ph
);
102 * [0, BRD_CTRL_START_ID) is for Dev Ctrl which is SOC related
103 * [BRD_CTRL_START_ID, 0xffff) is for Board Ctrl which is board related
105 if (ctrl_id
< BRD_CTRL_START_ID
&& ctrl_id
> mi
->nr_dev_ctrl
)
107 if (ctrl_id
>= BRD_CTRL_START_ID
+ mi
->nr_brd_ctrl
)
113 static int scmi_imx_misc_ctrl_notify(const struct scmi_protocol_handle
*ph
,
114 u32 ctrl_id
, u32 evt_id
, u32 flags
)
116 struct scmi_imx_misc_ctrl_notify_in
*in
;
120 ret
= scmi_imx_misc_ctrl_validate_id(ph
, ctrl_id
);
124 ret
= ph
->xops
->xfer_get_init(ph
, SCMI_IMX_MISC_CTRL_NOTIFY
,
130 in
->ctrl_id
= cpu_to_le32(ctrl_id
);
131 in
->flags
= cpu_to_le32(flags
);
133 ret
= ph
->xops
->do_xfer(ph
, t
);
135 ph
->xops
->xfer_put(ph
, t
);
141 scmi_imx_misc_ctrl_set_notify_enabled(const struct scmi_protocol_handle
*ph
,
142 u8 evt_id
, u32 src_id
, bool enable
)
146 /* misc_ctrl_req_notify is for enablement */
150 ret
= scmi_imx_misc_ctrl_notify(ph
, src_id
, evt_id
, 0);
152 dev_err(ph
->dev
, "FAIL_ENABLED - evt[%X] src[%d] - ret:%d\n",
153 evt_id
, src_id
, ret
);
159 scmi_imx_misc_ctrl_fill_custom_report(const struct scmi_protocol_handle
*ph
,
160 u8 evt_id
, ktime_t timestamp
,
161 const void *payld
, size_t payld_sz
,
162 void *report
, u32
*src_id
)
164 const struct scmi_imx_misc_ctrl_notify_payld
*p
= payld
;
165 struct scmi_imx_misc_ctrl_notify_report
*r
= report
;
167 if (sizeof(*p
) != payld_sz
)
170 r
->timestamp
= timestamp
;
171 r
->ctrl_id
= le32_to_cpu(p
->ctrl_id
);
172 r
->flags
= le32_to_cpu(p
->flags
);
174 *src_id
= r
->ctrl_id
;
175 dev_dbg(ph
->dev
, "%s: ctrl_id: %d flags: %d\n", __func__
,
176 r
->ctrl_id
, r
->flags
);
181 static const struct scmi_event_ops scmi_imx_misc_event_ops
= {
182 .set_notify_enabled
= scmi_imx_misc_ctrl_set_notify_enabled
,
183 .fill_custom_report
= scmi_imx_misc_ctrl_fill_custom_report
,
186 static const struct scmi_event scmi_imx_misc_events
[] = {
188 .id
= SCMI_EVENT_IMX_MISC_CONTROL
,
189 .max_payld_sz
= sizeof(struct scmi_imx_misc_ctrl_notify_payld
),
190 .max_report_sz
= sizeof(struct scmi_imx_misc_ctrl_notify_report
),
194 static struct scmi_protocol_events scmi_imx_misc_protocol_events
= {
195 .queue_sz
= SCMI_PROTO_QUEUE_SZ
,
196 .ops
= &scmi_imx_misc_event_ops
,
197 .evts
= scmi_imx_misc_events
,
198 .num_events
= ARRAY_SIZE(scmi_imx_misc_events
),
199 .num_sources
= MAX_MISC_CTRL_SOURCES
,
202 static int scmi_imx_misc_ctrl_get(const struct scmi_protocol_handle
*ph
,
203 u32 ctrl_id
, u32
*num
, u32
*val
)
205 struct scmi_imx_misc_ctrl_get_out
*out
;
208 int max_msg_size
= ph
->hops
->get_max_msg_size(ph
);
209 int max_num
= (max_msg_size
- sizeof(*out
)) / sizeof(__le32
);
211 ret
= scmi_imx_misc_ctrl_validate_id(ph
, ctrl_id
);
215 ret
= ph
->xops
->xfer_get_init(ph
, SCMI_IMX_MISC_CTRL_GET
, sizeof(u32
),
220 put_unaligned_le32(ctrl_id
, t
->tx
.buf
);
221 ret
= ph
->xops
->do_xfer(ph
, t
);
224 *num
= le32_to_cpu(out
->num
);
226 if (*num
>= max_num
||
227 *num
* sizeof(__le32
) > t
->rx
.len
- sizeof(__le32
)) {
228 ph
->xops
->xfer_put(ph
, t
);
232 for (i
= 0; i
< *num
; i
++)
233 val
[i
] = le32_to_cpu(out
->val
[i
]);
236 ph
->xops
->xfer_put(ph
, t
);
241 static int scmi_imx_misc_ctrl_set(const struct scmi_protocol_handle
*ph
,
242 u32 ctrl_id
, u32 num
, u32
*val
)
244 struct scmi_imx_misc_ctrl_set_in
*in
;
247 int max_msg_size
= ph
->hops
->get_max_msg_size(ph
);
248 int max_num
= (max_msg_size
- sizeof(*in
)) / sizeof(__le32
);
250 ret
= scmi_imx_misc_ctrl_validate_id(ph
, ctrl_id
);
257 ret
= ph
->xops
->xfer_get_init(ph
, SCMI_IMX_MISC_CTRL_SET
, sizeof(*in
),
263 in
->id
= cpu_to_le32(ctrl_id
);
264 in
->num
= cpu_to_le32(num
);
265 for (i
= 0; i
< num
; i
++)
266 in
->value
[i
] = cpu_to_le32(val
[i
]);
268 ret
= ph
->xops
->do_xfer(ph
, t
);
270 ph
->xops
->xfer_put(ph
, t
);
275 static const struct scmi_imx_misc_proto_ops scmi_imx_misc_proto_ops
= {
276 .misc_ctrl_set
= scmi_imx_misc_ctrl_set
,
277 .misc_ctrl_get
= scmi_imx_misc_ctrl_get
,
278 .misc_ctrl_req_notify
= scmi_imx_misc_ctrl_notify
,
281 static int scmi_imx_misc_protocol_init(const struct scmi_protocol_handle
*ph
)
283 struct scmi_imx_misc_info
*minfo
;
287 ret
= ph
->xops
->version_get(ph
, &version
);
291 dev_info(ph
->dev
, "NXP SM MISC Version %d.%d\n",
292 PROTOCOL_REV_MAJOR(version
), PROTOCOL_REV_MINOR(version
));
294 minfo
= devm_kzalloc(ph
->dev
, sizeof(*minfo
), GFP_KERNEL
);
298 ret
= scmi_imx_misc_attributes_get(ph
, minfo
);
302 return ph
->set_priv(ph
, minfo
, version
);
305 static const struct scmi_protocol scmi_imx_misc
= {
306 .id
= SCMI_PROTOCOL_IMX_MISC
,
307 .owner
= THIS_MODULE
,
308 .instance_init
= &scmi_imx_misc_protocol_init
,
309 .ops
= &scmi_imx_misc_proto_ops
,
310 .events
= &scmi_imx_misc_protocol_events
,
311 .supported_version
= SCMI_PROTOCOL_SUPPORTED_VERSION
,
313 .sub_vendor_id
= "IMX",
315 module_scmi_protocol(scmi_imx_misc
);
317 MODULE_DESCRIPTION("i.MX SCMI MISC driver");
318 MODULE_LICENSE("GPL");