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 "morello_core.h"
10 #include "morello_scc_reg.h"
11 #include "morello_scp_mmap.h"
12 #include "morello_scp_pik.h"
13
14 #include <mod_cmn_skeena.h>
15 #include <mod_power_domain.h>
16 #include <mod_ppu_v1.h>
17
18 #include <fwk_assert.h>
19 #include <fwk_element.h>
20 #include <fwk_id.h>
21 #include <fwk_interrupt.h>
22 #include <fwk_macros.h>
23 #include <fwk_mm.h>
24 #include <fwk_module.h>
25 #include <fwk_module_idx.h>
26
27 #include <stdbool.h>
28 #include <stdint.h>
29 #include <stdio.h>
30 #include <string.h>
31
32 /* Maximum PPU core name size including the null terminator */
33 #define PPU_CORE_NAME_SIZE 16
34
35 /* Maximum PPU cluster name size including the null terminator */
36 #define PPU_CLUS_NAME_SIZE 8
37
38 /* Identifiers for the static table */
39 enum ppu_v1_static_element_idx {
40 PPU_V1_ELEMENT_IDX_SYS0,
41 PPU_V1_ELEMENT_IDX_SYS1,
42 PPU_V1_ELEMENT_IDX_GPUTOP0,
43 PPU_V1_ELEMENT_IDX_DPUTOP0,
44 PPU_V1_ELEMENT_IDX_COUNT
45 };
46
47 /* Lookup table for translating cluster indicies into CMN600 node IDs */
48 static const unsigned int cluster_idx_to_node_id[2] = { 192, 140 };
49
50 /* Module configuration data */
51 static struct mod_ppu_v1_config ppu_v1_config_data = {
52 .pd_notification_id = FWK_ID_NOTIFICATION_INIT(
53 FWK_MODULE_IDX_POWER_DOMAIN,
54 MOD_PD_NOTIFICATION_IDX_POWER_STATE_TRANSITION),
55 };
56
57 static struct fwk_element
58 ppu_v1_static_element_table[PPU_V1_ELEMENT_IDX_COUNT] = {
59 [PPU_V1_ELEMENT_IDX_SYS0] = {
60 .name = "SYS0",
61 .data = &((struct mod_ppu_v1_pd_config) {
62 .pd_type = MOD_PD_TYPE_SYSTEM,
63 .ppu.reg_base = SCP_PPU_SYS0_BASE,
64 .observer_id = FWK_ID_NONE_INIT,
65 .default_power_on = true,
66 }),
67 },
68 [PPU_V1_ELEMENT_IDX_SYS1] = {
69 .name = "SYS1",
70 .data = &((struct mod_ppu_v1_pd_config) {
71 .pd_type = MOD_PD_TYPE_SYSTEM,
72 .ppu.reg_base = SCP_PPU_SYS1_BASE,
73 .observer_id = FWK_ID_NONE_INIT,
74 .default_power_on = true,
75 }),
76 },
77 [PPU_V1_ELEMENT_IDX_GPUTOP0] = {
78 .name = "GPUTOP0",
79 .data = &((struct mod_ppu_v1_pd_config) {
80 .pd_type = MOD_PD_TYPE_DEVICE,
81 .ppu.reg_base = SCP_PPU_GPU_BASE,
82 .observer_id = FWK_ID_NONE_INIT,
83 .default_power_on = true,
84 }),
85 },
86 [PPU_V1_ELEMENT_IDX_DPUTOP0] = {
87 .name = "DPUTOP0",
88 .data = &((struct mod_ppu_v1_pd_config) {
89 .pd_type = MOD_PD_TYPE_DEVICE,
90 .ppu.reg_base = SCP_PPU_DPU_BASE,
91 .observer_id = FWK_ID_NONE_INIT,
92 .default_power_on = true,
93 }),
94 },
95 };
96
ppu_v1_get_element_table(fwk_id_t module_id)97 static const struct fwk_element *ppu_v1_get_element_table(fwk_id_t module_id)
98 {
99 struct fwk_element *element_table, *element;
100 struct mod_ppu_v1_pd_config *pd_config_table, *pd_config;
101 unsigned int core_idx;
102 unsigned int cluster_idx;
103 unsigned int core_count;
104 unsigned int cluster_count;
105 unsigned int core_element_count = 0;
106
107 core_count = morello_core_get_core_count();
108 cluster_count = morello_core_get_cluster_count();
109
110 fwk_assert(cluster_count == FWK_ARRAY_SIZE(cluster_idx_to_node_id));
111
112 /*
113 * Allocate element descriptors based on:
114 * Number of cores
115 * + Number of cluster descriptors
116 * + Number of system power domain descriptors
117 * + 1 terminator descriptor
118 */
119 element_table = fwk_mm_calloc(
120 core_count + cluster_count +
121 FWK_ARRAY_SIZE(ppu_v1_static_element_table) + 1,
122 sizeof(struct fwk_element));
123 if (element_table == NULL) {
124 return NULL;
125 }
126
127 pd_config_table = fwk_mm_calloc(
128 core_count + cluster_count, sizeof(struct mod_ppu_v1_pd_config));
129 if (pd_config_table == NULL) {
130 return NULL;
131 }
132
133 for (cluster_idx = 0; cluster_idx < cluster_count; cluster_idx++) {
134 for (core_idx = 0;
135 core_idx < morello_core_get_core_per_cluster_count(cluster_idx);
136 core_idx++) {
137 element = &element_table[core_element_count];
138 pd_config = &pd_config_table[core_element_count];
139
140 element->name = fwk_mm_alloc(PPU_CORE_NAME_SIZE, 1);
141 if (element->name == NULL) {
142 return NULL;
143 }
144
145 (void)snprintf(
146 (char *)element->name,
147 PPU_CORE_NAME_SIZE,
148 "CLUS%uCORE%u",
149 (uint8_t)cluster_idx,
150 (uint8_t)core_idx);
151
152 element->data = pd_config;
153
154 pd_config->pd_type = MOD_PD_TYPE_CORE;
155 pd_config->ppu.reg_base = SCP_PPU_CORE_BASE(cluster_idx, core_idx);
156 pd_config->ppu.irq = FWK_INTERRUPT_NONE;
157 pd_config->cluster_id = FWK_ID_ELEMENT(
158 FWK_MODULE_IDX_PPU_V1, (core_count + cluster_idx));
159 pd_config->observer_id = FWK_ID_NONE;
160 core_element_count++;
161 }
162
163 element = &element_table[core_count + cluster_idx];
164 pd_config = &pd_config_table[core_count + cluster_idx];
165
166 element->name = fwk_mm_alloc(PPU_CLUS_NAME_SIZE, 1);
167 if (element->name == NULL) {
168 return NULL;
169 }
170
171 (void)snprintf(
172 (char *)element->name,
173 PPU_CLUS_NAME_SIZE,
174 "CLUS%u",
175 (uint8_t)cluster_idx);
176
177 element->data = pd_config;
178
179 pd_config->pd_type = MOD_PD_TYPE_CLUSTER;
180 pd_config->ppu.reg_base = SCP_PPU_CLUSTER_BASE(cluster_idx);
181 pd_config->ppu.irq = FWK_INTERRUPT_NONE;
182 pd_config->observer_id = fwk_module_id_cmn_skeena;
183 pd_config->observer_api = FWK_ID_API(
184 FWK_MODULE_IDX_CMN_SKEENA, MOD_CMN_SKEENA_API_IDX_PPU_OBSERVER);
185 pd_config->post_ppu_on_param =
186 (void *)&cluster_idx_to_node_id[cluster_idx];
187 pd_config->opmode = (SCC->BOOT_GPR1 & SCC_BOOTGPR1_L3_CACHE_EN_MASK) ?
188 PPU_V1_OPMODE_04 :
189 PPU_V1_OPMODE_00;
190 }
191
192 (void)memcpy(
193 &element_table[core_count + cluster_count],
194 ppu_v1_static_element_table,
195 sizeof(ppu_v1_static_element_table));
196
197 /*
198 * Configure pd_source_id with the SYSTOP identifier from the power domain
199 * module which is dynamically defined based on the number of cores.
200 */
201 ppu_v1_config_data.pd_source_id = fwk_id_build_element_id(
202 fwk_module_id_power_domain, PD_SINGLE_CHIP_IDX_SYSTOP0);
203
204 return element_table;
205 }
206
207 /*
208 * Power module configuration data
209 */
210 const struct fwk_module_config config_ppu_v1 = {
211 .elements = FWK_MODULE_DYNAMIC_ELEMENTS(ppu_v1_get_element_table),
212 .data = &ppu_v1_config_data,
213 };
214