1 // SPDX-License-Identifier: GPL-2.0
3 * System Control and Management Interface (SCMI) System Power Protocol
5 * Copyright (C) 2020-2022 ARM Ltd.
8 #define pr_fmt(fmt) "SCMI Notifications SYSTEM - " fmt
10 #include <linux/module.h>
11 #include <linux/scmi_protocol.h>
13 #include "protocols.h"
16 /* Updated only after ALL the mandatory features for that version are merged */
17 #define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20001
19 #define SCMI_SYSTEM_NUM_SOURCES 1
21 enum scmi_system_protocol_cmd
{
22 SYSTEM_POWER_STATE_NOTIFY
= 0x5,
25 struct scmi_system_power_state_notify
{
29 struct scmi_system_power_state_notifier_payld
{
36 struct scmi_system_info
{
38 bool graceful_timeout_supported
;
39 bool power_state_notify_cmd
;
42 static bool scmi_system_notify_supported(const struct scmi_protocol_handle
*ph
,
43 u8 evt_id
, u32 src_id
)
45 struct scmi_system_info
*pinfo
= ph
->get_priv(ph
);
47 if (evt_id
!= SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER
)
50 return pinfo
->power_state_notify_cmd
;
53 static int scmi_system_request_notify(const struct scmi_protocol_handle
*ph
,
58 struct scmi_system_power_state_notify
*notify
;
60 ret
= ph
->xops
->xfer_get_init(ph
, SYSTEM_POWER_STATE_NOTIFY
,
61 sizeof(*notify
), 0, &t
);
66 notify
->notify_enable
= enable
? cpu_to_le32(BIT(0)) : 0;
68 ret
= ph
->xops
->do_xfer(ph
, t
);
70 ph
->xops
->xfer_put(ph
, t
);
74 static int scmi_system_set_notify_enabled(const struct scmi_protocol_handle
*ph
,
75 u8 evt_id
, u32 src_id
, bool enable
)
79 ret
= scmi_system_request_notify(ph
, enable
);
81 pr_debug("FAIL_ENABLE - evt[%X] - ret:%d\n", evt_id
, ret
);
87 scmi_system_fill_custom_report(const struct scmi_protocol_handle
*ph
,
88 u8 evt_id
, ktime_t timestamp
,
89 const void *payld
, size_t payld_sz
,
90 void *report
, u32
*src_id
)
93 const struct scmi_system_power_state_notifier_payld
*p
= payld
;
94 struct scmi_system_power_state_notifier_report
*r
= report
;
95 struct scmi_system_info
*pinfo
= ph
->get_priv(ph
);
97 expected_sz
= pinfo
->graceful_timeout_supported
?
98 sizeof(*p
) : sizeof(*p
) - sizeof(__le32
);
99 if (evt_id
!= SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER
||
100 payld_sz
!= expected_sz
)
103 r
->timestamp
= timestamp
;
104 r
->agent_id
= le32_to_cpu(p
->agent_id
);
105 r
->flags
= le32_to_cpu(p
->flags
);
106 r
->system_state
= le32_to_cpu(p
->system_state
);
107 if (pinfo
->graceful_timeout_supported
&&
108 r
->system_state
== SCMI_SYSTEM_SHUTDOWN
&&
109 SCMI_SYSPOWER_IS_REQUEST_GRACEFUL(r
->flags
))
110 r
->timeout
= le32_to_cpu(p
->timeout
);
118 static const struct scmi_event system_events
[] = {
120 .id
= SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER
,
122 sizeof(struct scmi_system_power_state_notifier_payld
),
124 sizeof(struct scmi_system_power_state_notifier_report
),
128 static const struct scmi_event_ops system_event_ops
= {
129 .is_notify_supported
= scmi_system_notify_supported
,
130 .set_notify_enabled
= scmi_system_set_notify_enabled
,
131 .fill_custom_report
= scmi_system_fill_custom_report
,
134 static const struct scmi_protocol_events system_protocol_events
= {
135 .queue_sz
= SCMI_PROTO_QUEUE_SZ
,
136 .ops
= &system_event_ops
,
137 .evts
= system_events
,
138 .num_events
= ARRAY_SIZE(system_events
),
139 .num_sources
= SCMI_SYSTEM_NUM_SOURCES
,
142 static int scmi_system_protocol_init(const struct scmi_protocol_handle
*ph
)
146 struct scmi_system_info
*pinfo
;
148 ret
= ph
->xops
->version_get(ph
, &version
);
152 dev_dbg(ph
->dev
, "System Power Version %d.%d\n",
153 PROTOCOL_REV_MAJOR(version
), PROTOCOL_REV_MINOR(version
));
155 pinfo
= devm_kzalloc(ph
->dev
, sizeof(*pinfo
), GFP_KERNEL
);
159 pinfo
->version
= version
;
160 if (PROTOCOL_REV_MAJOR(pinfo
->version
) >= 0x2)
161 pinfo
->graceful_timeout_supported
= true;
163 if (!ph
->hops
->protocol_msg_check(ph
, SYSTEM_POWER_STATE_NOTIFY
, NULL
))
164 pinfo
->power_state_notify_cmd
= true;
166 return ph
->set_priv(ph
, pinfo
, version
);
169 static const struct scmi_protocol scmi_system
= {
170 .id
= SCMI_PROTOCOL_SYSTEM
,
171 .owner
= THIS_MODULE
,
172 .instance_init
= &scmi_system_protocol_init
,
174 .events
= &system_protocol_events
,
175 .supported_version
= SCMI_PROTOCOL_SUPPORTED_VERSION
,
178 DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(system
, scmi_system
)