1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * System Control and Management Interface (SCMI) System Power Protocol 4 * 5 * Copyright (C) 2020 ARM Ltd. 6 */ 7 8 #define pr_fmt(fmt) "SCMI Notifications SYSTEM - " fmt 9 10 #include <linux/scmi_protocol.h> 11 12 #include "common.h" 13 #include "notify.h" 14 15 #define SCMI_SYSTEM_NUM_SOURCES 1 16 17 enum scmi_system_protocol_cmd { 18 SYSTEM_POWER_STATE_NOTIFY = 0x5, 19 }; 20 21 struct scmi_system_power_state_notify { 22 __le32 notify_enable; 23 }; 24 25 struct scmi_system_power_state_notifier_payld { 26 __le32 agent_id; 27 __le32 flags; 28 __le32 system_state; 29 }; 30 31 struct scmi_system_info { 32 u32 version; 33 }; 34 35 static int scmi_system_request_notify(const struct scmi_handle *handle, 36 bool enable) 37 { 38 int ret; 39 struct scmi_xfer *t; 40 struct scmi_system_power_state_notify *notify; 41 42 ret = scmi_xfer_get_init(handle, SYSTEM_POWER_STATE_NOTIFY, 43 SCMI_PROTOCOL_SYSTEM, sizeof(*notify), 0, &t); 44 if (ret) 45 return ret; 46 47 notify = t->tx.buf; 48 notify->notify_enable = enable ? cpu_to_le32(BIT(0)) : 0; 49 50 ret = scmi_do_xfer(handle, t); 51 52 scmi_xfer_put(handle, t); 53 return ret; 54 } 55 56 static int scmi_system_set_notify_enabled(const struct scmi_handle *handle, 57 u8 evt_id, u32 src_id, bool enable) 58 { 59 int ret; 60 61 ret = scmi_system_request_notify(handle, enable); 62 if (ret) 63 pr_debug("FAIL_ENABLE - evt[%X] - ret:%d\n", evt_id, ret); 64 65 return ret; 66 } 67 68 static void *scmi_system_fill_custom_report(const struct scmi_handle *handle, 69 u8 evt_id, ktime_t timestamp, 70 const void *payld, size_t payld_sz, 71 void *report, u32 *src_id) 72 { 73 const struct scmi_system_power_state_notifier_payld *p = payld; 74 struct scmi_system_power_state_notifier_report *r = report; 75 76 if (evt_id != SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER || 77 sizeof(*p) != payld_sz) 78 return NULL; 79 80 r->timestamp = timestamp; 81 r->agent_id = le32_to_cpu(p->agent_id); 82 r->flags = le32_to_cpu(p->flags); 83 r->system_state = le32_to_cpu(p->system_state); 84 *src_id = 0; 85 86 return r; 87 } 88 89 static const struct scmi_event system_events[] = { 90 { 91 .id = SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER, 92 .max_payld_sz = 93 sizeof(struct scmi_system_power_state_notifier_payld), 94 .max_report_sz = 95 sizeof(struct scmi_system_power_state_notifier_report), 96 }, 97 }; 98 99 static const struct scmi_event_ops system_event_ops = { 100 .set_notify_enabled = scmi_system_set_notify_enabled, 101 .fill_custom_report = scmi_system_fill_custom_report, 102 }; 103 104 static int scmi_system_protocol_init(struct scmi_handle *handle) 105 { 106 u32 version; 107 struct scmi_system_info *pinfo; 108 109 scmi_version_get(handle, SCMI_PROTOCOL_SYSTEM, &version); 110 111 dev_dbg(handle->dev, "System Power Version %d.%d\n", 112 PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); 113 114 pinfo = devm_kzalloc(handle->dev, sizeof(*pinfo), GFP_KERNEL); 115 if (!pinfo) 116 return -ENOMEM; 117 118 scmi_register_protocol_events(handle, 119 SCMI_PROTOCOL_SYSTEM, SCMI_PROTO_QUEUE_SZ, 120 &system_event_ops, 121 system_events, 122 ARRAY_SIZE(system_events), 123 SCMI_SYSTEM_NUM_SOURCES); 124 125 pinfo->version = version; 126 handle->system_priv = pinfo; 127 128 return 0; 129 } 130 131 DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_SYSTEM, system) 132