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