1 /*
2 * Arm SCP/MCP Software
3 * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 *
7 * Description:
8 * SCMI power capping and monitoring protocol completer.
9 */
10 #include "fwk_mm.h"
11 #include "fwk_module_idx.h"
12 #include "internal/scmi_power_capping_protocol.h"
13 #include "mod_power_allocator.h"
14 #include "mod_power_meter.h"
15
16 #ifdef BUILD_HAS_SCMI_POWER_CAPPING_FAST_CHANNELS_COMMANDS
17 # include "internal/scmi_power_capping.h"
18 # include "internal/scmi_power_capping_fast_channels.h"
19 #endif
20
21 #include <fwk_module.h>
22
23 struct mod_scmi_power_capping_power_apis power_management_apis;
24
25 #ifdef BUILD_HAS_SCMI_POWER_CAPPING_FAST_CHANNELS_COMMANDS
26 static const fwk_id_t mod_scmi_power_capping_event_id_fch_callback =
27 FWK_ID_EVENT_INIT(
28 FWK_MODULE_IDX_SCMI_POWER_CAPPING,
29 SCMI_POWER_CAPPING_EVENT_IDX_FAST_CHANNELS_PROCESS);
30 #endif
31
scmi_power_capping_power_api_bind(struct mod_scmi_power_capping_power_apis * power_apis)32 static int scmi_power_capping_power_api_bind(
33 struct mod_scmi_power_capping_power_apis *power_apis)
34 {
35 int status;
36
37 status = fwk_module_bind(
38 FWK_ID_MODULE(FWK_MODULE_IDX_POWER_ALLOCATOR),
39 FWK_ID_API(
40 FWK_MODULE_IDX_POWER_ALLOCATOR, MOD_POWER_ALLOCATOR_API_IDX_CAP),
41 &(power_apis->power_allocator_api));
42
43 if (status != FWK_SUCCESS) {
44 return status;
45 }
46
47 status = fwk_module_bind(
48 FWK_ID_MODULE(FWK_MODULE_IDX_POWER_COORDINATOR),
49 FWK_ID_API(
50 FWK_MODULE_IDX_POWER_COORDINATOR,
51 MOD_POWER_COORDINATOR_API_IDX_PERIOD),
52 &(power_apis->power_coordinator_api));
53
54 if (status != FWK_SUCCESS) {
55 return status;
56 }
57
58 return fwk_module_bind(
59 FWK_ID_MODULE(FWK_MODULE_IDX_POWER_METER),
60 FWK_ID_API(
61 FWK_MODULE_IDX_POWER_METER, MOD_POWER_METER_API_IDX_MEASUREMENT),
62 &(power_apis->power_meter_api));
63 }
64
65 #ifdef BUILD_HAS_SCMI_NOTIFICATIONS
66 static const fwk_id_t mod_scmi_power_capping_event_id_cap_pai_notify =
67 FWK_ID_EVENT_INIT(
68 FWK_MODULE_IDX_SCMI_POWER_CAPPING,
69 SCMI_POWER_CAPPING_EVENT_IDX_CAP_PAI_NOTIFY_PROCESS);
70 static const fwk_id_t mod_scmi_power_capping_event_id_measurement_notify =
71 FWK_ID_EVENT_INIT(
72 FWK_MODULE_IDX_SCMI_POWER_CAPPING,
73 SCMI_POWER_CAPPING_EVENT_IDX_MEASUREMENT_NOTIFY_PROCESS);
74 #endif
75
scmi_power_capping_init(fwk_id_t module_id,unsigned int element_count,const void * data)76 static int scmi_power_capping_init(
77 fwk_id_t module_id,
78 unsigned int element_count,
79 const void *data)
80 {
81 if (element_count == 0) {
82 return FWK_E_SUPPORT;
83 }
84
85 struct mod_scmi_power_capping_context ctx;
86
87 ctx.power_capping_domain_ctx_table = fwk_mm_calloc(
88 element_count, sizeof(struct mod_scmi_power_capping_domain_context));
89 ctx.domain_count = element_count;
90 #ifdef BUILD_HAS_SCMI_POWER_CAPPING_STD_COMMANDS
91 pcapping_protocol_init(&ctx);
92 #endif
93
94 #ifdef BUILD_HAS_SCMI_POWER_CAPPING_FAST_CHANNELS_COMMANDS
95 pcapping_fast_channel_ctx_init(&ctx);
96 #endif
97
98 return FWK_SUCCESS;
99 }
100
scmi_power_capping_element_init(fwk_id_t element_id,unsigned int sub_element_count,const void * data)101 static int scmi_power_capping_element_init(
102 fwk_id_t element_id,
103 unsigned int sub_element_count,
104 const void *data)
105 {
106 const struct mod_scmi_power_capping_domain_config *config;
107 unsigned int domain_idx;
108 #ifdef BUILD_HAS_SCMI_POWER_CAPPING_STD_COMMANDS
109 int status;
110 #endif
111
112 if (data == NULL) {
113 return FWK_E_PARAM;
114 }
115
116 config = (const struct mod_scmi_power_capping_domain_config *)data;
117 domain_idx = fwk_id_get_element_idx(element_id);
118
119 #ifdef BUILD_HAS_SCMI_POWER_CAPPING_STD_COMMANDS
120 status = pcapping_protocol_domain_init(domain_idx, config);
121 if (status != FWK_SUCCESS) {
122 return status;
123 }
124 #endif
125
126 #ifdef BUILD_HAS_SCMI_POWER_CAPPING_FAST_CHANNELS_COMMANDS
127 pcapping_fast_channel_set_domain_config(domain_idx, config);
128 #endif
129 return FWK_SUCCESS;
130 }
131
scmi_power_capping_bind(fwk_id_t id,unsigned int round)132 static int scmi_power_capping_bind(fwk_id_t id, unsigned int round)
133 {
134 int status = FWK_E_INIT;
135
136 if ((round == 1) || (fwk_id_is_type(id, FWK_ID_TYPE_ELEMENT))) {
137 return FWK_SUCCESS;
138 }
139 status = scmi_power_capping_power_api_bind(&power_management_apis);
140 #ifdef BUILD_HAS_SCMI_POWER_CAPPING_STD_COMMANDS
141 if (status != FWK_SUCCESS) {
142 return status;
143 }
144
145 status = pcapping_protocol_bind();
146
147 if (status != FWK_SUCCESS) {
148 return status;
149 }
150 pcapping_protocol_set_power_apis(&power_management_apis);
151 #endif
152
153 #ifdef BUILD_HAS_SCMI_POWER_CAPPING_FAST_CHANNELS_COMMANDS
154 status = pcapping_fast_channel_bind();
155 if (status != FWK_SUCCESS) {
156 return status;
157 }
158 pcapping_fast_channel_set_power_apis(&power_management_apis);
159 #endif
160 return status;
161 }
162
scmi_power_capping_start(fwk_id_t id)163 static int scmi_power_capping_start(fwk_id_t id)
164 {
165 #ifdef BUILD_HAS_SCMI_POWER_CAPPING_FAST_CHANNELS_COMMANDS
166 pcapping_fast_channel_start();
167 #endif
168
169 #ifdef BUILD_HAS_SCMI_POWER_CAPPING_STD_COMMANDS
170 return pcapping_protocol_start(id);
171 #else
172 return FWK_SUCCESS;
173 #endif
174 }
175
scmi_power_capping_process_notification(const struct fwk_event * event,struct fwk_event * resp_event)176 static int scmi_power_capping_process_notification(
177 const struct fwk_event *event,
178 struct fwk_event *resp_event)
179 {
180 #ifdef BUILD_HAS_SCMI_POWER_CAPPING_STD_COMMANDS
181 return pcapping_protocol_process_fwk_notification(event);
182 #else
183 return FWK_SUCCESS;
184 #endif
185 }
186
187 #ifdef BUILD_HAS_SCMI_POWER_CAPPING_STD_COMMANDS
scmi_power_capping_process_bind_request(fwk_id_t source_id,fwk_id_t target_id,fwk_id_t api_id,const void ** api)188 static int scmi_power_capping_process_bind_request(
189 fwk_id_t source_id,
190 fwk_id_t target_id,
191 fwk_id_t api_id,
192 const void **api)
193 {
194 if (fwk_id_is_equal(source_id, FWK_ID_MODULE(FWK_MODULE_IDX_SCMI))) {
195 return pcapping_protocol_process_bind_request(api_id, api);
196 }
197
198 return FWK_E_ACCESS;
199 }
200 #endif
201
scmi_power_capping_process_event(const struct fwk_event * event,struct fwk_event * resp_event)202 static int scmi_power_capping_process_event(
203 const struct fwk_event *event,
204 struct fwk_event *resp_event)
205 {
206 #ifdef BUILD_HAS_SCMI_POWER_CAPPING_FAST_CHANNELS_COMMANDS
207 if (fwk_id_is_equal(
208 event->id, mod_scmi_power_capping_event_id_fch_callback)) {
209 return pcapping_fast_channel_process_event(event);
210 }
211 #endif
212
213 #ifdef BUILD_HAS_SCMI_NOTIFICATIONS
214 if (fwk_id_is_equal(
215 event->id, mod_scmi_power_capping_event_id_cap_pai_notify)) {
216 return pcapping_protocol_process_cap_pai_notify_event(event);
217 }
218
219 if (fwk_id_is_equal(
220 event->id, mod_scmi_power_capping_event_id_measurement_notify)) {
221 return pcapping_protocol_process_measurements_notify_event(event);
222 }
223 #endif
224 return FWK_E_PARAM;
225 }
226
227 const struct fwk_module module_scmi_power_capping = {
228 .type = FWK_MODULE_TYPE_PROTOCOL,
229 .api_count = (unsigned int)MOD_SCMI_POWER_CAPPING_API_IDX_COUNT,
230 #ifdef BUILD_HAS_SCMI_POWER_CAPPING_FAST_CHANNELS_COMMANDS
231 .event_count = (unsigned int)SCMI_POWER_CAPPING_EVENT_COUNT,
232 #endif
233 .init = scmi_power_capping_init,
234 .element_init = scmi_power_capping_element_init,
235 .bind = scmi_power_capping_bind,
236 .start = scmi_power_capping_start,
237 .process_notification = scmi_power_capping_process_notification,
238 .process_event = scmi_power_capping_process_event,
239 #ifdef BUILD_HAS_SCMI_POWER_CAPPING_STD_COMMANDS
240 .process_bind_request = scmi_power_capping_process_bind_request,
241 #endif
242 };
243