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