1 /*
2 * Arm SCP/MCP Software
3 * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #include <config_power_domain.h>
9 #include <config_ppu_v0.h>
10 #include <morello_core.h>
11 #include <morello_power_domain.h>
12
13 #include <mod_power_domain.h>
14 #include <mod_ppu_v1.h>
15 #include <mod_system_power.h>
16
17 #include <fwk_element.h>
18 #include <fwk_macros.h>
19 #include <fwk_mm.h>
20 #include <fwk_module.h>
21 #include <fwk_module_idx.h>
22
23 #include <stdint.h>
24 #include <stdio.h>
25 #include <string.h>
26
27 /* Maximum power domain name size including the null terminator */
28 #define PD_NAME_SIZE 16
29
30 /* Mask of the allowed states for the systop power domain */
31 static const uint32_t systop_allowed_state_mask_table[2] = {
32 [MOD_PD_STATE_OFF] = MOD_PD_STATE_OFF_MASK,
33 [MOD_PD_STATE_ON] = MOD_PD_STATE_OFF_MASK | MOD_PD_STATE_ON_MASK |
34 (1 << MOD_SYSTEM_POWER_POWER_STATE_SLEEP0) |
35 (1 << MOD_SYSTEM_POWER_POWER_STATE_SLEEP1)
36 };
37
38 /*
39 * Mask of the allowed states for the top level power domains
40 * (but the cluster power domains) depending on the system states.
41 */
42 static const uint32_t toplevel_allowed_state_mask_table[5] = {
43 [MOD_PD_STATE_OFF] = MOD_PD_STATE_OFF_MASK,
44 [MOD_PD_STATE_ON] = MOD_PD_STATE_OFF_MASK | MOD_PD_STATE_ON_MASK,
45 [MOD_SYSTEM_POWER_POWER_STATE_SLEEP0] = MOD_PD_STATE_OFF_MASK,
46 [MOD_SYSTEM_POWER_POWER_STATE_SLEEP1] = MOD_PD_STATE_OFF_MASK
47 };
48
49 /*
50 * Mask of the allowed states for the cluster power domain depending on the
51 * system states.
52 */
53 static const uint32_t cluster_pd_allowed_state_mask_table[5] = {
54 [MOD_PD_STATE_OFF] = MOD_PD_STATE_OFF_MASK | MOD_PD_STATE_SLEEP_MASK,
55 [MOD_PD_STATE_ON] = MORELLO_CLUSTER_VALID_STATE_MASK,
56 [MOD_SYSTEM_POWER_POWER_STATE_SLEEP0] = MOD_PD_STATE_OFF_MASK,
57 [MOD_SYSTEM_POWER_POWER_STATE_SLEEP1] = MOD_PD_STATE_OFF_MASK
58 };
59
60 /* Mask of the allowed states for a core depending on the cluster states. */
61 static const uint32_t core_pd_allowed_state_mask_table[6] = {
62 [MOD_PD_STATE_OFF] = MOD_PD_STATE_OFF_MASK | MOD_PD_STATE_SLEEP_MASK,
63 [MOD_PD_STATE_ON] = MORELLO_CORE_VALID_STATE_MASK,
64 [MOD_PD_STATE_SLEEP] = MOD_PD_STATE_OFF_MASK | MOD_PD_STATE_SLEEP_MASK,
65 [MORELLO_POWER_DOMAIN_STATE_FUNC_RET] = MORELLO_CORE_VALID_STATE_MASK,
66 [MORELLO_POWER_DOMAIN_STATE_MEM_RET] = MOD_PD_STATE_OFF_MASK
67 };
68
69 /* Power module specific configuration data (none) */
70 static const struct mod_power_domain_config morello_power_domain_config = { 0 };
71
72 /* Power domain element table pointer */
73 struct fwk_element *element_table = NULL;
74
75 /* Power domain element configuration table pointer */
76 struct mod_power_domain_element_config *pd_config_table = NULL;
77
78 /*
79 * The SCP's view of PD tree in a single chip mode looks like below:
80 *
81 * -------------SYSTOP0----------------
82 * / / | \ \
83 * / / | \ \
84 * / / | \ \
85 * CLUS0 CLUS1 DBGTOP0 GPUTOP0 DPUTOP0
86 * / \ / \
87 * CPU0--CPU1--CPU2--CPU3
88 *
89 */
90
91 static struct fwk_element
92 morello_pd_single_chip_element_table[PD_SINGLE_CHIP_IDX_COUNT + 1] = {
93 [PD_SINGLE_CHIP_IDX_CLUS0CORE0] = {
94 .name = "CLUS0CORE0",
95 .data = &((struct mod_power_domain_element_config) {
96 .attributes.pd_type = MOD_PD_TYPE_CORE,
97 .parent_idx = PD_SINGLE_CHIP_IDX_CLUSTER0,
98 .driver_id = FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_PPU_V1, 0),
99 .api_id = FWK_ID_API_INIT(
100 FWK_MODULE_IDX_PPU_V1,
101 MOD_PPU_V1_API_IDX_POWER_DOMAIN_DRIVER),
102 .allowed_state_mask_table = core_pd_allowed_state_mask_table,
103 .allowed_state_mask_table_size =
104 FWK_ARRAY_SIZE(core_pd_allowed_state_mask_table)
105 }),
106 },
107 [PD_SINGLE_CHIP_IDX_CLUS0CORE1] = {
108 .name = "CLUS0CORE1",
109 .data = &((struct mod_power_domain_element_config) {
110 .attributes.pd_type = MOD_PD_TYPE_CORE,
111 .parent_idx = PD_SINGLE_CHIP_IDX_CLUSTER0,
112 .driver_id = FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_PPU_V1, 1),
113 .api_id = FWK_ID_API_INIT(
114 FWK_MODULE_IDX_PPU_V1,
115 MOD_PPU_V1_API_IDX_POWER_DOMAIN_DRIVER),
116 .allowed_state_mask_table = core_pd_allowed_state_mask_table,
117 .allowed_state_mask_table_size =
118 FWK_ARRAY_SIZE(core_pd_allowed_state_mask_table)
119 }),
120 },
121 [PD_SINGLE_CHIP_IDX_CLUS1CORE0] = {
122 .name = "CLUS1CORE0",
123 .data = &((struct mod_power_domain_element_config) {
124 .attributes.pd_type = MOD_PD_TYPE_CORE,
125 .parent_idx = PD_SINGLE_CHIP_IDX_CLUSTER1,
126 .driver_id = FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_PPU_V1, 2),
127 .api_id = FWK_ID_API_INIT(
128 FWK_MODULE_IDX_PPU_V1,
129 MOD_PPU_V1_API_IDX_POWER_DOMAIN_DRIVER),
130 .allowed_state_mask_table = core_pd_allowed_state_mask_table,
131 .allowed_state_mask_table_size =
132 FWK_ARRAY_SIZE(core_pd_allowed_state_mask_table)
133 }),
134 },
135 [PD_SINGLE_CHIP_IDX_CLUS1CORE1] = {
136 .name = "CLUS1CORE1",
137 .data = &((struct mod_power_domain_element_config) {
138 .attributes.pd_type = MOD_PD_TYPE_CORE,
139 .parent_idx = PD_SINGLE_CHIP_IDX_CLUSTER1,
140 .driver_id = FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_PPU_V1, 3),
141 .api_id = FWK_ID_API_INIT(
142 FWK_MODULE_IDX_PPU_V1,
143 MOD_PPU_V1_API_IDX_POWER_DOMAIN_DRIVER),
144 .allowed_state_mask_table = core_pd_allowed_state_mask_table,
145 .allowed_state_mask_table_size =
146 FWK_ARRAY_SIZE(core_pd_allowed_state_mask_table)
147 }),
148 },
149 [PD_SINGLE_CHIP_IDX_CLUSTER0] = {
150 .name = "CLUS0",
151 .data = &((struct mod_power_domain_element_config) {
152 .attributes.pd_type = MOD_PD_TYPE_CLUSTER,
153 .parent_idx = PD_SINGLE_CHIP_IDX_SYSTOP0,
154 .driver_id = FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_PPU_V1, 4),
155 .api_id = FWK_ID_API_INIT(
156 FWK_MODULE_IDX_PPU_V1,
157 MOD_PPU_V1_API_IDX_POWER_DOMAIN_DRIVER),
158 .allowed_state_mask_table = cluster_pd_allowed_state_mask_table,
159 .allowed_state_mask_table_size =
160 FWK_ARRAY_SIZE(cluster_pd_allowed_state_mask_table)
161 }),
162 },
163 [PD_SINGLE_CHIP_IDX_CLUSTER1] = {
164 .name = "CLUS1",
165 .data = &((struct mod_power_domain_element_config) {
166 .attributes.pd_type = MOD_PD_TYPE_CLUSTER,
167 .parent_idx = PD_SINGLE_CHIP_IDX_SYSTOP0,
168 .driver_id = FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_PPU_V1, 5),
169 .api_id = FWK_ID_API_INIT(
170 FWK_MODULE_IDX_PPU_V1,
171 MOD_PPU_V1_API_IDX_POWER_DOMAIN_DRIVER),
172 .allowed_state_mask_table = cluster_pd_allowed_state_mask_table,
173 .allowed_state_mask_table_size =
174 FWK_ARRAY_SIZE(cluster_pd_allowed_state_mask_table)
175 }),
176 },
177 [PD_SINGLE_CHIP_IDX_DBGTOP0] = {
178 .name = "DBGTOP0",
179 .data = &((struct mod_power_domain_element_config) {
180 .attributes.pd_type = MOD_PD_TYPE_DEVICE_DEBUG,
181 .parent_idx = PD_SINGLE_CHIP_IDX_SYSTOP0,
182 .driver_id = FWK_ID_ELEMENT_INIT(
183 FWK_MODULE_IDX_PPU_V0, PPU_V0_ELEMENT_IDX_DBGTOP),
184 .api_id = FWK_ID_API_INIT(FWK_MODULE_IDX_PPU_V0, 0),
185 .allowed_state_mask_table = toplevel_allowed_state_mask_table,
186 .allowed_state_mask_table_size =
187 FWK_ARRAY_SIZE(toplevel_allowed_state_mask_table)
188 }),
189 },
190 [PD_SINGLE_CHIP_IDX_GPUTOP0] = {
191 .name = "GPUTOP0",
192 .data = &((struct mod_power_domain_element_config) {
193 .attributes.pd_type = MOD_PD_TYPE_DEVICE,
194 .parent_idx = PD_SINGLE_CHIP_IDX_SYSTOP0,
195 .driver_id = FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_PPU_V1, 8),
196 .api_id = FWK_ID_API_INIT(
197 FWK_MODULE_IDX_PPU_V1,
198 MOD_PPU_V1_API_IDX_POWER_DOMAIN_DRIVER),
199 .allowed_state_mask_table = toplevel_allowed_state_mask_table,
200 .allowed_state_mask_table_size =
201 FWK_ARRAY_SIZE(toplevel_allowed_state_mask_table)
202 }),
203 },
204 [PD_SINGLE_CHIP_IDX_DPUTOP0] = {
205 .name = "DPUTOP0",
206 .data = &((struct mod_power_domain_element_config) {
207 .attributes.pd_type = MOD_PD_TYPE_DEVICE,
208 .parent_idx = PD_SINGLE_CHIP_IDX_SYSTOP0,
209 .driver_id = FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_PPU_V1, 9),
210 .api_id = FWK_ID_API_INIT(
211 FWK_MODULE_IDX_PPU_V1,
212 MOD_PPU_V1_API_IDX_POWER_DOMAIN_DRIVER),
213 .allowed_state_mask_table = toplevel_allowed_state_mask_table,
214 .allowed_state_mask_table_size =
215 FWK_ARRAY_SIZE(toplevel_allowed_state_mask_table)
216 }),
217 },
218 [PD_SINGLE_CHIP_IDX_SYSTOP0] = {
219 .name = "SYSTOP0",
220 .data = &((struct mod_power_domain_element_config) {
221 .attributes.pd_type = MOD_PD_TYPE_SYSTEM,
222 .parent_idx = PD_SINGLE_CHIP_IDX_NONE,
223 .driver_id = FWK_ID_MODULE_INIT(FWK_MODULE_IDX_SYSTEM_POWER),
224 .api_id = FWK_ID_API_INIT(
225 FWK_MODULE_IDX_SYSTEM_POWER,
226 MOD_SYSTEM_POWER_API_IDX_PD_DRIVER),
227 .allowed_state_mask_table = systop_allowed_state_mask_table,
228 .allowed_state_mask_table_size =
229 FWK_ARRAY_SIZE(systop_allowed_state_mask_table)
230 }),
231 },
232 [PD_SINGLE_CHIP_IDX_COUNT] = { 0 },
233 };
234
235 /*
236 * Function definitions with internal linkage
237 */
morello_power_domain_get_element_table(fwk_id_t module_id)238 static const struct fwk_element *morello_power_domain_get_element_table(
239 fwk_id_t module_id)
240 {
241 return morello_pd_single_chip_element_table;
242 }
243
244 /*
245 * Power module configuration data
246 */
247 const struct fwk_module_config config_power_domain = {
248 .elements =
249 FWK_MODULE_DYNAMIC_ELEMENTS(morello_power_domain_get_element_table),
250 .data = &morello_power_domain_config,
251 };
252