1 /*
2 * Arm SCP/MCP Software
3 * Copyright (c) 2022-2023, Linaro Limited and Contributors. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #include <fwk_module.h>
9 #include <fwk_module_idx.h>
10 #include <fwk_assert.h>
11 #include <fwk_log.h>
12 #include <fwk_mm.h>
13 #include <mod_power_domain.h>
14 #include <mod_mock_ppu.h>
15 #ifdef BUILD_HAS_MOD_SYSTEM_POWER
16 #include <mod_system_power.h>
17 #endif
18
19 /* Power domain context */
20 struct mock_ppu_pd_ctx {
21 /* Power domain configuration data */
22 const struct mod_mock_ppu_pd_config *config;
23
24 /* PPU registers */
25 uint32_t *ppu;
26
27 /* Identifier of the entity bound to the power domain driver API */
28 fwk_id_t bound_id;
29
30 /* Power module driver input API */
31 struct mod_pd_driver_input_api *pd_driver_input_api;
32 };
33
34 /* Module context */
35 struct mock_ppu_ctx {
36 /* Table of the power domain contexts */
37 struct mock_ppu_pd_ctx *pd_ctx_table;
38 };
39
40 /*
41 * Internal variables
42 */
43
44 static struct mock_ppu_ctx mock_ppu_ctx;
45
46 /*
47 * Power domain driver interface
48 */
pd_set_state(fwk_id_t pd_id,unsigned int state)49 static int pd_set_state(fwk_id_t pd_id, unsigned int state)
50 {
51 int status;
52 struct mock_ppu_pd_ctx *pd_ctx;
53
54 pd_ctx = mock_ppu_ctx.pd_ctx_table + fwk_id_get_element_idx(pd_id);
55
56 fwk_assert(pd_ctx->pd_driver_input_api != NULL);
57
58 switch (state) {
59 case MOD_PD_STATE_ON:
60 *pd_ctx->ppu = MOD_PD_STATE_ON;
61 status = pd_ctx->pd_driver_input_api->report_power_state_transition(
62 pd_ctx->bound_id, MOD_PD_STATE_ON);
63 assert(status == FWK_SUCCESS);
64 break;
65
66 case MOD_PD_STATE_OFF:
67 *pd_ctx->ppu = MOD_PD_STATE_OFF;
68 status = pd_ctx->pd_driver_input_api->report_power_state_transition(
69 pd_ctx->bound_id, MOD_PD_STATE_OFF);
70 assert(status == FWK_SUCCESS);
71 break;
72
73 default:
74 FWK_LOG_ERR("[PD] Requested power state (%i) is not supported.\n", state);
75 return FWK_E_PARAM;
76 }
77
78 if (status != FWK_SUCCESS)
79 return FWK_E_PANIC;
80
81 return FWK_SUCCESS;
82 }
83
pd_get_state(fwk_id_t pd_id,unsigned int * state)84 static int pd_get_state(fwk_id_t pd_id, unsigned int *state)
85 {
86 struct mock_ppu_pd_ctx *pd_ctx;
87
88 pd_ctx = mock_ppu_ctx.pd_ctx_table + fwk_id_get_element_idx(pd_id);
89
90 *state = *pd_ctx->ppu;
91
92 return FWK_SUCCESS;
93 }
94
pd_reset(fwk_id_t pd_id)95 static int pd_reset(fwk_id_t pd_id)
96 {
97 struct mock_ppu_pd_ctx *pd_ctx;
98
99 pd_ctx = mock_ppu_ctx.pd_ctx_table + fwk_id_get_element_idx(pd_id);
100
101 *pd_ctx->ppu = MOD_PD_STATE_ON;
102
103 return FWK_SUCCESS;
104 }
105
ppu_v0_prepare_core_for_system_suspend(fwk_id_t core_pd_id)106 static int ppu_v0_prepare_core_for_system_suspend(fwk_id_t core_pd_id)
107 {
108 return FWK_SUCCESS;
109 }
110
111 static const struct mod_pd_driver_api pd_driver = {
112 .set_state = pd_set_state,
113 .get_state = pd_get_state,
114 .reset = pd_reset,
115 .prepare_core_for_system_suspend = ppu_v0_prepare_core_for_system_suspend,
116 };
117
118 /*
119 * Framework handlers
120 */
121
mock_ppu_mod_init(fwk_id_t module_id,unsigned int pd_count,const void * unused)122 static int mock_ppu_mod_init(fwk_id_t module_id, unsigned int pd_count,
123 const void *unused)
124 {
125 mock_ppu_ctx.pd_ctx_table = fwk_mm_calloc(pd_count,
126 sizeof(struct mock_ppu_pd_ctx));
127 if (mock_ppu_ctx.pd_ctx_table == NULL)
128 return FWK_E_NOMEM;
129
130 return FWK_SUCCESS;
131 }
132
mock_ppu_pd_init(fwk_id_t pd_id,unsigned int unused,const void * data)133 static int mock_ppu_pd_init(fwk_id_t pd_id, unsigned int unused, const void *data)
134 {
135 const struct mod_mock_ppu_pd_config *config = data;
136 struct mock_ppu_pd_ctx *pd_ctx;
137
138 if (config->pd_type >= MOD_PD_TYPE_COUNT)
139 return FWK_E_DATA;
140
141 pd_ctx = mock_ppu_ctx.pd_ctx_table + fwk_id_get_element_idx(pd_id);
142 pd_ctx->config = config;
143 pd_ctx->ppu = (uint32_t *)(config->ppu.reg_base);
144 pd_ctx->bound_id = FWK_ID_NONE;
145
146 switch (config->pd_type) {
147 case MOD_PD_TYPE_DEVICE:
148 case MOD_PD_TYPE_DEVICE_DEBUG:
149 case MOD_PD_TYPE_SYSTEM:
150 if (config->default_power_on)
151 *pd_ctx->ppu = MOD_PD_STATE_ON;
152
153 return FWK_SUCCESS;
154
155 default:
156 return FWK_E_SUPPORT;
157 }
158 }
159
mock_ppu_bind(fwk_id_t id,unsigned int round)160 static int mock_ppu_bind(fwk_id_t id, unsigned int round)
161 {
162 struct mock_ppu_pd_ctx *pd_ctx;
163
164 /* Nothing to do during the first round of calls where the power module
165 will bind to the power domains of this module. */
166 if (round == 0)
167 return FWK_SUCCESS;
168
169 /* In the case of the module, nothing to do */
170 if (fwk_module_is_valid_module_id(id)) {
171 return FWK_SUCCESS;
172 }
173
174 pd_ctx = mock_ppu_ctx.pd_ctx_table + fwk_id_get_element_idx(id);
175
176 if (fwk_id_is_equal(pd_ctx->bound_id, FWK_ID_NONE))
177 return FWK_SUCCESS;
178
179 switch (fwk_id_get_module_idx(pd_ctx->bound_id)) {
180 #ifdef BUILD_HAS_MOD_POWER_DOMAIN
181 case FWK_MODULE_IDX_POWER_DOMAIN:
182 return fwk_module_bind(pd_ctx->bound_id,
183 mod_pd_api_id_driver_input,
184 &pd_ctx->pd_driver_input_api);
185 break;
186 #endif
187
188 #ifdef BUILD_HAS_MOD_SYSTEM_POWER
189 case FWK_MODULE_IDX_SYSTEM_POWER:
190 return fwk_module_bind(pd_ctx->bound_id,
191 mod_system_power_api_id_pd_driver_input,
192 &pd_ctx->pd_driver_input_api);
193 break;
194 #endif
195
196 default:
197 assert(false);
198 return FWK_E_SUPPORT;
199 }
200 }
201
mock_ppu_process_bind_request(fwk_id_t source_id,fwk_id_t target_id,fwk_id_t not_used,const void ** api)202 static int mock_ppu_process_bind_request(fwk_id_t source_id,
203 fwk_id_t target_id, fwk_id_t not_used,
204 const void **api)
205 {
206 struct mock_ppu_pd_ctx *pd_ctx;
207
208 pd_ctx = mock_ppu_ctx.pd_ctx_table + fwk_id_get_element_idx(target_id);
209
210 switch (pd_ctx->config->pd_type) {
211 case MOD_PD_TYPE_SYSTEM:
212 if (!fwk_id_is_equal(pd_ctx->bound_id, FWK_ID_NONE)) {
213 assert(false);
214 return FWK_E_ACCESS;
215 }
216 /* Fallthrough */
217
218 case MOD_PD_TYPE_DEVICE:
219 case MOD_PD_TYPE_DEVICE_DEBUG:
220 #ifdef BUILD_HAS_MOD_POWER_DOMAIN
221 if (fwk_id_get_module_idx(source_id) == FWK_MODULE_IDX_POWER_DOMAIN) {
222 pd_ctx->bound_id = source_id;
223 *api = &pd_driver;
224 break;
225 }
226 #endif
227 #ifdef BUILD_HAS_MOD_SYSTEM_POWER
228 if (fwk_id_get_module_idx(source_id) == FWK_MODULE_IDX_SYSTEM_POWER) {
229 pd_ctx->bound_id = source_id;
230 *api = &pd_driver;
231 break;
232 }
233 #endif
234 assert(false);
235 return FWK_E_ACCESS;
236
237 default:
238 (void)pd_driver;
239 return FWK_E_SUPPORT;
240 }
241
242 return FWK_SUCCESS;
243 }
244
245 const struct fwk_module module_mock_ppu = {
246 .type = FWK_MODULE_TYPE_DRIVER,
247 .api_count = 1,
248 .init = mock_ppu_mod_init,
249 .element_init = mock_ppu_pd_init,
250 .bind = mock_ppu_bind,
251 .process_bind_request = mock_ppu_process_bind_request,
252 };
253