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