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 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 35*b46d8527SCristian Marussi static int scmi_system_request_notify(const struct scmi_protocol_handle *ph, 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 42*b46d8527SCristian Marussi ret = ph->xops->xfer_get_init(ph, SYSTEM_POWER_STATE_NOTIFY, 43*b46d8527SCristian Marussi 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 50*b46d8527SCristian Marussi ret = ph->xops->do_xfer(ph, t); 51a8803055SCristian Marussi 52*b46d8527SCristian Marussi ph->xops->xfer_put(ph, t); 53a8803055SCristian Marussi return ret; 54a8803055SCristian Marussi } 55a8803055SCristian Marussi 56*b46d8527SCristian Marussi static int scmi_system_set_notify_enabled(const void *ph, 57a8803055SCristian Marussi u8 evt_id, u32 src_id, bool enable) 58a8803055SCristian Marussi { 59a8803055SCristian Marussi int ret; 60a8803055SCristian Marussi 61*b46d8527SCristian Marussi ret = scmi_system_request_notify(ph, 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 68*b46d8527SCristian Marussi static void *scmi_system_fill_custom_report(const void *ph, 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 104533c7095SCristian Marussi static const struct scmi_protocol_events system_protocol_events = { 105533c7095SCristian Marussi .queue_sz = SCMI_PROTO_QUEUE_SZ, 106533c7095SCristian Marussi .ops = &system_event_ops, 107533c7095SCristian Marussi .evts = system_events, 108533c7095SCristian Marussi .num_events = ARRAY_SIZE(system_events), 109533c7095SCristian Marussi .num_sources = SCMI_SYSTEM_NUM_SOURCES, 110533c7095SCristian Marussi }; 111533c7095SCristian Marussi 112*b46d8527SCristian Marussi static int scmi_system_protocol_init(const struct scmi_protocol_handle *ph) 113a8803055SCristian Marussi { 114a8803055SCristian Marussi u32 version; 115a8803055SCristian Marussi struct scmi_system_info *pinfo; 116a8803055SCristian Marussi 117*b46d8527SCristian Marussi ph->xops->version_get(ph, &version); 118a8803055SCristian Marussi 119*b46d8527SCristian Marussi dev_dbg(ph->dev, "System Power Version %d.%d\n", 120a8803055SCristian Marussi PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); 121a8803055SCristian Marussi 122*b46d8527SCristian Marussi pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL); 123a8803055SCristian Marussi if (!pinfo) 124a8803055SCristian Marussi return -ENOMEM; 125a8803055SCristian Marussi 126a8803055SCristian Marussi pinfo->version = version; 127*b46d8527SCristian Marussi return ph->set_priv(ph, pinfo); 128a8803055SCristian Marussi } 129a8803055SCristian Marussi 13048dc16e2SCristian Marussi static const struct scmi_protocol scmi_system = { 13148dc16e2SCristian Marussi .id = SCMI_PROTOCOL_SYSTEM, 132*b46d8527SCristian Marussi .instance_init = &scmi_system_protocol_init, 13348dc16e2SCristian Marussi .ops = NULL, 134533c7095SCristian Marussi .events = &system_protocol_events, 13548dc16e2SCristian Marussi }; 13648dc16e2SCristian Marussi 13748dc16e2SCristian Marussi DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(system, scmi_system) 138