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 
8 #include "config_power_domain.h"
9 #include "platform_core.h"
10 #include "scp_css_mmap.h"
11 
12 #include <mod_power_domain.h>
13 #include <mod_ppu_v1.h>
14 
15 #include <fwk_element.h>
16 #include <fwk_id.h>
17 #include <fwk_interrupt.h>
18 #include <fwk_macros.h>
19 #include <fwk_mm.h>
20 #include <fwk_module.h>
21 #include <fwk_module_idx.h>
22 
23 #include <stdio.h>
24 #include <string.h>
25 
26 /* Maximum PPU core name size including the null terminator */
27 #define PPU_CORE_NAME_SIZE 12
28 
29 /* Maximum PPU cluster name size including the null terminator */
30 #define PPU_CLUS_NAME_SIZE 6
31 
32 /* Module configuration data */
33 static struct mod_ppu_v1_config ppu_v1_config_data = {
34     .pd_notification_id = FWK_ID_NOTIFICATION_INIT(
35         FWK_MODULE_IDX_POWER_DOMAIN,
36         MOD_PD_NOTIFICATION_IDX_POWER_STATE_TRANSITION),
37 };
38 
39 static struct fwk_element ppu_v1_system_element_table[] = {
40     [0] = {
41         .name = "SYS0",
42         .data = &((struct mod_ppu_v1_pd_config) {
43             .pd_type = MOD_PD_TYPE_SYSTEM,
44             .ppu.reg_base = SCP_PPU_SYS0_BASE,
45             .observer_id = FWK_ID_NONE_INIT,
46         }),
47     },
48     [1] = {
49         .name = "SYS1",
50         .data = &((struct mod_ppu_v1_pd_config) {
51             .pd_type = MOD_PD_TYPE_SYSTEM,
52             .ppu.reg_base = SCP_PPU_SYS1_BASE,
53             .observer_id = FWK_ID_NONE_INIT,
54         }),
55     },
56 };
57 
ppu_v1_get_element_table(fwk_id_t module_id)58 static const struct fwk_element *ppu_v1_get_element_table(fwk_id_t module_id)
59 {
60     struct fwk_element *element_table, *element;
61     struct mod_ppu_v1_pd_config *pd_config_table, *pd_config;
62     unsigned int core_idx;
63     unsigned int cluster_idx;
64     unsigned int core_count;
65     unsigned int cluster_count;
66     unsigned int core_element_count = 0;
67 
68     core_count = platform_core_get_core_count();
69     cluster_count = platform_core_get_cluster_count();
70 
71     /*
72      * Allocate element descriptors based on:
73      *   Number of cores
74      *   + Number of cluster descriptors
75      *   + Number of system power domain descriptors
76      *   + 1 terminator descriptor
77      */
78     element_table = fwk_mm_calloc(
79         core_count + cluster_count +
80             FWK_ARRAY_SIZE(ppu_v1_system_element_table) + 1,
81         sizeof(struct fwk_element));
82     if (element_table == NULL)
83         return NULL;
84 
85     pd_config_table = fwk_mm_calloc(
86         core_count + cluster_count, sizeof(struct mod_ppu_v1_pd_config));
87     if (pd_config_table == NULL)
88         return NULL;
89 
90     for (cluster_idx = 0; cluster_idx < cluster_count; cluster_idx++) {
91         for (core_idx = 0;
92              core_idx < platform_core_get_core_per_cluster_count(cluster_idx);
93              core_idx++) {
94             element = &element_table[core_element_count];
95             pd_config = &pd_config_table[core_element_count];
96 
97             element->name = fwk_mm_alloc(PPU_CORE_NAME_SIZE, 1);
98             if (element->name == NULL)
99                 return NULL;
100 
101             snprintf(
102                 (char *)element->name,
103                 PPU_CORE_NAME_SIZE,
104                 "CLUS%uCORE%u",
105                 cluster_idx,
106                 core_idx);
107 
108             element->data = pd_config;
109 
110             pd_config->pd_type = MOD_PD_TYPE_CORE;
111             pd_config->ppu.reg_base = SCP_PPU_BASE(cluster_idx);
112             pd_config->ppu.irq = FWK_INTERRUPT_NONE;
113             pd_config->cluster_id = FWK_ID_ELEMENT(
114                 FWK_MODULE_IDX_PPU_V1, (core_count + cluster_idx));
115             pd_config->observer_id = FWK_ID_NONE;
116             core_element_count++;
117         }
118 
119         element = &element_table[core_count + cluster_idx];
120         pd_config = &pd_config_table[core_count + cluster_idx];
121 
122         element->name = fwk_mm_alloc(PPU_CLUS_NAME_SIZE, 1);
123         if (element->name == NULL)
124             return NULL;
125 
126         snprintf(
127             (char *)element->name, PPU_CLUS_NAME_SIZE, "CLUS%u", cluster_idx);
128 
129         element->data = pd_config;
130 
131         pd_config->pd_type = MOD_PD_TYPE_CLUSTER;
132         pd_config->ppu.reg_base = SCP_PPU_BASE(cluster_idx);
133         pd_config->ppu.irq = FWK_INTERRUPT_NONE;
134         pd_config->observer_id = FWK_ID_NONE;
135         pd_config->observer_api = FWK_ID_NONE;
136     }
137 
138     memcpy(
139         &element_table[core_count + cluster_count],
140         ppu_v1_system_element_table,
141         sizeof(ppu_v1_system_element_table));
142 
143     /*
144      * Configure pd_source_id with the SYSTOP identifier from the power domain
145      * module which is dynamically defined based on the number of cores.
146      */
147     ppu_v1_config_data.pd_source_id = fwk_id_build_element_id(
148         fwk_module_id_power_domain,
149         core_count + cluster_count + PD_STATIC_DEV_IDX_SYSTOP);
150 
151     return element_table;
152 }
153 
154 /*
155  * Power module configuration data
156  */
157 const struct fwk_module_config config_ppu_v1 = {
158     .data = &ppu_v1_config_data,
159     .elements = FWK_MODULE_DYNAMIC_ELEMENTS(ppu_v1_get_element_table),
160 };
161