dbd94d31074155c84a283ab325217fef9494475c
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / arm / mali400 / mali / common / mali_pm.c
1 /*
2  * Copyright (C) 2011-2015 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_pm.h"
12 #include "mali_kernel_common.h"
13 #include "mali_osk.h"
14 #include "mali_osk_mali.h"
15 #include "mali_scheduler.h"
16 #include "mali_group.h"
17 #include "mali_pm_domain.h"
18 #include "mali_pmu.h"
19
20 #include "mali_executor.h"
21 #include "mali_control_timer.h"
22
23 #if defined(DEBUG)
24 u32 num_pm_runtime_resume = 0;
25 u32 num_pm_updates = 0;
26 u32 num_pm_updates_up = 0;
27 u32 num_pm_updates_down = 0;
28 #endif
29
30 #define MALI_PM_DOMAIN_DUMMY_MASK (1 << MALI_DOMAIN_INDEX_DUMMY)
31
32 /* lock protecting power state (including pm_domains) */
33 static _mali_osk_spinlock_irq_t *pm_lock_state = NULL;
34
35 /* the wanted domain mask (protected by pm_lock_state) */
36 static u32 pd_mask_wanted = 0;
37
38 /* used to deferring the actual power changes */
39 static _mali_osk_wq_work_t *pm_work = NULL;
40
41 /* lock protecting power change execution */
42 static _mali_osk_mutex_t *pm_lock_exec = NULL;
43
44 /* PMU domains which are actually powered on (protected by pm_lock_exec) */
45 static u32 pmu_mask_current = 0;
46
47 /*
48  * domains which marked as powered on (protected by pm_lock_exec)
49  * This can be different from pmu_mask_current right after GPU power on
50  * if the PMU domains default to powered up.
51  */
52 static u32 pd_mask_current = 0;
53
54 static u16 domain_config[MALI_MAX_NUMBER_OF_DOMAINS] = {
55         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
56         1 << MALI_DOMAIN_INDEX_DUMMY
57 };
58
59 /* The relative core power cost */
60 #define MALI_GP_COST 3
61 #define MALI_PP_COST 6
62 #define MALI_L2_COST 1
63
64 /*
65  *We have MALI_MAX_NUMBER_OF_PP_PHYSICAL_CORES + 1 rows in this matrix
66  *because we mush store the mask of different pp cores: 0, 1, 2, 3, 4, 5, 6, 7, 8.
67  */
68 static int mali_pm_domain_power_cost_result[MALI_MAX_NUMBER_OF_PHYSICAL_PP_GROUPS + 1][MALI_MAX_NUMBER_OF_DOMAINS];
69 /*
70  * Keep track of runtime PM state, so that we know
71  * how to resume during OS resume.
72  */
73 #ifdef CONFIG_PM_RUNTIME
74 static mali_bool mali_pm_runtime_active = MALI_FALSE;
75 #else
76 /* when kernel don't enable PM_RUNTIME, set the flag always true,
77  * for GPU will not power off by runtime */
78 static mali_bool mali_pm_runtime_active = MALI_TRUE;
79 #endif
80
81 static void mali_pm_state_lock(void);
82 static void mali_pm_state_unlock(void);
83 static _mali_osk_errcode_t mali_pm_create_pm_domains(void);
84 static void mali_pm_set_pmu_domain_config(void);
85 static u32 mali_pm_get_registered_cores_mask(void);
86 static void mali_pm_update_sync_internal(void);
87 static mali_bool mali_pm_common_suspend(void);
88 static void mali_pm_update_work(void *data);
89 #if defined(DEBUG)
90 const char *mali_pm_mask_to_string(u32 mask);
91 const char *mali_pm_group_stats_to_string(void);
92 #endif
93
94 _mali_osk_errcode_t mali_pm_initialize(void)
95 {
96         _mali_osk_errcode_t err;
97         struct mali_pmu_core *pmu;
98
99         pm_lock_state = _mali_osk_spinlock_irq_init(_MALI_OSK_LOCKFLAG_ORDERED,
100                         _MALI_OSK_LOCK_ORDER_PM_STATE);
101         if (NULL == pm_lock_state) {
102                 mali_pm_terminate();
103                 return _MALI_OSK_ERR_FAULT;
104         }
105
106         pm_lock_exec = _mali_osk_mutex_init(_MALI_OSK_LOCKFLAG_ORDERED,
107                                             _MALI_OSK_LOCK_ORDER_PM_STATE);
108         if (NULL == pm_lock_exec) {
109                 mali_pm_terminate();
110                 return _MALI_OSK_ERR_FAULT;
111         }
112
113         pm_work = _mali_osk_wq_create_work(mali_pm_update_work, NULL);
114         if (NULL == pm_work) {
115                 mali_pm_terminate();
116                 return _MALI_OSK_ERR_FAULT;
117         }
118
119         pmu = mali_pmu_get_global_pmu_core();
120         if (NULL != pmu) {
121                 /*
122                  * We have a Mali PMU, set the correct domain
123                  * configuration (default or custom)
124                  */
125
126                 u32 registered_cores_mask;
127
128                 mali_pm_set_pmu_domain_config();
129
130                 registered_cores_mask = mali_pm_get_registered_cores_mask();
131                 mali_pmu_set_registered_cores_mask(pmu, registered_cores_mask);
132
133                 MALI_DEBUG_ASSERT(0 == pd_mask_wanted);
134         }
135
136         /* Create all power domains needed (at least one dummy domain) */
137         err = mali_pm_create_pm_domains();
138         if (_MALI_OSK_ERR_OK != err) {
139                 mali_pm_terminate();
140                 return err;
141         }
142
143         return _MALI_OSK_ERR_OK;
144 }
145
146 void mali_pm_terminate(void)
147 {
148         if (NULL != pm_work) {
149                 _mali_osk_wq_delete_work(pm_work);
150                 pm_work = NULL;
151         }
152
153         mali_pm_domain_terminate();
154
155         if (NULL != pm_lock_exec) {
156                 _mali_osk_mutex_term(pm_lock_exec);
157                 pm_lock_exec = NULL;
158         }
159
160         if (NULL != pm_lock_state) {
161                 _mali_osk_spinlock_irq_term(pm_lock_state);
162                 pm_lock_state = NULL;
163         }
164 }
165
166 struct mali_pm_domain *mali_pm_register_l2_cache(u32 domain_index,
167                 struct mali_l2_cache_core *l2_cache)
168 {
169         struct mali_pm_domain *domain;
170
171         domain = mali_pm_domain_get_from_mask(domain_config[domain_index]);
172         if (NULL == domain) {
173                 MALI_DEBUG_ASSERT(0 == domain_config[domain_index]);
174                 domain = mali_pm_domain_get_from_index(
175                                  MALI_DOMAIN_INDEX_DUMMY);
176                 domain_config[domain_index] = MALI_PM_DOMAIN_DUMMY_MASK;
177         } else {
178                 MALI_DEBUG_ASSERT(0 != domain_config[domain_index]);
179         }
180
181         MALI_DEBUG_ASSERT(NULL != domain);
182
183         mali_pm_domain_add_l2_cache(domain, l2_cache);
184
185         return domain; /* return the actual domain this was registered in */
186 }
187
188 struct mali_pm_domain *mali_pm_register_group(u32 domain_index,
189                 struct mali_group *group)
190 {
191         struct mali_pm_domain *domain;
192
193         domain = mali_pm_domain_get_from_mask(domain_config[domain_index]);
194         if (NULL == domain) {
195                 MALI_DEBUG_ASSERT(0 == domain_config[domain_index]);
196                 domain = mali_pm_domain_get_from_index(
197                                  MALI_DOMAIN_INDEX_DUMMY);
198                 domain_config[domain_index] = MALI_PM_DOMAIN_DUMMY_MASK;
199         } else {
200                 MALI_DEBUG_ASSERT(0 != domain_config[domain_index]);
201         }
202
203         MALI_DEBUG_ASSERT(NULL != domain);
204
205         mali_pm_domain_add_group(domain, group);
206
207         return domain; /* return the actual domain this was registered in */
208 }
209
210 mali_bool mali_pm_get_domain_refs(struct mali_pm_domain **domains,
211                                   struct mali_group **groups,
212                                   u32 num_domains)
213 {
214         mali_bool ret = MALI_TRUE; /* Assume all is powered on instantly */
215         u32 i;
216
217         mali_pm_state_lock();
218
219         for (i = 0; i < num_domains; i++) {
220                 MALI_DEBUG_ASSERT_POINTER(domains[i]);
221                 pd_mask_wanted |= mali_pm_domain_ref_get(domains[i]);
222                 if (MALI_FALSE == mali_pm_domain_power_is_on(domains[i])) {
223                         /*
224                          * Tell caller that the corresponding group
225                          * was not already powered on.
226                          */
227                         ret = MALI_FALSE;
228                 } else {
229                         /*
230                          * There is a time gap between we power on the domain and
231                          * set the power state of the corresponding groups to be on.
232                          */
233                         if (NULL != groups[i] &&
234                             MALI_FALSE == mali_group_power_is_on(groups[i])) {
235                                 ret = MALI_FALSE;
236                         }
237                 }
238         }
239
240         MALI_DEBUG_PRINT(3, ("PM: wanted domain mask = 0x%08X (get refs)\n", pd_mask_wanted));
241
242         mali_pm_state_unlock();
243
244         return ret;
245 }
246
247 mali_bool mali_pm_put_domain_refs(struct mali_pm_domain **domains,
248                                   u32 num_domains)
249 {
250         u32 mask = 0;
251         mali_bool ret;
252         u32 i;
253
254         mali_pm_state_lock();
255
256         for (i = 0; i < num_domains; i++) {
257                 MALI_DEBUG_ASSERT_POINTER(domains[i]);
258                 mask |= mali_pm_domain_ref_put(domains[i]);
259         }
260
261         if (0 == mask) {
262                 /* return false, all domains should still stay on */
263                 ret = MALI_FALSE;
264         } else {
265                 /* Assert that we are dealing with a change */
266                 MALI_DEBUG_ASSERT((pd_mask_wanted & mask) == mask);
267
268                 /* Update our desired domain mask */
269                 pd_mask_wanted &= ~mask;
270
271                 /* return true; one or more domains can now be powered down */
272                 ret = MALI_TRUE;
273         }
274
275         MALI_DEBUG_PRINT(3, ("PM: wanted domain mask = 0x%08X (put refs)\n", pd_mask_wanted));
276
277         mali_pm_state_unlock();
278
279         return ret;
280 }
281
282 void mali_pm_init_begin(void)
283 {
284         struct mali_pmu_core *pmu = mali_pmu_get_global_pmu_core();
285
286         _mali_osk_pm_dev_ref_get_sync();
287
288         /* Ensure all PMU domains are on */
289         if (NULL != pmu) {
290                 mali_pmu_power_up_all(pmu);
291         }
292 }
293
294 void mali_pm_init_end(void)
295 {
296         struct mali_pmu_core *pmu = mali_pmu_get_global_pmu_core();
297
298         /* Ensure all PMU domains are off */
299         if (NULL != pmu) {
300                 mali_pmu_power_down_all(pmu);
301         }
302
303         _mali_osk_pm_dev_ref_put();
304 }
305
306 void mali_pm_update_sync(void)
307 {
308         mali_pm_exec_lock();
309
310         if (MALI_TRUE == mali_pm_runtime_active) {
311                 /*
312                  * Only update if GPU is powered on.
313                  * Deactivation of the last group will result in both a
314                  * deferred runtime PM suspend operation and
315                  * deferred execution of this function.
316                  * mali_pm_runtime_active will be false if runtime PM
317                  * executed first and thus the GPU is now fully powered off.
318                  */
319                 mali_pm_update_sync_internal();
320         }
321
322         mali_pm_exec_unlock();
323 }
324
325 void mali_pm_update_async(void)
326 {
327         _mali_osk_wq_schedule_work(pm_work);
328 }
329
330 void mali_pm_os_suspend(mali_bool os_suspend)
331 {
332         int ret;
333
334         MALI_DEBUG_PRINT(3, ("Mali PM: OS suspend\n"));
335
336         /* Suspend execution of all jobs, and go to inactive state */
337         mali_executor_suspend();
338
339         if (os_suspend) {
340                 mali_control_timer_suspend(MALI_TRUE);
341         }
342
343         mali_pm_exec_lock();
344
345         ret = mali_pm_common_suspend();
346
347         MALI_DEBUG_ASSERT(MALI_TRUE == ret);
348         MALI_IGNORE(ret);
349
350         mali_pm_exec_unlock();
351 }
352
353 void mali_pm_os_resume(void)
354 {
355         struct mali_pmu_core *pmu = mali_pmu_get_global_pmu_core();
356
357         MALI_DEBUG_PRINT(3, ("Mali PM: OS resume\n"));
358
359         mali_pm_exec_lock();
360
361 #if defined(DEBUG)
362         mali_pm_state_lock();
363
364         /* Assert that things are as we left them in os_suspend(). */
365         MALI_DEBUG_ASSERT(0 == pd_mask_wanted);
366         MALI_DEBUG_ASSERT(0 == pd_mask_current);
367         MALI_DEBUG_ASSERT(0 == pmu_mask_current);
368
369         MALI_DEBUG_ASSERT(MALI_TRUE == mali_pm_domain_all_unused());
370
371         mali_pm_state_unlock();
372 #endif
373
374         if (MALI_TRUE == mali_pm_runtime_active) {
375                 /* Runtime PM was active, so reset PMU */
376                 if (NULL != pmu) {
377                         mali_pmu_reset(pmu);
378                         pmu_mask_current = mali_pmu_get_mask(pmu);
379
380                         MALI_DEBUG_PRINT(3, ("Mali PM: OS resume 0x%x \n", pmu_mask_current));
381                 }
382
383                 mali_pm_update_sync_internal();
384         }
385
386         mali_pm_exec_unlock();
387
388         /* Start executing jobs again */
389         mali_executor_resume();
390 }
391
392 mali_bool mali_pm_runtime_suspend(void)
393 {
394         mali_bool ret;
395
396         MALI_DEBUG_PRINT(3, ("Mali PM: Runtime suspend\n"));
397
398         mali_pm_exec_lock();
399
400         /*
401          * Put SW state directly into "off" state, and do not bother to power
402          * down each power domain, because entire GPU will be powered off
403          * when we return.
404          * For runtime PM suspend, in contrast to OS suspend, there is a race
405          * between this function and the mali_pm_update_sync_internal(), which
406          * is fine...
407          */
408         ret = mali_pm_common_suspend();
409         if (MALI_TRUE == ret) {
410                 mali_pm_runtime_active = MALI_FALSE;
411         } else {
412                 /*
413                  * Process the "power up" instead,
414                  * which could have been "lost"
415                  */
416                 mali_pm_update_sync_internal();
417         }
418
419         mali_pm_exec_unlock();
420
421         return ret;
422 }
423
424 void mali_pm_runtime_resume(void)
425 {
426         struct mali_pmu_core *pmu = mali_pmu_get_global_pmu_core();
427
428         mali_pm_exec_lock();
429
430         mali_pm_runtime_active = MALI_TRUE;
431
432 #if defined(DEBUG)
433         ++num_pm_runtime_resume;
434
435         mali_pm_state_lock();
436
437         /*
438          * Assert that things are as we left them in runtime_suspend(),
439          * except for pd_mask_wanted which normally will be the reason we
440          * got here (job queued => domains wanted)
441          */
442         MALI_DEBUG_ASSERT(0 == pd_mask_current);
443         MALI_DEBUG_ASSERT(0 == pmu_mask_current);
444
445         mali_pm_state_unlock();
446 #endif
447
448         if (NULL != pmu) {
449                 mali_pmu_reset(pmu);
450                 pmu_mask_current = mali_pmu_get_mask(pmu);
451                 MALI_DEBUG_PRINT(3, ("Mali PM: Runtime resume 0x%x \n", pmu_mask_current));
452         }
453
454         /*
455          * Normally we are resumed because a job has just been queued.
456          * pd_mask_wanted should thus be != 0.
457          * It is however possible for others to take a Mali Runtime PM ref
458          * without having a job queued.
459          * We should however always call mali_pm_update_sync_internal(),
460          * because this will take care of any potential mismatch between
461          * pmu_mask_current and pd_mask_current.
462          */
463         mali_pm_update_sync_internal();
464
465         mali_pm_exec_unlock();
466 }
467
468 #if MALI_STATE_TRACKING
469 u32 mali_pm_dump_state_domain(struct mali_pm_domain *domain,
470                               char *buf, u32 size)
471 {
472         int n = 0;
473
474         n += _mali_osk_snprintf(buf + n, size - n,
475                                 "\tPower domain: id %u\n",
476                                 mali_pm_domain_get_id(domain));
477
478         n += _mali_osk_snprintf(buf + n, size - n,
479                                 "\t\tMask: 0x%04x\n",
480                                 mali_pm_domain_get_mask(domain));
481
482         n += _mali_osk_snprintf(buf + n, size - n,
483                                 "\t\tUse count: %u\n",
484                                 mali_pm_domain_get_use_count(domain));
485
486         n += _mali_osk_snprintf(buf + n, size - n,
487                                 "\t\tCurrent power state: %s\n",
488                                 (mali_pm_domain_get_mask(domain) & pd_mask_current) ?
489                                 "On" : "Off");
490
491         n += _mali_osk_snprintf(buf + n, size - n,
492                                 "\t\tWanted power state: %s\n",
493                                 (mali_pm_domain_get_mask(domain) & pd_mask_wanted) ?
494                                 "On" : "Off");
495
496         return n;
497 }
498 #endif
499
500 static void mali_pm_state_lock(void)
501 {
502         _mali_osk_spinlock_irq_lock(pm_lock_state);
503 }
504
505 static void mali_pm_state_unlock(void)
506 {
507         _mali_osk_spinlock_irq_unlock(pm_lock_state);
508 }
509
510 void mali_pm_exec_lock(void)
511 {
512         _mali_osk_mutex_wait(pm_lock_exec);
513 }
514
515 void mali_pm_exec_unlock(void)
516 {
517         _mali_osk_mutex_signal(pm_lock_exec);
518 }
519
520 static void mali_pm_domain_power_up(u32 power_up_mask,
521                                     struct mali_group *groups_up[MALI_MAX_NUMBER_OF_GROUPS],
522                                     u32 *num_groups_up,
523                                     struct mali_l2_cache_core *l2_up[MALI_MAX_NUMBER_OF_L2_CACHE_CORES],
524                                     u32 *num_l2_up)
525 {
526         u32 domain_bit;
527         u32 notify_mask = power_up_mask;
528
529         MALI_DEBUG_ASSERT(0 != power_up_mask);
530         MALI_DEBUG_ASSERT_POINTER(groups_up);
531         MALI_DEBUG_ASSERT_POINTER(num_groups_up);
532         MALI_DEBUG_ASSERT(0 == *num_groups_up);
533         MALI_DEBUG_ASSERT_POINTER(l2_up);
534         MALI_DEBUG_ASSERT_POINTER(num_l2_up);
535         MALI_DEBUG_ASSERT(0 == *num_l2_up);
536
537         MALI_DEBUG_ASSERT_LOCK_HELD(pm_lock_exec);
538         MALI_DEBUG_ASSERT_LOCK_HELD(pm_lock_state);
539
540         MALI_DEBUG_PRINT(5,
541                          ("PM update:      Powering up domains: . [%s]\n",
542                           mali_pm_mask_to_string(power_up_mask)));
543
544         pd_mask_current |= power_up_mask;
545
546         domain_bit = _mali_osk_fls(notify_mask);
547         while (0 != domain_bit) {
548                 u32 domain_id = domain_bit - 1;
549                 struct mali_pm_domain *domain =
550                         mali_pm_domain_get_from_index(
551                                 domain_id);
552                 struct mali_l2_cache_core *l2_cache;
553                 struct mali_l2_cache_core *l2_cache_tmp;
554                 struct mali_group *group;
555                 struct mali_group *group_tmp;
556
557                 /* Mark domain as powered up */
558                 mali_pm_domain_set_power_on(domain, MALI_TRUE);
559
560                 /*
561                  * Make a note of the L2 and/or group(s) to notify
562                  * (need to release the PM state lock before doing so)
563                  */
564
565                 _MALI_OSK_LIST_FOREACHENTRY(l2_cache,
566                                             l2_cache_tmp,
567                                             mali_pm_domain_get_l2_cache_list(
568                                                     domain),
569                                             struct mali_l2_cache_core,
570                                             pm_domain_list) {
571                         MALI_DEBUG_ASSERT(*num_l2_up <
572                                           MALI_MAX_NUMBER_OF_L2_CACHE_CORES);
573                         l2_up[*num_l2_up] = l2_cache;
574                         (*num_l2_up)++;
575                 }
576
577                 _MALI_OSK_LIST_FOREACHENTRY(group,
578                                             group_tmp,
579                                             mali_pm_domain_get_group_list(domain),
580                                             struct mali_group,
581                                             pm_domain_list) {
582                         MALI_DEBUG_ASSERT(*num_groups_up <
583                                           MALI_MAX_NUMBER_OF_GROUPS);
584                         groups_up[*num_groups_up] = group;
585
586                         (*num_groups_up)++;
587                 }
588
589                 /* Remove current bit and find next */
590                 notify_mask &= ~(1 << (domain_id));
591                 domain_bit = _mali_osk_fls(notify_mask);
592         }
593 }
594 static void mali_pm_domain_power_down(u32 power_down_mask,
595                                       struct mali_group *groups_down[MALI_MAX_NUMBER_OF_GROUPS],
596                                       u32 *num_groups_down,
597                                       struct mali_l2_cache_core *l2_down[MALI_MAX_NUMBER_OF_L2_CACHE_CORES],
598                                       u32 *num_l2_down)
599 {
600         u32 domain_bit;
601         u32 notify_mask = power_down_mask;
602
603         MALI_DEBUG_ASSERT(0 != power_down_mask);
604         MALI_DEBUG_ASSERT_POINTER(groups_down);
605         MALI_DEBUG_ASSERT_POINTER(num_groups_down);
606         MALI_DEBUG_ASSERT(0 == *num_groups_down);
607         MALI_DEBUG_ASSERT_POINTER(l2_down);
608         MALI_DEBUG_ASSERT_POINTER(num_l2_down);
609         MALI_DEBUG_ASSERT(0 == *num_l2_down);
610
611         MALI_DEBUG_ASSERT_LOCK_HELD(pm_lock_exec);
612         MALI_DEBUG_ASSERT_LOCK_HELD(pm_lock_state);
613
614         MALI_DEBUG_PRINT(5,
615                          ("PM update:      Powering down domains: [%s]\n",
616                           mali_pm_mask_to_string(power_down_mask)));
617
618         pd_mask_current &= ~power_down_mask;
619
620         domain_bit = _mali_osk_fls(notify_mask);
621         while (0 != domain_bit) {
622                 u32 domain_id = domain_bit - 1;
623                 struct mali_pm_domain *domain =
624                         mali_pm_domain_get_from_index(domain_id);
625                 struct mali_l2_cache_core *l2_cache;
626                 struct mali_l2_cache_core *l2_cache_tmp;
627                 struct mali_group *group;
628                 struct mali_group *group_tmp;
629
630                 /* Mark domain as powered down */
631                 mali_pm_domain_set_power_on(domain, MALI_FALSE);
632
633                 /*
634                  * Make a note of the L2s and/or groups to notify
635                  * (need to release the PM state lock before doing so)
636                  */
637
638                 _MALI_OSK_LIST_FOREACHENTRY(l2_cache,
639                                             l2_cache_tmp,
640                                             mali_pm_domain_get_l2_cache_list(domain),
641                                             struct mali_l2_cache_core,
642                                             pm_domain_list) {
643                         MALI_DEBUG_ASSERT(*num_l2_down <
644                                           MALI_MAX_NUMBER_OF_L2_CACHE_CORES);
645                         l2_down[*num_l2_down] = l2_cache;
646                         (*num_l2_down)++;
647                 }
648
649                 _MALI_OSK_LIST_FOREACHENTRY(group,
650                                             group_tmp,
651                                             mali_pm_domain_get_group_list(domain),
652                                             struct mali_group,
653                                             pm_domain_list) {
654                         MALI_DEBUG_ASSERT(*num_groups_down <
655                                           MALI_MAX_NUMBER_OF_GROUPS);
656                         groups_down[*num_groups_down] = group;
657                         (*num_groups_down)++;
658                 }
659
660                 /* Remove current bit and find next */
661                 notify_mask &= ~(1 << (domain_id));
662                 domain_bit = _mali_osk_fls(notify_mask);
663         }
664 }
665
666 /*
667  * Execute pending power domain changes
668  * pm_lock_exec lock must be taken by caller.
669  */
670 static void mali_pm_update_sync_internal(void)
671 {
672         /*
673          * This should only be called in non-atomic context
674          * (normally as deferred work)
675          *
676          * Look at the pending power domain changes, and execute these.
677          * Make sure group and schedulers are notified about changes.
678          */
679
680         struct mali_pmu_core *pmu = mali_pmu_get_global_pmu_core();
681
682         u32 power_down_mask;
683         u32 power_up_mask;
684
685         MALI_DEBUG_ASSERT_LOCK_HELD(pm_lock_exec);
686
687 #if defined(DEBUG)
688         ++num_pm_updates;
689 #endif
690
691         /* Hold PM state lock while we look at (and obey) the wanted state */
692         mali_pm_state_lock();
693
694         MALI_DEBUG_PRINT(5, ("PM update pre:  Wanted domain mask: .. [%s]\n",
695                              mali_pm_mask_to_string(pd_mask_wanted)));
696         MALI_DEBUG_PRINT(5, ("PM update pre:  Current domain mask: . [%s]\n",
697                              mali_pm_mask_to_string(pd_mask_current)));
698         MALI_DEBUG_PRINT(5, ("PM update pre:  Current PMU mask: .... [%s]\n",
699                              mali_pm_mask_to_string(pmu_mask_current)));
700         MALI_DEBUG_PRINT(5, ("PM update pre:  Group power stats: ... <%s>\n",
701                              mali_pm_group_stats_to_string()));
702
703         /* Figure out which cores we need to power on */
704         power_up_mask = pd_mask_wanted &
705                         (pd_mask_wanted ^ pd_mask_current);
706
707         if (0 != power_up_mask) {
708                 u32 power_up_mask_pmu;
709                 struct mali_group *groups_up[MALI_MAX_NUMBER_OF_GROUPS];
710                 u32 num_groups_up = 0;
711                 struct mali_l2_cache_core *
712                         l2_up[MALI_MAX_NUMBER_OF_L2_CACHE_CORES];
713                 u32 num_l2_up = 0;
714                 u32 i;
715
716 #if defined(DEBUG)
717                 ++num_pm_updates_up;
718 #endif
719
720                 /*
721                  * Make sure dummy/global domain is always included when
722                  * powering up, since this is controlled by runtime PM,
723                  * and device power is on at this stage.
724                  */
725                 power_up_mask |= MALI_PM_DOMAIN_DUMMY_MASK;
726
727                 /* Power up only real PMU domains */
728                 power_up_mask_pmu = power_up_mask & ~MALI_PM_DOMAIN_DUMMY_MASK;
729
730                 /* But not those that happen to be powered on already */
731                 power_up_mask_pmu &= (power_up_mask ^ pmu_mask_current) &
732                                      power_up_mask;
733
734                 if (0 != power_up_mask_pmu) {
735                         MALI_DEBUG_ASSERT(NULL != pmu);
736                         pmu_mask_current |= power_up_mask_pmu;
737                         mali_pmu_power_up(pmu, power_up_mask_pmu);
738                 }
739
740                 /*
741                  * Put the domains themselves in power up state.
742                  * We get the groups and L2s to notify in return.
743                  */
744                 mali_pm_domain_power_up(power_up_mask,
745                                         groups_up, &num_groups_up,
746                                         l2_up, &num_l2_up);
747
748                 /* Need to unlock PM state lock before notifying L2 + groups */
749                 mali_pm_state_unlock();
750
751                 /* Notify each L2 cache that we have be powered up */
752                 for (i = 0; i < num_l2_up; i++) {
753                         mali_l2_cache_power_up(l2_up[i]);
754                 }
755
756                 /*
757                  * Tell execution module about all the groups we have
758                  * powered up. Groups will be notified as a result of this.
759                  */
760                 mali_executor_group_power_up(groups_up, num_groups_up);
761
762                 /* Lock state again before checking for power down */
763                 mali_pm_state_lock();
764         }
765
766         /* Figure out which cores we need to power off */
767         power_down_mask = pd_mask_current &
768                           (pd_mask_wanted ^ pd_mask_current);
769
770         /*
771          * Never power down the dummy/global domain here. This is to be done
772          * from a suspend request (since this domain is only physicall powered
773          * down at that point)
774          */
775         power_down_mask &= ~MALI_PM_DOMAIN_DUMMY_MASK;
776
777         if (0 != power_down_mask) {
778                 u32 power_down_mask_pmu;
779                 struct mali_group *groups_down[MALI_MAX_NUMBER_OF_GROUPS];
780                 u32 num_groups_down = 0;
781                 struct mali_l2_cache_core *
782                         l2_down[MALI_MAX_NUMBER_OF_L2_CACHE_CORES];
783                 u32 num_l2_down = 0;
784                 u32 i;
785
786 #if defined(DEBUG)
787                 ++num_pm_updates_down;
788 #endif
789
790                 /*
791                  * Put the domains themselves in power down state.
792                  * We get the groups and L2s to notify in return.
793                  */
794                 mali_pm_domain_power_down(power_down_mask,
795                                           groups_down, &num_groups_down,
796                                           l2_down, &num_l2_down);
797
798                 /* Need to unlock PM state lock before notifying L2 + groups */
799                 mali_pm_state_unlock();
800
801                 /*
802                  * Tell execution module about all the groups we will be
803                  * powering down. Groups will be notified as a result of this.
804                  */
805                 if (0 < num_groups_down) {
806                         mali_executor_group_power_down(groups_down, num_groups_down);
807                 }
808
809                 /* Notify each L2 cache that we will be powering down */
810                 for (i = 0; i < num_l2_down; i++) {
811                         mali_l2_cache_power_down(l2_down[i]);
812                 }
813
814                 /*
815                  * Power down only PMU domains which should not stay on
816                  * Some domains might for instance currently be incorrectly
817                  * powered up if default domain power state is all on.
818                  */
819                 power_down_mask_pmu = pmu_mask_current & (~pd_mask_current);
820
821                 if (0 != power_down_mask_pmu) {
822                         MALI_DEBUG_ASSERT(NULL != pmu);
823                         pmu_mask_current &= ~power_down_mask_pmu;
824                         mali_pmu_power_down(pmu, power_down_mask_pmu);
825
826                 }
827         } else {
828                 /*
829                  * Power down only PMU domains which should not stay on
830                  * Some domains might for instance currently be incorrectly
831                  * powered up if default domain power state is all on.
832                  */
833                 u32 power_down_mask_pmu;
834
835                 /* No need for state lock since we'll only update PMU */
836                 mali_pm_state_unlock();
837
838                 power_down_mask_pmu = pmu_mask_current & (~pd_mask_current);
839
840                 if (0 != power_down_mask_pmu) {
841                         MALI_DEBUG_ASSERT(NULL != pmu);
842                         pmu_mask_current &= ~power_down_mask_pmu;
843                         mali_pmu_power_down(pmu, power_down_mask_pmu);
844                 }
845         }
846
847         MALI_DEBUG_PRINT(5, ("PM update post: Current domain mask: . [%s]\n",
848                              mali_pm_mask_to_string(pd_mask_current)));
849         MALI_DEBUG_PRINT(5, ("PM update post: Current PMU mask: .... [%s]\n",
850                              mali_pm_mask_to_string(pmu_mask_current)));
851         MALI_DEBUG_PRINT(5, ("PM update post: Group power stats: ... <%s>\n",
852                              mali_pm_group_stats_to_string()));
853 }
854
855 static mali_bool mali_pm_common_suspend(void)
856 {
857         mali_pm_state_lock();
858
859         if (0 != pd_mask_wanted) {
860                 MALI_DEBUG_PRINT(5, ("PM: Aborting suspend operation\n\n\n"));
861                 mali_pm_state_unlock();
862                 return MALI_FALSE;
863         }
864
865         MALI_DEBUG_PRINT(5, ("PM suspend pre: Wanted domain mask: .. [%s]\n",
866                              mali_pm_mask_to_string(pd_mask_wanted)));
867         MALI_DEBUG_PRINT(5, ("PM suspend pre: Current domain mask: . [%s]\n",
868                              mali_pm_mask_to_string(pd_mask_current)));
869         MALI_DEBUG_PRINT(5, ("PM suspend pre: Current PMU mask: .... [%s]\n",
870                              mali_pm_mask_to_string(pmu_mask_current)));
871         MALI_DEBUG_PRINT(5, ("PM suspend pre: Group power stats: ... <%s>\n",
872                              mali_pm_group_stats_to_string()));
873
874         if (0 != pd_mask_current) {
875                 /*
876                  * We have still some domains powered on.
877                  * It is for instance very normal that at least the
878                  * dummy/global domain is marked as powered on at this point.
879                  * (because it is physically powered on until this function
880                  * returns)
881                  */
882
883                 struct mali_group *groups_down[MALI_MAX_NUMBER_OF_GROUPS];
884                 u32 num_groups_down = 0;
885                 struct mali_l2_cache_core *
886                         l2_down[MALI_MAX_NUMBER_OF_L2_CACHE_CORES];
887                 u32 num_l2_down = 0;
888                 u32 i;
889
890                 /*
891                  * Put the domains themselves in power down state.
892                  * We get the groups and L2s to notify in return.
893                  */
894                 mali_pm_domain_power_down(pd_mask_current,
895                                           groups_down,
896                                           &num_groups_down,
897                                           l2_down,
898                                           &num_l2_down);
899
900                 MALI_DEBUG_ASSERT(0 == pd_mask_current);
901                 MALI_DEBUG_ASSERT(MALI_TRUE == mali_pm_domain_all_unused());
902
903                 /* Need to unlock PM state lock before notifying L2 + groups */
904                 mali_pm_state_unlock();
905
906                 /*
907                  * Tell execution module about all the groups we will be
908                  * powering down. Groups will be notified as a result of this.
909                  */
910                 if (0 < num_groups_down) {
911                         mali_executor_group_power_down(groups_down, num_groups_down);
912                 }
913
914                 /* Notify each L2 cache that we will be powering down */
915                 for (i = 0; i < num_l2_down; i++) {
916                         mali_l2_cache_power_down(l2_down[i]);
917                 }
918
919                 pmu_mask_current = 0;
920         } else {
921                 MALI_DEBUG_ASSERT(0 == pmu_mask_current);
922
923                 MALI_DEBUG_ASSERT(MALI_TRUE == mali_pm_domain_all_unused());
924
925                 mali_pm_state_unlock();
926         }
927
928         MALI_DEBUG_PRINT(5, ("PM suspend post: Current domain mask:  [%s]\n",
929                              mali_pm_mask_to_string(pd_mask_current)));
930         MALI_DEBUG_PRINT(5, ("PM suspend post: Current PMU mask: ... [%s]\n",
931                              mali_pm_mask_to_string(pmu_mask_current)));
932         MALI_DEBUG_PRINT(5, ("PM suspend post: Group power stats: .. <%s>\n",
933                              mali_pm_group_stats_to_string()));
934
935         return MALI_TRUE;
936 }
937
938 static void mali_pm_update_work(void *data)
939 {
940         MALI_IGNORE(data);
941         mali_pm_update_sync();
942 }
943
944 static _mali_osk_errcode_t mali_pm_create_pm_domains(void)
945 {
946         int i;
947
948         /* Create all domains (including dummy domain) */
949         for (i = 0; i < MALI_MAX_NUMBER_OF_DOMAINS; i++) {
950                 if (0x0 == domain_config[i]) continue;
951
952                 if (NULL == mali_pm_domain_create(domain_config[i])) {
953                         return _MALI_OSK_ERR_NOMEM;
954                 }
955         }
956
957         return _MALI_OSK_ERR_OK;
958 }
959
960 static void mali_pm_set_default_pm_domain_config(void)
961 {
962         MALI_DEBUG_ASSERT(0 != _mali_osk_resource_base_address());
963
964         /* GP core */
965         if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(
966                     MALI_OFFSET_GP, NULL)) {
967                 domain_config[MALI_DOMAIN_INDEX_GP] = 0x01;
968         }
969
970         /* PP0 - PP3 core */
971         if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(
972                     MALI_OFFSET_PP0, NULL)) {
973                 if (mali_is_mali400()) {
974                         domain_config[MALI_DOMAIN_INDEX_PP0] = 0x01 << 2;
975                 } else if (mali_is_mali450()) {
976                         domain_config[MALI_DOMAIN_INDEX_PP0] = 0x01 << 1;
977                 } else if (mali_is_mali470()) {
978                         domain_config[MALI_DOMAIN_INDEX_PP0] = 0x01 << 0;
979                 }
980         }
981
982         if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(
983                     MALI_OFFSET_PP1, NULL)) {
984                 if (mali_is_mali400()) {
985                         domain_config[MALI_DOMAIN_INDEX_PP1] = 0x01 << 3;
986                 } else if (mali_is_mali450()) {
987                         domain_config[MALI_DOMAIN_INDEX_PP1] = 0x01 << 2;
988                 } else if (mali_is_mali470()) {
989                         domain_config[MALI_DOMAIN_INDEX_PP1] = 0x01 << 1;
990                 }
991         }
992
993         if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(
994                     MALI_OFFSET_PP2, NULL)) {
995                 if (mali_is_mali400()) {
996                         domain_config[MALI_DOMAIN_INDEX_PP2] = 0x01 << 4;
997                 } else if (mali_is_mali450()) {
998                         domain_config[MALI_DOMAIN_INDEX_PP2] = 0x01 << 2;
999                 } else if (mali_is_mali470()) {
1000                         domain_config[MALI_DOMAIN_INDEX_PP2] = 0x01 << 1;
1001                 }
1002         }
1003
1004         if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(
1005                     MALI_OFFSET_PP3, NULL)) {
1006                 if (mali_is_mali400()) {
1007                         domain_config[MALI_DOMAIN_INDEX_PP3] = 0x01 << 5;
1008                 } else if (mali_is_mali450()) {
1009                         domain_config[MALI_DOMAIN_INDEX_PP3] = 0x01 << 2;
1010                 } else if (mali_is_mali470()) {
1011                         domain_config[MALI_DOMAIN_INDEX_PP3] = 0x01 << 1;
1012                 }
1013         }
1014
1015         /* PP4 - PP7 */
1016         if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(
1017                     MALI_OFFSET_PP4, NULL)) {
1018                 domain_config[MALI_DOMAIN_INDEX_PP4] = 0x01 << 3;
1019         }
1020
1021         if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(
1022                     MALI_OFFSET_PP5, NULL)) {
1023                 domain_config[MALI_DOMAIN_INDEX_PP5] = 0x01 << 3;
1024         }
1025
1026         if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(
1027                     MALI_OFFSET_PP6, NULL)) {
1028                 domain_config[MALI_DOMAIN_INDEX_PP6] = 0x01 << 3;
1029         }
1030
1031         if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(
1032                     MALI_OFFSET_PP7, NULL)) {
1033                 domain_config[MALI_DOMAIN_INDEX_PP7] = 0x01 << 3;
1034         }
1035
1036         /* L2gp/L2PP0/L2PP4 */
1037         if (mali_is_mali400()) {
1038                 if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(
1039                             MALI400_OFFSET_L2_CACHE0, NULL)) {
1040                         domain_config[MALI_DOMAIN_INDEX_L20] = 0x01 << 1;
1041                 }
1042         } else if (mali_is_mali450()) {
1043                 if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(
1044                             MALI450_OFFSET_L2_CACHE0, NULL)) {
1045                         domain_config[MALI_DOMAIN_INDEX_L20] = 0x01 << 0;
1046                 }
1047
1048                 if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(
1049                             MALI450_OFFSET_L2_CACHE1, NULL)) {
1050                         domain_config[MALI_DOMAIN_INDEX_L21] = 0x01 << 1;
1051                 }
1052
1053                 if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(
1054                             MALI450_OFFSET_L2_CACHE2, NULL)) {
1055                         domain_config[MALI_DOMAIN_INDEX_L22] = 0x01 << 3;
1056                 }
1057         } else if (mali_is_mali470()) {
1058                 if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(
1059                             MALI470_OFFSET_L2_CACHE1, NULL)) {
1060                         domain_config[MALI_DOMAIN_INDEX_L21] = 0x01 << 0;
1061                 }
1062         }
1063 }
1064
1065 static u32 mali_pm_get_registered_cores_mask(void)
1066 {
1067         int i = 0;
1068         u32 mask = 0;
1069
1070         for (i = 0; i < MALI_DOMAIN_INDEX_DUMMY; i++) {
1071                 mask |= domain_config[i];
1072         }
1073
1074         return mask;
1075 }
1076
1077 static void mali_pm_set_pmu_domain_config(void)
1078 {
1079         int i = 0;
1080
1081         _mali_osk_device_data_pmu_config_get(domain_config, MALI_MAX_NUMBER_OF_DOMAINS - 1);
1082
1083         for (i = 0; i < MALI_MAX_NUMBER_OF_DOMAINS - 1; i++) {
1084                 if (0 != domain_config[i]) {
1085                         MALI_DEBUG_PRINT(2, ("Using customer pmu config:\n"));
1086                         break;
1087                 }
1088         }
1089
1090         if (MALI_MAX_NUMBER_OF_DOMAINS - 1 == i) {
1091                 MALI_DEBUG_PRINT(2, ("Using hw detect pmu config:\n"));
1092                 mali_pm_set_default_pm_domain_config();
1093         }
1094
1095         for (i = 0; i < MALI_MAX_NUMBER_OF_DOMAINS - 1; i++) {
1096                 if (domain_config[i]) {
1097                         MALI_DEBUG_PRINT(2, ("domain_config[%d] = 0x%x \n", i, domain_config[i]));
1098                 }
1099         }
1100         /* Can't override dummy domain mask */
1101         domain_config[MALI_DOMAIN_INDEX_DUMMY] =
1102                 1 << MALI_DOMAIN_INDEX_DUMMY;
1103 }
1104
1105 #if defined(DEBUG)
1106 const char *mali_pm_mask_to_string(u32 mask)
1107 {
1108         static char bit_str[MALI_MAX_NUMBER_OF_DOMAINS + 1];
1109         int bit;
1110         int str_pos = 0;
1111
1112         /* Must be protected by lock since we use shared string buffer */
1113         if (NULL != pm_lock_exec) {
1114                 MALI_DEBUG_ASSERT_LOCK_HELD(pm_lock_exec);
1115         }
1116
1117         for (bit = MALI_MAX_NUMBER_OF_DOMAINS - 1; bit >= 0; bit--) {
1118                 if (mask & (1 << bit)) {
1119                         bit_str[str_pos] = 'X';
1120                 } else {
1121                         bit_str[str_pos] = '-';
1122                 }
1123                 str_pos++;
1124         }
1125
1126         bit_str[MALI_MAX_NUMBER_OF_DOMAINS] = '\0';
1127
1128         return bit_str;
1129 }
1130
1131 const char *mali_pm_group_stats_to_string(void)
1132 {
1133         static char bit_str[MALI_MAX_NUMBER_OF_GROUPS + 1];
1134         u32 num_groups = mali_group_get_glob_num_groups();
1135         u32 i;
1136
1137         /* Must be protected by lock since we use shared string buffer */
1138         if (NULL != pm_lock_exec) {
1139                 MALI_DEBUG_ASSERT_LOCK_HELD(pm_lock_exec);
1140         }
1141
1142         for (i = 0; i < num_groups && i < MALI_MAX_NUMBER_OF_GROUPS; i++) {
1143                 struct mali_group *group;
1144
1145                 group = mali_group_get_glob_group(i);
1146
1147                 if (MALI_TRUE == mali_group_power_is_on(group)) {
1148                         bit_str[i] = 'X';
1149                 } else {
1150                         bit_str[i] = '-';
1151                 }
1152         }
1153
1154         bit_str[i] = '\0';
1155
1156         return bit_str;
1157 }
1158 #endif
1159
1160 /*
1161  * num_pp is the number of PP cores which will be powered on given this mask
1162  * cost is the total power cost of cores which will be powered on given this mask
1163  */
1164 static void mali_pm_stat_from_mask(u32 mask, u32 *num_pp, u32 *cost)
1165 {
1166         u32 i;
1167
1168         /* loop through all cores */
1169         for (i = 0; i < MALI_MAX_NUMBER_OF_DOMAINS; i++) {
1170                 if (!(domain_config[i] & mask)) {
1171                         continue;
1172                 }
1173
1174                 switch (i) {
1175                 case MALI_DOMAIN_INDEX_GP:
1176                         *cost += MALI_GP_COST;
1177
1178                         break;
1179                 case MALI_DOMAIN_INDEX_PP0: /* Fall through */
1180                 case MALI_DOMAIN_INDEX_PP1: /* Fall through */
1181                 case MALI_DOMAIN_INDEX_PP2: /* Fall through */
1182                 case MALI_DOMAIN_INDEX_PP3:
1183                         if (mali_is_mali400()) {
1184                                 if ((domain_config[MALI_DOMAIN_INDEX_L20] & mask)
1185                                     || (domain_config[MALI_DOMAIN_INDEX_DUMMY]
1186                                         == domain_config[MALI_DOMAIN_INDEX_L20])) {
1187                                         *num_pp += 1;
1188                                 }
1189                         } else {
1190                                 if ((domain_config[MALI_DOMAIN_INDEX_L21] & mask)
1191                                     || (domain_config[MALI_DOMAIN_INDEX_DUMMY]
1192                                         == domain_config[MALI_DOMAIN_INDEX_L21])) {
1193                                         *num_pp += 1;
1194                                 }
1195                         }
1196
1197                         *cost += MALI_PP_COST;
1198                         break;
1199                 case MALI_DOMAIN_INDEX_PP4: /* Fall through */
1200                 case MALI_DOMAIN_INDEX_PP5: /* Fall through */
1201                 case MALI_DOMAIN_INDEX_PP6: /* Fall through */
1202                 case MALI_DOMAIN_INDEX_PP7:
1203                         MALI_DEBUG_ASSERT(mali_is_mali450());
1204
1205                         if ((domain_config[MALI_DOMAIN_INDEX_L22] & mask)
1206                             || (domain_config[MALI_DOMAIN_INDEX_DUMMY]
1207                                 == domain_config[MALI_DOMAIN_INDEX_L22])) {
1208                                 *num_pp += 1;
1209                         }
1210
1211                         *cost += MALI_PP_COST;
1212                         break;
1213                 case MALI_DOMAIN_INDEX_L20: /* Fall through */
1214                 case MALI_DOMAIN_INDEX_L21: /* Fall through */
1215                 case MALI_DOMAIN_INDEX_L22:
1216                         *cost += MALI_L2_COST;
1217
1218                         break;
1219                 }
1220         }
1221 }
1222
1223 void mali_pm_power_cost_setup(void)
1224 {
1225         /*
1226          * Two parallel arrays which store the best domain mask and its cost
1227          * The index is the number of PP cores, E.g. Index 0 is for 1 PP option,
1228          * might have mask 0x2 and with cost of 1, lower cost is better
1229          */
1230         u32 best_mask[MALI_MAX_NUMBER_OF_PHYSICAL_PP_GROUPS] = { 0 };
1231         u32 best_cost[MALI_MAX_NUMBER_OF_PHYSICAL_PP_GROUPS] = { 0 };
1232         /* Array cores_in_domain is used to store the total pp cores in each pm domain. */
1233         u32 cores_in_domain[MALI_MAX_NUMBER_OF_DOMAINS] = { 0 };
1234         /* Domain_count is used to represent the max domain we have.*/
1235         u32 max_domain_mask = 0;
1236         u32 max_domain_id = 0;
1237         u32 always_on_pp_cores = 0;
1238
1239         u32 num_pp, cost, mask;
1240         u32 i, j , k;
1241
1242         /* Initialize statistics */
1243         for (i = 0; i < MALI_MAX_NUMBER_OF_PHYSICAL_PP_GROUPS; i++) {
1244                 best_mask[i] = 0;
1245                 best_cost[i] = 0xFFFFFFFF; /* lower cost is better */
1246         }
1247
1248         for (i = 0; i < MALI_MAX_NUMBER_OF_PHYSICAL_PP_GROUPS + 1; i++) {
1249                 for (j = 0; j < MALI_MAX_NUMBER_OF_DOMAINS; j++) {
1250                         mali_pm_domain_power_cost_result[i][j] = 0;
1251                 }
1252         }
1253
1254         /* Caculate number of pp cores of a given domain config. */
1255         for (i = MALI_DOMAIN_INDEX_PP0; i <= MALI_DOMAIN_INDEX_PP7; i++) {
1256                 if (0 < domain_config[i]) {
1257                         /* Get the max domain mask value used to caculate power cost
1258                          * and we don't count in always on pp cores. */
1259                         if (MALI_PM_DOMAIN_DUMMY_MASK != domain_config[i]
1260                             && max_domain_mask < domain_config[i]) {
1261                                 max_domain_mask = domain_config[i];
1262                         }
1263
1264                         if (MALI_PM_DOMAIN_DUMMY_MASK == domain_config[i]) {
1265                                 always_on_pp_cores++;
1266                         }
1267                 }
1268         }
1269         max_domain_id = _mali_osk_fls(max_domain_mask);
1270
1271         /*
1272          * Try all combinations of power domains and check how many PP cores
1273          * they have and their power cost.
1274          */
1275         for (mask = 0; mask < (1 << max_domain_id); mask++) {
1276                 num_pp = 0;
1277                 cost = 0;
1278
1279                 mali_pm_stat_from_mask(mask, &num_pp, &cost);
1280
1281                 /* This mask is usable for all MP1 up to num_pp PP cores, check statistics for all */
1282                 for (i = 0; i < num_pp; i++) {
1283                         if (best_cost[i] >= cost) {
1284                                 best_cost[i] = cost;
1285                                 best_mask[i] = mask;
1286                         }
1287                 }
1288         }
1289
1290         /*
1291          * If we want to enable x pp cores, if x is less than number of always_on pp cores,
1292          * all of pp cores we will enable must be always_on pp cores.
1293          */
1294         for (i = 0; i < mali_executor_get_num_cores_total(); i++) {
1295                 if (i < always_on_pp_cores) {
1296                         mali_pm_domain_power_cost_result[i + 1][MALI_MAX_NUMBER_OF_DOMAINS - 1]
1297                                 = i + 1;
1298                 } else {
1299                         mali_pm_domain_power_cost_result[i + 1][MALI_MAX_NUMBER_OF_DOMAINS - 1]
1300                                 = always_on_pp_cores;
1301                 }
1302         }
1303
1304         /* In this loop, variable i represent for the number of non-always on pp cores we want to enabled. */
1305         for (i = 0; i < (mali_executor_get_num_cores_total() - always_on_pp_cores); i++) {
1306                 if (best_mask[i] == 0) {
1307                         /* This MP variant is not available */
1308                         continue;
1309                 }
1310
1311                 for (j = 0; j < MALI_MAX_NUMBER_OF_DOMAINS; j++) {
1312                         cores_in_domain[j] = 0;
1313                 }
1314
1315                 for (j = MALI_DOMAIN_INDEX_PP0; j <= MALI_DOMAIN_INDEX_PP7; j++) {
1316                         if (0 < domain_config[j]
1317                             && (MALI_PM_DOMAIN_DUMMY_MASK != domain_config[i])) {
1318                                 cores_in_domain[_mali_osk_fls(domain_config[j]) - 1]++;
1319                         }
1320                 }
1321
1322                 /* In this loop, j represent for the number we have already enabled.*/
1323                 for (j = 0; j <= i;) {
1324                         /* j used to visit all of domain to get the number of pp cores remained in it. */
1325                         for (k = 0; k < max_domain_id; k++) {
1326                                 /* If domain k in best_mask[i] is enabled and this domain has extra pp cores,
1327                                  * we know we must pick at least one pp core from this domain.
1328                                  * And then we move to next enabled pm domain. */
1329                                 if ((best_mask[i] & (0x1 << k)) && (0 < cores_in_domain[k])) {
1330                                         cores_in_domain[k]--;
1331                                         mali_pm_domain_power_cost_result[always_on_pp_cores + i + 1][k]++;
1332                                         j++;
1333                                         if (j > i) {
1334                                                 break;
1335                                         }
1336                                 }
1337                         }
1338                 }
1339         }
1340 }
1341
1342 /*
1343  * When we are doing core scaling,
1344  * this function is called to return the best mask to
1345  * achieve the best pp group power cost.
1346  */
1347 void mali_pm_get_best_power_cost_mask(int num_requested, int *dst)
1348 {
1349         MALI_DEBUG_ASSERT((mali_executor_get_num_cores_total() >= num_requested) && (0 <= num_requested));
1350
1351         _mali_osk_memcpy(dst, mali_pm_domain_power_cost_result[num_requested], MALI_MAX_NUMBER_OF_DOMAINS * sizeof(int));
1352 }
1353
1354 u32 mali_pm_get_current_mask(void)
1355 {
1356         return pd_mask_current;
1357 }
1358
1359 u32 mali_pm_get_wanted_mask(void)
1360 {
1361         return pd_mask_wanted;
1362 }