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