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 "scp_mmap.h"
10 #include "tc1_core.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 /* Cluster ID for Theodul DSU */
33 #define CLUSTER_ID 0
34 
35 /* Module configuration data */
36 static struct mod_ppu_v1_config ppu_v1_config_data = {
37     .pd_notification_id = FWK_ID_NOTIFICATION_INIT(
38         FWK_MODULE_IDX_POWER_DOMAIN,
39         MOD_PD_NOTIFICATION_IDX_POWER_STATE_TRANSITION),
40 };
41 
42 static const struct fwk_element ppu_v1_system_element_table[1] = {
43     [0] =
44         {
45             .name = "SYS0",
46             .data = &((struct mod_ppu_v1_pd_config){
47                 .pd_type = MOD_PD_TYPE_SYSTEM,
48                 .ppu.reg_base = SCP_PPU_SYS0_BASE,
49                 .observer_id = FWK_ID_NONE_INIT,
50             }),
51         },
52 };
53 
ppu_v1_get_element_table(fwk_id_t module_id)54 static const struct fwk_element *ppu_v1_get_element_table(fwk_id_t module_id)
55 {
56     struct fwk_element *element_table, *element;
57     struct mod_ppu_v1_pd_config *pd_config_table, *pd_config;
58     unsigned int core_idx;
59     unsigned int core_count;
60     unsigned int cluster_count;
61     unsigned int core_element_count = 0;
62 
63     core_count = tc1_core_get_core_count();
64     cluster_count = tc1_core_get_cluster_count();
65 
66     /*
67      * Allocate element descriptors based on:
68      *   Number of cores
69      *   + Number of cluster descriptors
70      *   + Number of system power domain descriptors
71      *   + 1 terminator descriptor
72      */
73     element_table = fwk_mm_calloc(
74         core_count + cluster_count +
75             FWK_ARRAY_SIZE(ppu_v1_system_element_table) + 1,
76         sizeof(struct fwk_element));
77     if (element_table == NULL) {
78         return NULL;
79     }
80 
81     pd_config_table = fwk_mm_calloc(
82         core_count + cluster_count, sizeof(struct mod_ppu_v1_pd_config));
83     if (pd_config_table == NULL) {
84         return NULL;
85     }
86 
87     for (core_idx = 0;
88          core_idx < tc1_core_get_core_per_cluster_count(CLUSTER_ID);
89          core_idx++) {
90         element = &element_table[core_element_count];
91         pd_config = &pd_config_table[core_element_count];
92 
93         element->name = fwk_mm_alloc(PPU_CORE_NAME_SIZE, 1);
94         if (element->name == NULL) {
95             return NULL;
96         }
97 
98         (void)snprintf(
99             (char *)element->name, PPU_CORE_NAME_SIZE, "CORE%u", core_idx);
100 
101         element->data = pd_config;
102 
103         pd_config->pd_type = MOD_PD_TYPE_CORE;
104         pd_config->ppu.reg_base = SCP_PPU_CORE_BASE(core_idx);
105         pd_config->ppu.irq = FWK_INTERRUPT_NONE;
106         pd_config->cluster_id =
107             FWK_ID_ELEMENT(FWK_MODULE_IDX_PPU_V1, core_count);
108         pd_config->observer_id = FWK_ID_NONE;
109         core_element_count++;
110     }
111 
112     element = &element_table[core_count];
113     pd_config = &pd_config_table[core_count];
114 
115     element->name = fwk_mm_alloc(PPU_CLUS_NAME_SIZE, 1);
116     if (element->name == NULL) {
117         return NULL;
118     }
119 
120     element->data = pd_config;
121 
122     pd_config->pd_type = MOD_PD_TYPE_CLUSTER;
123     pd_config->ppu.reg_base = SCP_PPU_CLUSTER_BASE;
124     pd_config->ppu.irq = FWK_INTERRUPT_NONE;
125     pd_config->observer_id = FWK_ID_NONE;
126 
127     (void)memcpy(
128         &element_table[core_count + cluster_count],
129         ppu_v1_system_element_table,
130         sizeof(ppu_v1_system_element_table));
131 
132     /*
133      * Configure pd_source_id with the SYSTOP identifier from the power domain
134      * module which is dynamically defined based on the number of cores.
135      */
136     ppu_v1_config_data.pd_source_id = fwk_id_build_element_id(
137         fwk_module_id_power_domain,
138         core_count + cluster_count + PD_STATIC_DEV_IDX_SYSTOP);
139 
140     return element_table;
141 }
142 
143 /*
144  * Power module configuration data
145  */
146 const struct fwk_module_config config_ppu_v1 = {
147     .elements = FWK_MODULE_DYNAMIC_ELEMENTS(ppu_v1_get_element_table),
148     .data = &ppu_v1_config_data,
149 };
150