1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2017-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 "config_ppu_v0.h"
10 #include "rdn1e1_core.h"
11 #include "rdn1e1_power_domain.h"
12 
13 #include <power_domain_utils.h>
14 
15 #include <mod_power_domain.h>
16 #include <mod_ppu_v1.h>
17 #include <mod_system_power.h>
18 
19 #include <fwk_element.h>
20 #include <fwk_id.h>
21 #include <fwk_macros.h>
22 #include <fwk_mm.h>
23 #include <fwk_module.h>
24 #include <fwk_module_idx.h>
25 
26 #include <stdint.h>
27 #include <stdio.h>
28 #include <string.h>
29 
30 /* Maximum power domain name size including the null terminator */
31 #define PD_NAME_SIZE 12
32 
33 /* Mask of the allowed states for the systop power domain */
34 static const uint32_t systop_allowed_state_mask_table[] = {
35     [0] = MOD_PD_STATE_OFF_MASK | MOD_PD_STATE_ON_MASK |
36           (1 << MOD_SYSTEM_POWER_POWER_STATE_SLEEP0) |
37           (1 << MOD_SYSTEM_POWER_POWER_STATE_SLEEP1)
38 };
39 
40 /*
41  * Mask of the allowed states for the top level power domains
42  * (but the cluster power domains) depending on the system states.
43  */
44 static const uint32_t toplevel_allowed_state_mask_table[] = {
45     [MOD_PD_STATE_OFF] = MOD_PD_STATE_OFF_MASK,
46     [MOD_PD_STATE_ON] = MOD_PD_STATE_OFF_MASK | MOD_PD_STATE_ON_MASK,
47     [MOD_SYSTEM_POWER_POWER_STATE_SLEEP0] = MOD_PD_STATE_OFF_MASK,
48     [MOD_SYSTEM_POWER_POWER_STATE_SLEEP1] = MOD_PD_STATE_OFF_MASK
49 };
50 
51 /*
52  * Mask of the allowed states for the cluster power domain depending on the
53  * system states.
54  *
55  * While the clusters may reach a SLEEP state, SLEEP does not appear in this
56  * table. This is because the PPU driver backing the clusters will not accept a
57  * manual SLEEP request, but will transition to it automatically when possible.
58  */
59 static const uint32_t cluster_pd_allowed_state_mask_table[] = {
60     [MOD_PD_STATE_OFF] = MOD_PD_STATE_OFF_MASK,
61     [MOD_PD_STATE_ON] =
62         RDN1E1_CLUSTER_VALID_STATE_MASK & (~MOD_PD_STATE_SLEEP_MASK),
63     [MOD_SYSTEM_POWER_POWER_STATE_SLEEP0] = MOD_PD_STATE_OFF_MASK,
64     [MOD_SYSTEM_POWER_POWER_STATE_SLEEP1] = MOD_PD_STATE_OFF_MASK
65 };
66 
67 /* Mask of the allowed states for a core depending on the cluster states. */
68 static const uint32_t core_pd_allowed_state_mask_table[] = {
69     [MOD_PD_STATE_OFF] = MOD_PD_STATE_OFF_MASK | MOD_PD_STATE_SLEEP_MASK,
70     [MOD_PD_STATE_ON] = RDN1E1_CORE_VALID_STATE_MASK,
71     [MOD_PD_STATE_SLEEP] = MOD_PD_STATE_OFF_MASK | MOD_PD_STATE_SLEEP_MASK,
72     [RDN1E1_POWER_DOMAIN_STATE_FUNC_RET] = RDN1E1_CORE_VALID_STATE_MASK,
73     [RDN1E1_POWER_DOMAIN_STATE_MEM_RET] = MOD_PD_STATE_OFF_MASK
74 };
75 
76 /* Power module specific configuration data (none) */
77 static const struct mod_power_domain_config
78     rdn1e1_power_domain_config = { 0 };
79 
80 static struct fwk_element rdn1e1_power_domain_static_element_table[] = {
81     [PD_STATIC_DEV_IDX_DBGTOP] = {
82         .name = "DBGTOP",
83         .data = &((struct mod_power_domain_element_config) {
84             .attributes.pd_type = MOD_PD_TYPE_DEVICE_DEBUG,
85             .driver_id = FWK_ID_ELEMENT_INIT(
86                 FWK_MODULE_IDX_PPU_V0, PPU_V0_ELEMENT_IDX_DBGTOP),
87             .api_id = FWK_ID_API_INIT(FWK_MODULE_IDX_PPU_V0, 0),
88             .allowed_state_mask_table = toplevel_allowed_state_mask_table,
89             .allowed_state_mask_table_size =
90                 FWK_ARRAY_SIZE(toplevel_allowed_state_mask_table)
91         }),
92     },
93     [PD_STATIC_DEV_IDX_SYSTOP] = {
94         .name = "SYSTOP",
95         .data = &((struct mod_power_domain_element_config) {
96             .attributes.pd_type = MOD_PD_TYPE_SYSTEM,
97             .parent_idx = PD_STATIC_DEV_IDX_NONE,
98             .driver_id = FWK_ID_MODULE_INIT(FWK_MODULE_IDX_SYSTEM_POWER),
99             .api_id = FWK_ID_API_INIT(
100                 FWK_MODULE_IDX_SYSTEM_POWER,
101                 MOD_SYSTEM_POWER_API_IDX_PD_DRIVER),
102             .allowed_state_mask_table = systop_allowed_state_mask_table,
103             .allowed_state_mask_table_size =
104                 FWK_ARRAY_SIZE(systop_allowed_state_mask_table)
105         }),
106     },
107 };
108 
109 /*
110  * Function definitions with internal linkage
111  */
rdn1e1_power_domain_get_element_table(fwk_id_t module_id)112 static const struct fwk_element *rdn1e1_power_domain_get_element_table
113     (fwk_id_t module_id)
114 {
115     return create_power_domain_element_table(
116         rdn1e1_core_get_core_count(),
117         rdn1e1_core_get_cluster_count(),
118         FWK_MODULE_IDX_PPU_V1,
119         MOD_PPU_V1_API_IDX_POWER_DOMAIN_DRIVER,
120         core_pd_allowed_state_mask_table,
121         FWK_ARRAY_SIZE(core_pd_allowed_state_mask_table),
122         cluster_pd_allowed_state_mask_table,
123         FWK_ARRAY_SIZE(cluster_pd_allowed_state_mask_table),
124         rdn1e1_power_domain_static_element_table,
125         FWK_ARRAY_SIZE(rdn1e1_power_domain_static_element_table));
126 }
127 
128 /*
129  * Power module configuration data
130  */
131 const struct fwk_module_config config_power_domain = {
132     .data = &rdn1e1_power_domain_config,
133     .elements =
134         FWK_MODULE_DYNAMIC_ELEMENTS(rdn1e1_power_domain_get_element_table),
135 };
136