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 7
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
83 pd_config_table = fwk_mm_calloc(
84 core_count + cluster_count, sizeof(struct mod_ppu_v1_pd_config));
85
86 for (cluster_idx = 0; cluster_idx < cluster_count; cluster_idx++) {
87 for (core_idx = 0;
88 core_idx < platform_core_get_core_per_cluster_count(cluster_idx);
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
95 snprintf(
96 (char *)element->name,
97 PPU_CORE_NAME_SIZE,
98 "CLUS%uCORE%u",
99 cluster_idx,
100 core_idx);
101
102 element->data = pd_config;
103
104 pd_config->pd_type = MOD_PD_TYPE_CORE;
105 pd_config->ppu.reg_base = SCP_PPU_BASE(cluster_idx);
106 pd_config->ppu.irq = FWK_INTERRUPT_NONE;
107 pd_config->cluster_id = FWK_ID_ELEMENT(
108 FWK_MODULE_IDX_PPU_V1, (core_count + cluster_idx));
109 pd_config->observer_id = FWK_ID_NONE;
110 core_element_count++;
111 }
112
113 element = &element_table[core_count + cluster_idx];
114 pd_config = &pd_config_table[core_count + cluster_idx];
115
116 element->name = fwk_mm_alloc(PPU_CLUS_NAME_SIZE, 1);
117
118 snprintf(
119 (char *)element->name, PPU_CLUS_NAME_SIZE, "CLUS%u", cluster_idx);
120
121 element->data = pd_config;
122
123 pd_config->pd_type = MOD_PD_TYPE_CLUSTER;
124 pd_config->ppu.reg_base = SCP_PPU_BASE(cluster_idx);
125 pd_config->ppu.irq = FWK_INTERRUPT_NONE;
126 pd_config->observer_id = FWK_ID_NONE;
127 pd_config->observer_api = FWK_ID_NONE;
128 }
129
130 memcpy(
131 &element_table[core_count + cluster_count],
132 ppu_v1_system_element_table,
133 sizeof(ppu_v1_system_element_table));
134
135 /*
136 * Configure pd_source_id with the SYSTOP identifier from the power domain
137 * module which is dynamically defined based on the number of cores.
138 */
139 ppu_v1_config_data.pd_source_id = fwk_id_build_element_id(
140 fwk_module_id_power_domain,
141 core_count + cluster_count + PD_STATIC_DEV_IDX_SYSTOP);
142
143 return element_table;
144 }
145
146 /*
147 * Power module configuration data
148 */
149 const struct fwk_module_config config_ppu_v1 = {
150 .data = &ppu_v1_config_data,
151 .elements = FWK_MODULE_DYNAMIC_ELEMENTS(ppu_v1_get_element_table),
152 };
153