1 /*
2 * Arm SCP/MCP Software
3 * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 *
7 * Description:
8 * Power domain utilities.
9 */
10
11 #include <mod_power_domain.h>
12 #include <power_domain_utils.h>
13
14 #include <fwk_element.h>
15 #include <fwk_id.h>
16 #include <fwk_mm.h>
17 #include <fwk_status.h>
18 #include <fwk_string.h>
19
20 #include <stdio.h>
21
22 /* Maximum power domain name size including the null terminator */
23 #define PD_NAME_SIZE 25
24 /* Maximum number of cores */
25 #define MAX_CORES_COUNT 64
26 /* Maximum number of static table elements */
27 #define MAX_STATIC_ELEMENTS_COUNT 32
28
create_core_cluster_pd_element_table(struct fwk_element * element_table,unsigned int core_count,unsigned int cluster_count,unsigned int driver_idx,unsigned int api_idx,const uint32_t * core_state_table,size_t core_state_table_size,const uint32_t * cluster_state_table,size_t cluster_state_table_size)29 static int create_core_cluster_pd_element_table(
30 struct fwk_element *element_table,
31 unsigned int core_count,
32 unsigned int cluster_count,
33 unsigned int driver_idx,
34 unsigned int api_idx,
35 const uint32_t *core_state_table,
36 size_t core_state_table_size,
37 const uint32_t *cluster_state_table,
38 size_t cluster_state_table_size)
39 {
40 struct fwk_element *element;
41 struct mod_power_domain_element_config *pd_config, *pd_config_table = NULL;
42 unsigned int core_element_counter = 0;
43 unsigned int core_idx;
44 unsigned int cluster_idx;
45 unsigned int cores_per_clusters = core_count / cluster_count;
46 int status;
47
48 pd_config_table = fwk_mm_calloc(
49 core_count + cluster_count,
50 sizeof(struct mod_power_domain_element_config));
51 if (pd_config_table == NULL) {
52 return FWK_E_NOMEM;
53 }
54
55 for (cluster_idx = 0; cluster_idx < cluster_count; cluster_idx++) {
56 for (core_idx = 0; core_idx < cores_per_clusters; core_idx++) {
57 element = &element_table[core_element_counter];
58 pd_config = &pd_config_table[core_element_counter];
59 element->name = fwk_mm_alloc(PD_NAME_SIZE, 1);
60 status = snprintf(
61 (char *)element->name,
62 PD_NAME_SIZE,
63 "CLUS%uCORE%u",
64 cluster_idx,
65 core_idx);
66 if (status < 0) {
67 return FWK_E_PANIC;
68 }
69 element->data = pd_config;
70 pd_config->attributes.pd_type = MOD_PD_TYPE_CORE;
71 pd_config->parent_idx = cluster_idx + core_count;
72 pd_config->driver_id =
73 FWK_ID_ELEMENT(driver_idx, core_element_counter);
74 pd_config->api_id = FWK_ID_API(driver_idx, api_idx);
75 pd_config->allowed_state_mask_table = core_state_table;
76 pd_config->allowed_state_mask_table_size = core_state_table_size;
77 core_element_counter++;
78 }
79 /* Define the cluster configuration */
80 element = &element_table[cluster_idx + core_count];
81 pd_config = &pd_config_table[cluster_idx + core_count];
82 element->name = fwk_mm_alloc(PD_NAME_SIZE, 1);
83 status = snprintf(
84 (char *)element->name, PD_NAME_SIZE, "CLUS%u", cluster_idx);
85 if (status < 0) {
86 return FWK_E_PANIC;
87 }
88 element->data = pd_config;
89 pd_config->attributes.pd_type = MOD_PD_TYPE_CLUSTER;
90 pd_config->driver_id =
91 FWK_ID_ELEMENT(driver_idx, cluster_idx + core_count);
92 pd_config->api_id = FWK_ID_API(driver_idx, api_idx);
93 pd_config->allowed_state_mask_table = cluster_state_table;
94 pd_config->allowed_state_mask_table_size = cluster_state_table_size;
95 }
96
97 return FWK_SUCCESS;
98 }
99
create_power_domain_element_table(unsigned int core_count,unsigned int cluster_count,unsigned int driver_idx,unsigned int api_idx,const uint32_t * core_state_table,size_t core_state_table_size,const uint32_t * cluster_state_table,size_t cluster_state_table_size,struct fwk_element * static_table,size_t static_table_size)100 const struct fwk_element *create_power_domain_element_table(
101 unsigned int core_count,
102 unsigned int cluster_count,
103 unsigned int driver_idx,
104 unsigned int api_idx,
105 const uint32_t *core_state_table,
106 size_t core_state_table_size,
107 const uint32_t *cluster_state_table,
108 size_t cluster_state_table_size,
109 struct fwk_element *static_table,
110 size_t static_table_size)
111 {
112 struct fwk_element *element_table = NULL;
113 struct mod_power_domain_element_config *pd_config;
114 unsigned int systop_idx, element_idx;
115 int status;
116
117 if ((core_count % cluster_count != 0) || (core_count > MAX_CORES_COUNT) ||
118 (static_table_size > MAX_STATIC_ELEMENTS_COUNT)) {
119 return NULL;
120 }
121
122 element_table = fwk_mm_calloc(
123 core_count + cluster_count + static_table_size + 1, /* Terminator */
124 sizeof(struct fwk_element));
125
126 if (element_table == NULL) {
127 return element_table;
128 }
129
130 status = create_core_cluster_pd_element_table(
131 element_table,
132 core_count,
133 cluster_count,
134 driver_idx,
135 api_idx,
136 core_state_table,
137 core_state_table_size,
138 cluster_state_table,
139 cluster_state_table_size);
140
141 if (status != FWK_SUCCESS) {
142 return NULL;
143 }
144
145 fwk_str_memcpy(
146 element_table + (core_count + cluster_count),
147 static_table,
148 static_table_size * sizeof(struct fwk_element));
149
150 /* Calculate SYSTOP index */
151 systop_idx =
152 (unsigned int)(core_count + cluster_count + static_table_size - 1);
153
154 /* Set Power Domain Parent for all SYSTOP children */
155 for (element_idx = core_count; element_idx < systop_idx; element_idx++) {
156 pd_config =
157 (struct mod_power_domain_element_config *)element_table[element_idx]
158 .data;
159 pd_config->parent_idx = systop_idx;
160 }
161
162 return element_table;
163 }
164