1 /*
2 * Copyright (C) 2013-2014, 2016-2017 ARM Limited. All rights reserved.
3 *
4 * This program is free software and is provided to you under the terms of the GNU General Public License version 2
5 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
6 *
7 * A copy of the licence is included with the program, and can also be obtained from Free Software
8 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
9 */
10
11 #include "mali_kernel_common.h"
12 #include "mali_osk.h"
13 #include "mali_pm_domain.h"
14 #include "mali_pmu.h"
15 #include "mali_group.h"
16 #include "mali_pm.h"
17
18 static struct mali_pm_domain *mali_pm_domains[MALI_MAX_NUMBER_OF_DOMAINS] =
19 { NULL, };
20
mali_pm_domain_initialize(void)21 void mali_pm_domain_initialize(void)
22 {
23 /* Domains will be initialized/created on demand */
24 }
25
mali_pm_domain_terminate(void)26 void mali_pm_domain_terminate(void)
27 {
28 int i;
29
30 /* Delete all domains that has been created */
31 for (i = 0; i < MALI_MAX_NUMBER_OF_DOMAINS; i++) {
32 mali_pm_domain_delete(mali_pm_domains[i]);
33 mali_pm_domains[i] = NULL;
34 }
35 }
36
mali_pm_domain_create(u32 pmu_mask)37 struct mali_pm_domain *mali_pm_domain_create(u32 pmu_mask)
38 {
39 struct mali_pm_domain *domain = NULL;
40 u32 domain_id = 0;
41
42 domain = mali_pm_domain_get_from_mask(pmu_mask);
43 if (NULL != domain) return domain;
44
45 MALI_DEBUG_PRINT(2,
46 ("Mali PM domain: Creating Mali PM domain (mask=0x%08X)\n",
47 pmu_mask));
48
49 domain = (struct mali_pm_domain *)_mali_osk_malloc(
50 sizeof(struct mali_pm_domain));
51 if (NULL != domain) {
52 domain->power_is_on = MALI_FALSE;
53 domain->pmu_mask = pmu_mask;
54 domain->use_count = 0;
55 _mali_osk_list_init(&domain->group_list);
56 _mali_osk_list_init(&domain->l2_cache_list);
57
58 domain_id = _mali_osk_fls(pmu_mask) - 1;
59 /* Verify the domain_id */
60 MALI_DEBUG_ASSERT(MALI_MAX_NUMBER_OF_DOMAINS > domain_id);
61 /* Verify that pmu_mask only one bit is set */
62 MALI_DEBUG_ASSERT((1 << domain_id) == pmu_mask);
63 mali_pm_domains[domain_id] = domain;
64
65 return domain;
66 } else {
67 MALI_DEBUG_PRINT_ERROR(("Unable to create PM domain\n"));
68 }
69
70 return NULL;
71 }
72
mali_pm_domain_delete(struct mali_pm_domain * domain)73 void mali_pm_domain_delete(struct mali_pm_domain *domain)
74 {
75 if (NULL == domain) {
76 return;
77 }
78
79 _mali_osk_list_delinit(&domain->group_list);
80 _mali_osk_list_delinit(&domain->l2_cache_list);
81
82 _mali_osk_free(domain);
83 }
84
mali_pm_domain_add_group(struct mali_pm_domain * domain,struct mali_group * group)85 void mali_pm_domain_add_group(struct mali_pm_domain *domain,
86 struct mali_group *group)
87 {
88 MALI_DEBUG_ASSERT_POINTER(domain);
89 MALI_DEBUG_ASSERT_POINTER(group);
90
91 /*
92 * Use addtail because virtual group is created last and it needs
93 * to be at the end of the list (in order to be activated after
94 * all children.
95 */
96 _mali_osk_list_addtail(&group->pm_domain_list, &domain->group_list);
97 }
98
mali_pm_domain_add_l2_cache(struct mali_pm_domain * domain,struct mali_l2_cache_core * l2_cache)99 void mali_pm_domain_add_l2_cache(struct mali_pm_domain *domain,
100 struct mali_l2_cache_core *l2_cache)
101 {
102 MALI_DEBUG_ASSERT_POINTER(domain);
103 MALI_DEBUG_ASSERT_POINTER(l2_cache);
104 _mali_osk_list_add(&l2_cache->pm_domain_list, &domain->l2_cache_list);
105 }
106
mali_pm_domain_get_from_mask(u32 mask)107 struct mali_pm_domain *mali_pm_domain_get_from_mask(u32 mask)
108 {
109 u32 id = 0;
110
111 if (0 == mask) {
112 return NULL;
113 }
114
115 id = _mali_osk_fls(mask) - 1;
116
117 MALI_DEBUG_ASSERT(MALI_MAX_NUMBER_OF_DOMAINS > id);
118 /* Verify that pmu_mask only one bit is set */
119 MALI_DEBUG_ASSERT((1 << id) == mask);
120
121 return mali_pm_domains[id];
122 }
123
mali_pm_domain_get_from_index(u32 id)124 struct mali_pm_domain *mali_pm_domain_get_from_index(u32 id)
125 {
126 MALI_DEBUG_ASSERT(MALI_MAX_NUMBER_OF_DOMAINS > id);
127
128 return mali_pm_domains[id];
129 }
130
mali_pm_domain_ref_get(struct mali_pm_domain * domain)131 u32 mali_pm_domain_ref_get(struct mali_pm_domain *domain)
132 {
133 MALI_DEBUG_ASSERT_POINTER(domain);
134
135 if (0 == domain->use_count) {
136 _mali_osk_pm_dev_ref_get_async();
137 }
138
139 ++domain->use_count;
140 MALI_DEBUG_PRINT(4, ("PM domain %p: ref_get, use_count => %u\n", domain, domain->use_count));
141
142 /* Return our mask so caller can check this against wanted mask */
143 return domain->pmu_mask;
144 }
145
mali_pm_domain_ref_put(struct mali_pm_domain * domain)146 u32 mali_pm_domain_ref_put(struct mali_pm_domain *domain)
147 {
148 MALI_DEBUG_ASSERT_POINTER(domain);
149
150 --domain->use_count;
151 MALI_DEBUG_PRINT(4, ("PM domain %p: ref_put, use_count => %u\n", domain, domain->use_count));
152
153 if (0 == domain->use_count) {
154 _mali_osk_pm_dev_ref_put();
155 }
156
157 /*
158 * Return the PMU mask which now could be be powered down
159 * (the bit for this domain).
160 * This is the responsibility of the caller (mali_pm)
161 */
162 return (0 == domain->use_count ? domain->pmu_mask : 0);
163 }
164
165 #if MALI_STATE_TRACKING
mali_pm_domain_get_id(struct mali_pm_domain * domain)166 u32 mali_pm_domain_get_id(struct mali_pm_domain *domain)
167 {
168 u32 id = 0;
169
170 MALI_DEBUG_ASSERT_POINTER(domain);
171 MALI_DEBUG_ASSERT(0 != domain->pmu_mask);
172
173 id = _mali_osk_fls(domain->pmu_mask) - 1;
174
175 MALI_DEBUG_ASSERT(MALI_MAX_NUMBER_OF_DOMAINS > id);
176 /* Verify that pmu_mask only one bit is set */
177 MALI_DEBUG_ASSERT((1 << id) == domain->pmu_mask);
178 /* Verify that we have stored the domain at right id/index */
179 MALI_DEBUG_ASSERT(domain == mali_pm_domains[id]);
180
181 return id;
182 }
183 #endif
184
185 #if defined(DEBUG)
mali_pm_domain_all_unused(void)186 mali_bool mali_pm_domain_all_unused(void)
187 {
188 int i;
189
190 for (i = 0; i < MALI_MAX_NUMBER_OF_DOMAINS; i++) {
191 if (NULL == mali_pm_domains[i]) {
192 /* Nothing to check */
193 continue;
194 }
195
196 if (MALI_TRUE == mali_pm_domains[i]->power_is_on) {
197 /* Not ready for suspend! */
198 return MALI_FALSE;
199 }
200
201 if (0 != mali_pm_domains[i]->use_count) {
202 /* Not ready for suspend! */
203 return MALI_FALSE;
204 }
205 }
206
207 return MALI_TRUE;
208 }
209 #endif
210