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