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