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