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