2 * Copyright (C) 2010 ARM Limited. All rights reserved.
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.
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.
14 #include "mali_kernel_common.h"
15 #include "mali_kernel_subsystem.h"
18 #include "mali_pmm_state.h"
19 #include "mali_pmm_system.h"
21 #include "mali_kernel_core.h"
22 #include "mali_platform.h"
24 #define SIZEOF_CORES_LIST 6
26 /* NOTE: L2 *MUST* be first on the list so that it
27 * is correctly powered on first and powered off last
29 static mali_pmm_core_id cores_list[] = { MALI_PMM_CORE_L2,
38 void pmm_update_system_state( _mali_pmm_internal_state_t *pmm )
42 MALI_DEBUG_ASSERT_POINTER(pmm);
44 if( pmm->cores_registered == 0 )
46 state = MALI_PMM_STATE_UNAVAILABLE;
48 else if( pmm->cores_powered == 0 )
50 state = MALI_PMM_STATE_SYSTEM_OFF;
52 else if( pmm->cores_powered == pmm->cores_registered )
54 state = MALI_PMM_STATE_SYSTEM_ON;
58 /* Some other state where not everything is on or off */
59 state = MALI_PMM_STATE_SYSTEM_TRANSITION;
63 _mali_pmm_trace_state_change( pmm->state, state );
68 mali_pmm_core_mask pmm_cores_from_event_data( _mali_pmm_internal_state_t *pmm, mali_pmm_message_t *event )
70 mali_pmm_core_mask cores;
71 MALI_DEBUG_ASSERT_POINTER(pmm);
72 MALI_DEBUG_ASSERT_POINTER(event);
76 case MALI_PMM_EVENT_OS_POWER_UP:
77 case MALI_PMM_EVENT_OS_POWER_DOWN:
78 /* All cores - the system */
79 cores = pmm->cores_registered;
82 case MALI_PMM_EVENT_JOB_SCHEDULED:
83 case MALI_PMM_EVENT_JOB_QUEUED:
84 case MALI_PMM_EVENT_JOB_FINISHED:
85 case MALI_PMM_EVENT_INTERNAL_POWER_UP_ACK:
86 case MALI_PMM_EVENT_INTERNAL_POWER_DOWN_ACK:
87 /* Currently the main event data is only the cores
90 cores = (mali_pmm_core_mask)event->data;
91 if( cores == MALI_PMM_CORE_SYSTEM )
93 cores = pmm->cores_registered;
95 else if( cores == MALI_PMM_CORE_PP_ALL )
97 /* Get the subset of registered PP cores */
98 cores = (pmm->cores_registered & MALI_PMM_CORE_PP_ALL);
100 MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, cores );
104 /* Assume timeout messages - report cores still powered */
105 cores = pmm->cores_powered;
112 mali_pmm_core_mask pmm_cores_to_power_up( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores )
114 mali_pmm_core_mask cores_subset;
115 MALI_DEBUG_ASSERT_POINTER(pmm);
116 MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, cores );
118 /* Check that cores aren't pending power down when asked for power up */
119 MALI_DEBUG_ASSERT( pmm->cores_pend_down == 0 );
121 cores_subset = (~(pmm->cores_powered) & cores);
122 if( cores_subset != 0 )
124 /* There are some cores that need powering up */
125 pmm->cores_pend_up = cores_subset;
131 mali_pmm_core_mask pmm_cores_to_power_down( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores, mali_bool immediate_only )
133 mali_pmm_core_mask cores_subset;
134 _mali_osk_errcode_t err;
135 MALI_DEBUG_ASSERT_POINTER(pmm);
136 MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, cores );
138 /* Check that cores aren't pending power up when asked for power down */
139 MALI_DEBUG_ASSERT( pmm->cores_pend_up == 0 );
141 cores_subset = (pmm->cores_powered & cores);
142 if( cores_subset != 0 )
145 volatile mali_pmm_core_mask *ppowered = &(pmm->cores_powered);
147 /* There are some cores that need powering up, but we may
148 * need to wait until they are idle
150 for( n = SIZEOF_CORES_LIST-1; n >= 0; n-- )
152 if( (cores_list[n] & cores_subset) != 0 )
154 /* Core is to be powered down */
155 pmm->cores_pend_down |= cores_list[n];
157 /* Can't hold the power lock, when acessing subsystem mutex via
158 * the core power call.
159 * Due to terminatation of driver requiring a subsystem mutex
160 * and then power lock held to unregister a core.
161 * This does mean that the following function could fail
162 * as the core is unregistered before we tell it to power
163 * down, but it does not matter as we are terminating
165 #if MALI_STATE_TRACKING
166 pmm->mali_pmm_lock_acquired = 0;
167 #endif /* MALI_STATE_TRACKING */
169 MALI_PMM_UNLOCK(pmm);
170 /* Signal the core to power down
171 * If it is busy (not idle) it will set a pending power down flag
172 * (as long as we don't want to only immediately power down).
173 * If it isn't busy it will move out of the idle queue right
176 err = mali_core_signal_power_down( cores_list[n], immediate_only );
179 #if MALI_STATE_TRACKING
180 pmm->mali_pmm_lock_acquired = 1;
181 #endif /* MALI_STATE_TRACKING */
184 /* Re-read cores_subset in case it has changed */
185 cores_subset = (*ppowered & cores);
187 if( err == _MALI_OSK_ERR_OK )
189 /* We moved an idle core to the power down queue
190 * which means it is now acknowledged (if it is still
193 pmm->cores_ack_down |= (cores_list[n] & cores_subset);
197 MALI_DEBUG_PRINT(1,("The error in PMM is ...%x...%x",err,*ppowered));
198 MALI_DEBUG_ASSERT( err == _MALI_OSK_ERR_BUSY ||
199 (err == _MALI_OSK_ERR_FAULT &&
200 (*ppowered & cores_list[n]) == 0) );
201 /* If we didn't move a core - it must be active, so
202 * leave it pending, so we get an acknowledgement (when
203 * not in immediate only mode)
204 * Alternatively we are shutting down and the core has
215 void pmm_power_down_cancel( _mali_pmm_internal_state_t *pmm )
218 mali_pmm_core_mask pd, ad;
219 _mali_osk_errcode_t err;
220 volatile mali_pmm_core_mask *pregistered;
222 MALI_DEBUG_ASSERT_POINTER(pmm);
224 MALIPMM_DEBUG_PRINT( ("PMM: Cancelling power down\n") );
226 pd = pmm->cores_pend_down;
227 ad = pmm->cores_ack_down;
228 /* Clear the pending cores so that they don't move to the off
229 * queue if they haven't already
231 pmm->cores_pend_down = 0;
232 pmm->cores_ack_down = 0;
233 pregistered = &(pmm->cores_registered);
235 /* Power up all the pending power down cores - just so
236 * we make sure the system is in a known state, as a
237 * pending core might have sent an acknowledged message
238 * which hasn't been read yet.
240 for( n = 0; n < SIZEOF_CORES_LIST; n++ )
242 if( (cores_list[n] & pd) != 0 )
244 /* Can't hold the power lock, when acessing subsystem mutex via
245 * the core power call.
246 * Due to terminatation of driver requiring a subsystem mutex
247 * and then power lock held to unregister a core.
248 * This does mean that the following power up function could fail
249 * as the core is unregistered before we tell it to power
250 * up, but it does not matter as we are terminating
252 #if MALI_STATE_TRACKING
253 pmm->mali_pmm_lock_acquired = 0;
254 #endif /* MALI_STATE_TRACKING */
256 MALI_PMM_UNLOCK(pmm);
257 /* As we are cancelling - only move the cores back to the queue -
260 err = mali_core_signal_power_up( cores_list[n], MALI_TRUE );
262 #if MALI_STATE_TRACKING
263 pmm->mali_pmm_lock_acquired = 1;
264 #endif /* MALI_STATE_TRACKING */
266 /* Update pending list with the current registered cores */
267 pd &= (*pregistered);
269 if( err != _MALI_OSK_ERR_OK )
271 MALI_DEBUG_ASSERT( (err == _MALI_OSK_ERR_BUSY &&
272 ((cores_list[n] & ad) == 0)) ||
273 (err == _MALI_OSK_ERR_FAULT &&
274 (*pregistered & cores_list[n]) == 0) );
275 /* If we didn't power up a core - it must be active and
276 * hasn't actually tried to power down - this is expected
277 * for cores that haven't acknowledged
278 * Alternatively we are shutting down and the core has
284 /* Only used in debug builds */
289 mali_bool pmm_power_down_okay( _mali_pmm_internal_state_t *pmm )
291 MALI_DEBUG_ASSERT_POINTER(pmm);
293 return ( pmm->cores_pend_down == pmm->cores_ack_down ? MALI_TRUE : MALI_FALSE );
296 mali_bool pmm_invoke_power_down( _mali_pmm_internal_state_t *pmm, mali_power_mode power_mode )
298 _mali_osk_errcode_t err;
299 MALI_DEBUG_ASSERT_POINTER(pmm);
301 /* Check that cores are pending power down during power down invoke */
302 MALI_DEBUG_ASSERT( pmm->cores_pend_down != 0 );
303 /* Check that cores are not pending power up during power down invoke */
304 MALI_DEBUG_ASSERT( pmm->cores_pend_up == 0 );
306 if( !pmm_power_down_okay( pmm ) )
308 MALIPMM_DEBUG_PRINT( ("PMM: Waiting for cores to go idle for power off - 0x%08x / 0x%08x\n",
309 pmm->cores_pend_down, pmm->cores_ack_down) );
314 pmm->cores_powered &= ~(pmm->cores_pend_down);
316 err = malipmm_powerdown( pmm->cores_pend_down, power_mode);
318 err = _MALI_OSK_ERR_OK;
321 if( err == _MALI_OSK_ERR_OK )
324 mali_pmm_core_mask old_power = pmm->cores_powered;
326 /* Remove powered down cores from idle and powered list */
327 pmm->cores_idle &= ~(pmm->cores_pend_down);
328 /* Reset pending/acknowledged status */
329 pmm->cores_pend_down = 0;
330 pmm->cores_ack_down = 0;
332 _mali_pmm_trace_hardware_change( old_power, pmm->cores_powered );
337 pmm->cores_powered |= pmm->cores_pend_down;
338 MALI_PRINT_ERROR( ("PMM: Failed to get PMU to power down cores - (0x%x) %s",
339 pmm->cores_pend_down, pmm_trace_get_core_name(pmm->cores_pend_down)) );
340 pmm->fatal_power_err = MALI_TRUE;
348 mali_bool pmm_power_up_okay( _mali_pmm_internal_state_t *pmm )
350 MALI_DEBUG_ASSERT_POINTER(pmm);
352 return ( pmm->cores_pend_up == pmm->cores_ack_up ? MALI_TRUE : MALI_FALSE );
356 mali_bool pmm_invoke_power_up( _mali_pmm_internal_state_t *pmm )
358 _mali_osk_errcode_t err;
360 MALI_DEBUG_ASSERT_POINTER(pmm);
362 /* Check that cores are pending power up during power up invoke */
363 MALI_DEBUG_ASSERT( pmm->cores_pend_up != 0 );
364 /* Check that cores are not pending power down during power up invoke */
365 MALI_DEBUG_ASSERT( pmm->cores_pend_down == 0 );
367 if( pmm_power_up_okay( pmm ) )
369 /* Power up has completed - sort out subsystem core status */
372 /* Use volatile to access, so that it is updated if any cores are unregistered */
373 volatile mali_pmm_core_mask *ppendup = &(pmm->cores_pend_up);
375 mali_pmm_core_mask old_power = pmm->cores_powered;
377 /* Move cores into idle queues */
378 for( n = 0; n < SIZEOF_CORES_LIST; n++ )
380 if( (cores_list[n] & (*ppendup)) != 0 )
382 /* Can't hold the power lock, when acessing subsystem mutex via
383 * the core power call.
384 * Due to terminatation of driver requiring a subsystem mutex
385 * and then power lock held to unregister a core.
386 * This does mean that the following function could fail
387 * as the core is unregistered before we tell it to power
388 * up, but it does not matter as we are terminating
390 #if MALI_STATE_TRACKING
391 pmm->mali_pmm_lock_acquired = 0;
392 #endif /* MALI_STATE_TRACKING */
394 MALI_PMM_UNLOCK(pmm);
395 err = mali_core_signal_power_up( cores_list[n], MALI_FALSE );
398 #if MALI_STATE_TRACKING
399 pmm->mali_pmm_lock_acquired = 1;
400 #endif /* MALI_STATE_TRACKING */
403 if( err != _MALI_OSK_ERR_OK )
405 MALI_DEBUG_ASSERT( (err == _MALI_OSK_ERR_FAULT &&
406 (*ppendup & cores_list[n]) == 0) );
407 /* We only expect this to fail when we are shutting down
408 * and the core has been unregistered
413 /* Finished power up - add cores to idle and powered list */
414 pmm->cores_powered |= (*ppendup);
415 pmm->cores_idle |= (*ppendup);
416 /* Reset pending/acknowledge status */
417 pmm->cores_pend_up = 0;
418 pmm->cores_ack_up = 0;
421 _mali_pmm_trace_hardware_change( old_power, pmm->cores_powered );
428 /* Power up must now be done */
429 err = malipmm_powerup( pmm->cores_pend_up );
431 err = _MALI_OSK_ERR_OK;
433 if( err != _MALI_OSK_ERR_OK )
435 MALI_PRINT_ERROR( ("PMM: Failed to get PMU to power up cores - (0x%x) %s",
436 pmm->cores_pend_up, pmm_trace_get_core_name(pmm->cores_pend_up)) );
437 pmm->fatal_power_err = MALI_TRUE;
441 /* TBD - Update core status immediately rather than use event message */
442 _mali_uk_pmm_message_s event = {
444 MALI_PMM_EVENT_INTERNAL_POWER_UP_ACK,
446 /* All the cores that were pending power up, have now completed power up */
447 event.data = pmm->cores_pend_up;
448 _mali_ukk_pmm_event_message( &event );
449 MALIPMM_DEBUG_PRINT( ("PMM: Sending ACK to power up") );
453 /* Always return false, as we need an interrupt to acknowledge
454 * when power up is complete
459 mali_pmm_core_mask pmm_cores_set_active( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores )
461 MALI_DEBUG_ASSERT_POINTER(pmm);
462 MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, cores );
464 pmm->cores_idle &= (~cores);
465 return pmm->cores_idle;
468 mali_pmm_core_mask pmm_cores_set_idle( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores )
470 MALI_DEBUG_ASSERT_POINTER(pmm);
471 MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, cores );
473 pmm->cores_idle |= (cores);
474 return pmm->cores_idle;
477 mali_pmm_core_mask pmm_cores_set_down_ack( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores )
479 MALI_DEBUG_ASSERT_POINTER(pmm);
480 MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, cores );
482 /* Check core is not pending a power down */
483 MALI_DEBUG_ASSERT( (pmm->cores_pend_down & cores) != 0 );
484 /* Check core has not acknowledged power down more than once */
485 MALI_DEBUG_ASSERT( (pmm->cores_ack_down & cores) == 0 );
487 pmm->cores_ack_down |= (cores);
489 return pmm->cores_ack_down;
492 void pmm_fatal_reset( _mali_pmm_internal_state_t *pmm )
494 _mali_osk_errcode_t err = _MALI_OSK_ERR_OK;
495 _mali_osk_notification_t *msg = NULL;
496 mali_pmm_status status;
497 MALI_DEBUG_ASSERT_POINTER(pmm);
498 MALIPMM_DEBUG_PRINT( ("PMM: Fatal Reset called") );
500 MALI_DEBUG_ASSERT( pmm->status != MALI_PMM_STATUS_OFF );
502 /* Reset the common status */
505 pmm->fatal_power_err = MALI_FALSE;
507 pmm->check_policy = MALI_FALSE;
508 pmm->cores_pend_down = 0;
509 pmm->cores_pend_up = 0;
510 pmm->cores_ack_down = 0;
511 pmm->cores_ack_up = 0;
512 pmm->is_dvfs_active = 0;
514 pmm->messages_sent = 0;
515 pmm->messages_received = 0;
516 pmm->imessages_sent = 0;
517 pmm->imessages_received = 0;
518 MALI_PRINT( ("PMM Trace: *** Fatal reset occurred ***") );
521 /* Set that we are unavailable whilst resetting */
522 pmm->state = MALI_PMM_STATE_UNAVAILABLE;
523 status = pmm->status;
524 pmm->status = MALI_PMM_STATUS_OFF;
526 /* We want all cores powered */
527 pmm->cores_powered = pmm->cores_registered;
528 /* The cores may not be idle, but this state will be rectified later */
529 pmm->cores_idle = pmm->cores_registered;
531 /* So power on any cores that are registered */
532 if( pmm->cores_registered != 0 )
535 volatile mali_pmm_core_mask *pregistered = &(pmm->cores_registered);
537 err = malipmm_powerup( pmm->cores_registered );
539 if( err != _MALI_OSK_ERR_OK )
541 /* This is very bad as we can't even be certain the cores are now
544 MALI_PRINT_ERROR( ("PMM: Failed to perform PMM reset!\n") );
545 /* TBD driver exit? */
548 for( n = SIZEOF_CORES_LIST-1; n >= 0; n-- )
550 if( (cores_list[n] & (*pregistered)) != 0 )
552 #if MALI_STATE_TRACKING
553 pmm->mali_pmm_lock_acquired = 0;
554 #endif /* MALI_STATE_TRACKING */
556 MALI_PMM_UNLOCK(pmm);
557 /* Core is now active - so try putting it in the idle queue */
558 err = mali_core_signal_power_up( cores_list[n], MALI_FALSE );
560 #if MALI_STATE_TRACKING
561 pmm->mali_pmm_lock_acquired = 1;
562 #endif /* MALI_STATE_TRACKING */
564 /* We either succeeded, or we were not off anyway, or we have
565 * just be deregistered
567 MALI_DEBUG_ASSERT( (err == _MALI_OSK_ERR_OK) ||
568 (err == _MALI_OSK_ERR_BUSY) ||
569 (err == _MALI_OSK_ERR_FAULT &&
570 (*pregistered & cores_list[n]) == 0) );
575 /* Unblock any pending OS event */
576 if( status == MALI_PMM_STATUS_OS_POWER_UP )
578 /* Get the OS data and respond to the power up */
579 _mali_osk_pmm_power_up_done( pmm_retrieve_os_event_data( pmm ) );
581 if( status == MALI_PMM_STATUS_OS_POWER_DOWN )
583 /* Get the OS data and respond to the power down
584 * NOTE: We are not powered down at this point due to power problems,
585 * so we are lying to the system, but something bad has already
586 * happened and we are trying unstick things
587 * TBD - Add busy loop to power down cores?
589 _mali_osk_pmm_power_down_done( pmm_retrieve_os_event_data( pmm ) );
592 /* Purge the event queues */
595 if( _mali_osk_notification_queue_dequeue( pmm->iqueue, &msg ) == _MALI_OSK_ERR_OK )
597 _mali_osk_notification_delete ( msg );
604 if( _mali_osk_notification_queue_dequeue( pmm->queue, &msg ) == _MALI_OSK_ERR_OK )
606 _mali_osk_notification_delete ( msg );
611 /* Return status/state to normal */
612 pmm->status = MALI_PMM_STATUS_IDLE;
613 pmm_update_system_state(pmm);
616 mali_pmm_core_mask pmm_cores_set_up_ack( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores )
618 MALI_DEBUG_ASSERT_POINTER(pmm);
619 MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, cores );
621 /* Check core is not pending a power up */
622 MALI_DEBUG_ASSERT( (pmm->cores_pend_up & cores) != 0 );
623 /* Check core has not acknowledged power up more than once */
624 MALI_DEBUG_ASSERT( (pmm->cores_ack_up & cores) == 0 );
626 pmm->cores_ack_up |= (cores);
628 return pmm->cores_ack_up;
631 void pmm_save_os_event_data(_mali_pmm_internal_state_t *pmm, mali_pmm_message_data data)
633 MALI_DEBUG_ASSERT_POINTER(pmm);
634 /* Check that there is no saved data */
635 MALI_DEBUG_ASSERT( pmm->os_data == 0 );
636 /* Can't store zero data - as retrieve check will fail */
637 MALI_DEBUG_ASSERT( data != 0 );
642 mali_pmm_message_data pmm_retrieve_os_event_data(_mali_pmm_internal_state_t *pmm)
644 mali_pmm_message_data data;
646 MALI_DEBUG_ASSERT_POINTER(pmm);
647 /* Check that there is saved data */
648 MALI_DEBUG_ASSERT( pmm->os_data != 0 );
650 /* Get data, and clear the saved version */
657 /* Create list of core names to look up
658 * We are doing it this way to overcome the need for
659 * either string allocation, or stack space, so we
660 * use constant strings instead
662 typedef struct pmm_trace_corelist
664 mali_pmm_core_mask id;
666 } pmm_trace_corelist_t;
668 static pmm_trace_corelist_t pmm_trace_cores[] = {
669 { MALI_PMM_CORE_SYSTEM, "SYSTEM" },
670 { MALI_PMM_CORE_GP, "GP" },
671 { MALI_PMM_CORE_L2, "L2" },
672 { MALI_PMM_CORE_PP0, "PP0" },
673 { MALI_PMM_CORE_PP1, "PP1" },
674 { MALI_PMM_CORE_PP2, "PP2" },
675 { MALI_PMM_CORE_PP3, "PP3" },
676 { MALI_PMM_CORE_PP_ALL, "PP (all)" },
677 { (MALI_PMM_CORE_GP | MALI_PMM_CORE_L2 | MALI_PMM_CORE_PP0),
679 { (MALI_PMM_CORE_GP | MALI_PMM_CORE_PP0),
681 { (MALI_PMM_CORE_GP | MALI_PMM_CORE_L2 | MALI_PMM_CORE_PP0 | MALI_PMM_CORE_PP1),
683 { (MALI_PMM_CORE_GP | MALI_PMM_CORE_PP0 | MALI_PMM_CORE_PP1),
685 { 0, NULL } /* Terminator of list */
688 const char *pmm_trace_get_core_name( mali_pmm_core_mask cores )
690 const char *dname = NULL;
693 /* Look up name in corelist */
695 while( pmm_trace_cores[cl].name != NULL )
697 if( pmm_trace_cores[cl].id == cores )
699 dname = pmm_trace_cores[cl].name;
707 /* We don't know a good short-hand for the configuration */
708 dname = "[multi-core]";
714 #endif /* USING_MALI_PMM */