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 /* Updated only after ALL the mandatory features for that version are merged */ 17 #define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20000 18 19 #define SCMI_SYSTEM_NUM_SOURCES 1 20 21 enum scmi_system_protocol_cmd { 22 SYSTEM_POWER_STATE_NOTIFY = 0x5, 23 }; 24 25 struct scmi_system_power_state_notify { 26 __le32 notify_enable; 27 }; 28 29 struct scmi_system_power_state_notifier_payld { 30 __le32 agent_id; 31 __le32 flags; 32 __le32 system_state; 33 __le32 timeout; 34 }; 35 36 struct scmi_system_info { 37 u32 version; 38 bool graceful_timeout_supported; 39 }; 40 41 static int scmi_system_request_notify(const struct scmi_protocol_handle *ph, 42 bool enable) 43 { 44 int ret; 45 struct scmi_xfer *t; 46 struct scmi_system_power_state_notify *notify; 47 48 ret = ph->xops->xfer_get_init(ph, SYSTEM_POWER_STATE_NOTIFY, 49 sizeof(*notify), 0, &t); 50 if (ret) 51 return ret; 52 53 notify = t->tx.buf; 54 notify->notify_enable = enable ? cpu_to_le32(BIT(0)) : 0; 55 56 ret = ph->xops->do_xfer(ph, t); 57 58 ph->xops->xfer_put(ph, t); 59 return ret; 60 } 61 62 static int scmi_system_set_notify_enabled(const struct scmi_protocol_handle *ph, 63 u8 evt_id, u32 src_id, bool enable) 64 { 65 int ret; 66 67 ret = scmi_system_request_notify(ph, enable); 68 if (ret) 69 pr_debug("FAIL_ENABLE - evt[%X] - ret:%d\n", evt_id, ret); 70 71 return ret; 72 } 73 74 static void * 75 scmi_system_fill_custom_report(const struct scmi_protocol_handle *ph, 76 u8 evt_id, ktime_t timestamp, 77 const void *payld, size_t payld_sz, 78 void *report, u32 *src_id) 79 { 80 size_t expected_sz; 81 const struct scmi_system_power_state_notifier_payld *p = payld; 82 struct scmi_system_power_state_notifier_report *r = report; 83 struct scmi_system_info *pinfo = ph->get_priv(ph); 84 85 expected_sz = pinfo->graceful_timeout_supported ? 86 sizeof(*p) : sizeof(*p) - sizeof(__le32); 87 if (evt_id != SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER || 88 payld_sz != expected_sz) 89 return NULL; 90 91 r->timestamp = timestamp; 92 r->agent_id = le32_to_cpu(p->agent_id); 93 r->flags = le32_to_cpu(p->flags); 94 r->system_state = le32_to_cpu(p->system_state); 95 if (pinfo->graceful_timeout_supported && 96 r->system_state == SCMI_SYSTEM_SHUTDOWN && 97 SCMI_SYSPOWER_IS_REQUEST_GRACEFUL(r->flags)) 98 r->timeout = le32_to_cpu(p->timeout); 99 else 100 r->timeout = 0x00; 101 *src_id = 0; 102 103 return r; 104 } 105 106 static const struct scmi_event system_events[] = { 107 { 108 .id = SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER, 109 .max_payld_sz = 110 sizeof(struct scmi_system_power_state_notifier_payld), 111 .max_report_sz = 112 sizeof(struct scmi_system_power_state_notifier_report), 113 }, 114 }; 115 116 static const struct scmi_event_ops system_event_ops = { 117 .set_notify_enabled = scmi_system_set_notify_enabled, 118 .fill_custom_report = scmi_system_fill_custom_report, 119 }; 120 121 static const struct scmi_protocol_events system_protocol_events = { 122 .queue_sz = SCMI_PROTO_QUEUE_SZ, 123 .ops = &system_event_ops, 124 .evts = system_events, 125 .num_events = ARRAY_SIZE(system_events), 126 .num_sources = SCMI_SYSTEM_NUM_SOURCES, 127 }; 128 129 static int scmi_system_protocol_init(const struct scmi_protocol_handle *ph) 130 { 131 int ret; 132 u32 version; 133 struct scmi_system_info *pinfo; 134 135 ret = ph->xops->version_get(ph, &version); 136 if (ret) 137 return ret; 138 139 dev_dbg(ph->dev, "System Power Version %d.%d\n", 140 PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); 141 142 pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL); 143 if (!pinfo) 144 return -ENOMEM; 145 146 pinfo->version = version; 147 if (PROTOCOL_REV_MAJOR(pinfo->version) >= 0x2) 148 pinfo->graceful_timeout_supported = true; 149 150 return ph->set_priv(ph, pinfo, version); 151 } 152 153 static const struct scmi_protocol scmi_system = { 154 .id = SCMI_PROTOCOL_SYSTEM, 155 .owner = THIS_MODULE, 156 .instance_init = &scmi_system_protocol_init, 157 .ops = NULL, 158 .events = &system_protocol_events, 159 .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION, 160 }; 161 162 DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(system, scmi_system) 163