summaryrefslogtreecommitdiff
path: root/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm')
-rw-r--r--drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm.c921
-rw-r--r--drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm.h323
-rw-r--r--drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm_policy.c243
-rw-r--r--drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm_policy.h155
-rw-r--r--drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm_policy_alwayson.c81
-rw-r--r--drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm_policy_alwayson.h62
-rw-r--r--drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm_policy_jobcontrol.c461
-rw-r--r--drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm_policy_jobcontrol.h80
-rw-r--r--drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm_state.c718
-rw-r--r--drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm_state.h296
-rw-r--r--drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm_system.h66
11 files changed, 3406 insertions, 0 deletions
diff --git a/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm.c b/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm.c
new file mode 100644
index 00000000000..eeb29589ddc
--- /dev/null
+++ b/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm.c
@@ -0,0 +1,921 @@
+/*
+ * Copyright (C) 2010-2011 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * @file mali_pmm.c
+ * Implementation of the power management module for the kernel device driver
+ */
+
+#if USING_MALI_PMM
+
+#include "mali_ukk.h"
+#include "mali_kernel_common.h"
+#include "mali_kernel_subsystem.h"
+
+#include "mali_pmm.h"
+#include "mali_pmm_system.h"
+#include "mali_pmm_state.h"
+#include "mali_pmm_policy.h"
+#include "mali_platform.h"
+
+/* Internal PMM subsystem state */
+static _mali_pmm_internal_state_t *pmm_state = NULL;
+/* Mali kernel subsystem id */
+static mali_kernel_subsystem_identifier mali_subsystem_pmm_id = -1;
+
+#define GET_PMM_STATE_PTR (pmm_state)
+
+/* Internal functions */
+static _mali_osk_errcode_t malipmm_create(_mali_osk_resource_t *resource);
+static void pmm_event_process( void );
+_mali_osk_errcode_t malipmm_irq_uhandler(void *data);
+void malipmm_irq_bhandler(void *data);
+
+/** @brief Start the PMM subsystem
+ *
+ * @param id Subsystem id to uniquely identify this subsystem
+ * @return _MALI_OSK_ERR_OK if the system started successfully, or a suitable
+ * _mali_osk_errcode_t otherwise.
+ */
+_mali_osk_errcode_t malipmm_kernel_subsystem_start( mali_kernel_subsystem_identifier id );
+
+/** @brief Perform post start up of the PMM subsystem
+ *
+ * Post start up includes initializing the current policy, now that the system is
+ * completely started - to stop policies turning off hardware during the start up
+ *
+ * @param id the unique subsystem id
+ * @return _MALI_OSK_ERR_OK if the post startup was successful, or a suitable
+ * _mali_osk_errcode_t otherwise.
+ */
+_mali_osk_errcode_t malipmm_kernel_load_complete( mali_kernel_subsystem_identifier id );
+
+/** @brief Terminate the PMM subsystem
+ *
+ * @param id the unique subsystem id
+ */
+void malipmm_kernel_subsystem_terminate( mali_kernel_subsystem_identifier id );
+
+#if MALI_STATE_TRACKING
+ void malipmm_subsystem_dump_state( void );
+#endif
+
+
+/* This will be one of the subsystems in the array of subsystems:
+ static struct mali_kernel_subsystem * subsystems[];
+ found in file: mali_kernel_core.c
+*/
+struct mali_kernel_subsystem mali_subsystem_pmm=
+{
+ malipmm_kernel_subsystem_start, /* startup */
+ malipmm_kernel_subsystem_terminate, /* shutdown */
+ malipmm_kernel_load_complete, /* loaded all subsystems */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+#if MALI_STATE_TRACKING
+ malipmm_subsystem_dump_state, /* dump_state */
+#endif
+};
+
+#if PMM_OS_TEST
+
+u32 power_test_event = 0;
+mali_bool power_test_flag = MALI_FALSE;
+_mali_osk_timer_t *power_test_timer = NULL;
+
+void _mali_osk_pmm_power_up_done(mali_pmm_message_data data)
+{
+ MALI_PRINT(("POWER TEST OS UP DONE\n"));
+}
+
+void _mali_osk_pmm_power_down_done(mali_pmm_message_data data)
+{
+ MALI_PRINT(("POWER TEST OS DOWN DONE\n"));
+}
+
+/**
+ * Symbian OS Power Up call to the driver
+ */
+void power_test_callback( void *arg )
+{
+ _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR;
+ MALI_DEBUG_ASSERT_POINTER(pmm);
+
+ power_test_flag = MALI_TRUE;
+ _mali_osk_irq_schedulework( pmm->irq );
+}
+
+void power_test_start()
+{
+ power_test_timer = _mali_osk_timer_init();
+ _mali_osk_timer_setcallback( power_test_timer, power_test_callback, NULL );
+
+ /* First event is power down */
+ power_test_event = MALI_PMM_EVENT_OS_POWER_DOWN;
+ _mali_osk_timer_add( power_test_timer, 10000 );
+}
+
+mali_bool power_test_check()
+{
+ if( power_test_flag )
+ {
+ _mali_uk_pmm_message_s event = {
+ NULL,
+ 0,
+ 1 };
+ event.id = power_test_event;
+
+ power_test_flag = MALI_FALSE;
+
+ /* Send event */
+ _mali_ukk_pmm_event_message( &event );
+
+ /* Switch to next event to test */
+ if( power_test_event == MALI_PMM_EVENT_OS_POWER_DOWN )
+ {
+ power_test_event = MALI_PMM_EVENT_OS_POWER_UP;
+ }
+ else
+ {
+ power_test_event = MALI_PMM_EVENT_OS_POWER_DOWN;
+ }
+ _mali_osk_timer_add( power_test_timer, 5000 );
+
+ return MALI_TRUE;
+ }
+
+ return MALI_FALSE;
+}
+
+void power_test_end()
+{
+ _mali_osk_timer_del( power_test_timer );
+ _mali_osk_timer_term( power_test_timer );
+ power_test_timer = NULL;
+}
+
+#endif
+
+void _mali_ukk_pmm_event_message( _mali_uk_pmm_message_s *args )
+{
+ _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR;
+ _mali_osk_notification_t *msg;
+ mali_pmm_message_t *event;
+ MALI_DEBUG_ASSERT_POINTER(pmm);
+ MALI_DEBUG_ASSERT_POINTER(args);
+
+ MALIPMM_DEBUG_PRINT( ("PMM: sending message\n") );
+
+#if MALI_PMM_TRACE && MALI_PMM_TRACE_SENT_EVENTS
+ _mali_pmm_trace_event_message( args, MALI_FALSE );
+#endif
+
+ msg = _mali_osk_notification_create( MALI_PMM_NOTIFICATION_TYPE, sizeof( mali_pmm_message_t ) );
+
+ if( msg )
+ {
+ event = (mali_pmm_message_t *)msg->result_buffer;
+ event->id = args->id;
+ event->ts = _mali_osk_time_tickcount();
+ event->data = args->data;
+
+ _mali_osk_atomic_inc( &(pmm->messages_queued) );
+
+ if( args->id > MALI_PMM_EVENT_INTERNALS )
+ {
+ /* Internal PMM message */
+ _mali_osk_notification_queue_send( pmm->iqueue, msg );
+ #if (MALI_PMM_TRACE || MALI_STATE_TRACKING)
+ pmm->imessages_sent++;
+ #endif
+ }
+ else
+ {
+ /* Real event */
+ _mali_osk_notification_queue_send( pmm->queue, msg );
+ #if (MALI_PMM_TRACE || MALI_STATE_TRACKING)
+ pmm->messages_sent++;
+ #endif
+ }
+ }
+ else
+ {
+ MALI_PRINT_ERROR( ("PMM: Could not send message %d", args->id) );
+ /* Make note of this OOM - which has caused a missed event */
+ pmm->missed++;
+ }
+
+ /* Schedule time to look at the event or the fact we couldn't create an event */
+ _mali_osk_irq_schedulework( pmm->irq );
+}
+
+mali_pmm_state _mali_pmm_state( void )
+{
+ _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR;
+ MALI_DEBUG_ASSERT_POINTER(pmm);
+
+ if( pmm && (mali_subsystem_pmm_id != -1) )
+ {
+ return pmm->state;
+ }
+
+ /* No working subsystem yet */
+ return MALI_PMM_STATE_UNAVAILABLE;
+}
+
+
+mali_pmm_core_mask _mali_pmm_cores_list( void )
+{
+ _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR;
+ MALI_DEBUG_ASSERT_POINTER(pmm);
+
+ return pmm->cores_registered;
+}
+
+mali_pmm_core_mask _mali_pmm_cores_powered( void )
+{
+ _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR;
+ MALI_DEBUG_ASSERT_POINTER(pmm);
+
+ return pmm->cores_powered;
+}
+
+
+_mali_osk_errcode_t _mali_pmm_list_policies(
+ u32 policy_list_size,
+ mali_pmm_policy *policy_list,
+ u32 *policies_available )
+{
+ /* TBD - This is currently a stub function for basic power management */
+
+ MALI_ERROR( _MALI_OSK_ERR_UNSUPPORTED );
+}
+
+_mali_osk_errcode_t _mali_pmm_set_policy( mali_pmm_policy policy )
+{
+ /* TBD - This is currently a stub function for basic power management */
+
+/* TBD - When this is not a stub... include tracing...
+#if MALI_PMM_TRACE
+ _mali_pmm_trace_policy_change( old, newpolicy );
+#endif
+*/
+ MALI_ERROR( _MALI_OSK_ERR_UNSUPPORTED );
+}
+
+_mali_osk_errcode_t _mali_pmm_get_policy( mali_pmm_policy *policy )
+{
+ if( policy )
+ {
+ _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR;
+ MALI_DEBUG_ASSERT_POINTER(pmm);
+
+ if( pmm )
+ {
+ *policy = pmm->policy;
+ MALI_SUCCESS;
+ }
+ else
+ {
+ *policy = MALI_PMM_POLICY_NONE;
+ MALI_ERROR( _MALI_OSK_ERR_FAULT );
+ }
+ }
+
+ /* No return argument */
+ MALI_ERROR( _MALI_OSK_ERR_INVALID_ARGS );
+}
+
+#if MALI_PMM_TRACE
+
+/* Event names - order must match mali_pmm_event_id enum */
+static char *pmm_trace_events[] = {
+ "OS_POWER_UP",
+ "OS_POWER_DOWN",
+ "JOB_SCHEDULED",
+ "JOB_QUEUED",
+ "JOB_FINISHED",
+ "TIMEOUT",
+};
+
+/* UK event names - order must match mali_pmm_event_id enum */
+static char *pmm_trace_events_uk[] = {
+ "UKS",
+ "UK_EXAMPLE",
+};
+
+/* Internal event names - order must match mali_pmm_event_id enum */
+static char *pmm_trace_events_internal[] = {
+ "INTERNALS",
+ "INTERNAL_POWER_UP_ACK",
+ "INTERNAL_POWER_DOWN_ACK",
+};
+
+/* State names - order must match mali_pmm_state enum */
+static char *pmm_trace_state[] = {
+ "UNAVAILABLE",
+ "SYSTEM ON",
+ "SYSTEM OFF",
+ "SYSTEM TRANSITION",
+};
+
+/* Policy names - order must match mali_pmm_policy enum */
+static char *pmm_trace_policy[] = {
+ "NONE",
+ "ALWAYS ON",
+ "JOB CONTROL",
+};
+
+void _mali_pmm_trace_hardware_change( mali_pmm_core_mask old, mali_pmm_core_mask newstate )
+{
+ const char *dname;
+ const char *cname;
+ const char *ename;
+
+ if( old != newstate )
+ {
+ if( newstate == 0 )
+ {
+ dname = "NO cores";
+ }
+ else
+ {
+ dname = pmm_trace_get_core_name( newstate );
+ }
+
+ /* These state checks only work if the assumption that only cores can be
+ * turned on or turned off in seperate actions is true. If core power states can
+ * be toggled (some one, some off) at the same time, this check does not work
+ */
+ if( old > newstate )
+ {
+ /* Cores have turned off */
+ cname = pmm_trace_get_core_name( old - newstate );
+ ename = "OFF";
+ }
+ else
+ {
+ /* Cores have turned on */
+ cname = pmm_trace_get_core_name( newstate - old );
+ ename = "ON";
+ }
+ MALI_PRINT( ("PMM Trace: Hardware %s ON, %s just turned %s. { 0x%08x -> 0x%08x }", dname, cname, ename, old, newstate) );
+ }
+}
+
+void _mali_pmm_trace_state_change( mali_pmm_state old, mali_pmm_state newstate )
+{
+ if( old != newstate )
+ {
+ MALI_PRINT( ("PMM Trace: State changed from %s to %s", pmm_trace_state[old], pmm_trace_state[newstate]) );
+ }
+}
+
+void _mali_pmm_trace_policy_change( mali_pmm_policy old, mali_pmm_policy newpolicy )
+{
+ if( old != newpolicy )
+ {
+ MALI_PRINT( ("PMM Trace: Policy changed from %s to %s", pmm_trace_policy[old], pmm_trace_policy[newpolicy]) );
+ }
+}
+
+void _mali_pmm_trace_event_message( mali_pmm_message_t *event, mali_bool received )
+{
+ const char *ename;
+ const char *dname;
+ const char *tname;
+ const char *format = "PMM Trace: Event %s { (%d) %s, %d ticks, (0x%x) %s }";
+
+ MALI_DEBUG_ASSERT_POINTER(event);
+
+ tname = (received) ? "received" : "sent";
+
+ if( event->id >= MALI_PMM_EVENT_INTERNALS )
+ {
+ ename = pmm_trace_events_internal[((int)event->id) - MALI_PMM_EVENT_INTERNALS];
+ }
+ else if( event->id >= MALI_PMM_EVENT_UKS )
+ {
+ ename = pmm_trace_events_uk[((int)event->id) - MALI_PMM_EVENT_UKS];
+ }
+ else
+ {
+ ename = pmm_trace_events[event->id];
+ }
+
+ switch( event->id )
+ {
+ case MALI_PMM_EVENT_OS_POWER_UP:
+ case MALI_PMM_EVENT_OS_POWER_DOWN:
+ dname = "os event";
+ break;
+
+ case MALI_PMM_EVENT_JOB_SCHEDULED:
+ case MALI_PMM_EVENT_JOB_QUEUED:
+ case MALI_PMM_EVENT_JOB_FINISHED:
+ case MALI_PMM_EVENT_INTERNAL_POWER_UP_ACK:
+ case MALI_PMM_EVENT_INTERNAL_POWER_DOWN_ACK:
+ dname = pmm_trace_get_core_name( (mali_pmm_core_mask)event->data );
+ break;
+
+ case MALI_PMM_EVENT_TIMEOUT:
+ dname = "timeout start";
+ /* Print data with a different format */
+ format = "PMM Trace: Event %s { (%d) %s, %d ticks, %d ticks %s }";
+ break;
+ default:
+ dname = "unknown data";
+ }
+
+ MALI_PRINT( (format, tname, (u32)event->id, ename, event->ts, (u32)event->data, dname) );
+}
+
+#endif /* MALI_PMM_TRACE */
+
+
+/****************** Mali Kernel API *****************/
+
+_mali_osk_errcode_t malipmm_kernel_subsystem_start( mali_kernel_subsystem_identifier id )
+{
+ mali_subsystem_pmm_id = id;
+ MALI_CHECK_NO_ERROR(_mali_kernel_core_register_resource_handler(PMU, malipmm_create));
+ MALI_SUCCESS;
+}
+
+_mali_osk_errcode_t malipmm_create(_mali_osk_resource_t *resource)
+{
+ /* Create PMM state memory */
+ MALI_DEBUG_ASSERT( pmm_state == NULL );
+ pmm_state = (_mali_pmm_internal_state_t *) _mali_osk_malloc(sizeof(*pmm_state));
+ MALI_CHECK_NON_NULL( pmm_state, _MALI_OSK_ERR_NOMEM );
+
+ /* All values get 0 as default */
+ _mali_osk_memset(pmm_state, 0, sizeof(*pmm_state));
+
+ /* Set up the initial PMM state */
+ pmm_state->waiting = 0;
+ pmm_state->status = MALI_PMM_STATUS_IDLE;
+ pmm_state->state = MALI_PMM_STATE_UNAVAILABLE; /* Until a core registers */
+
+ /* Set up policy via compile time option for the moment */
+#if MALI_PMM_ALWAYS_ON
+ pmm_state->policy = MALI_PMM_POLICY_ALWAYS_ON;
+#else
+ pmm_state->policy = MALI_PMM_POLICY_JOB_CONTROL;
+#endif
+
+#if MALI_PMM_TRACE
+ _mali_pmm_trace_policy_change( MALI_PMM_POLICY_NONE, pmm_state->policy );
+#endif
+
+ /* Set up assumes all values are initialized to NULL or MALI_FALSE, so
+ * we can exit halfway through set up and perform clean up
+ */
+#if !MALI_PMM_NO_PMU
+ if( mali_platform_init(resource) != _MALI_OSK_ERR_OK ) goto pmm_fail_cleanup;
+ pmm_state->pmu_initialized = MALI_TRUE;
+#endif
+
+ pmm_state->queue = _mali_osk_notification_queue_init();
+ if( !pmm_state->queue ) goto pmm_fail_cleanup;
+
+ pmm_state->iqueue = _mali_osk_notification_queue_init();
+ if( !pmm_state->iqueue ) goto pmm_fail_cleanup;
+
+ /* We are creating an IRQ handler just for the worker thread it gives us */
+ pmm_state->irq = _mali_osk_irq_init( _MALI_OSK_IRQ_NUMBER_PMM,
+ malipmm_irq_uhandler,
+ malipmm_irq_bhandler,
+ NULL,
+ NULL,
+ (void *)pmm_state, /* PMM state is passed to IRQ */
+ "PMM handler" );
+
+ if( !pmm_state->irq ) goto pmm_fail_cleanup;
+
+ pmm_state->lock = _mali_osk_lock_init((_mali_osk_lock_flags_t)(_MALI_OSK_LOCKFLAG_READERWRITER | _MALI_OSK_LOCKFLAG_ORDERED), 0, 75);
+ if( !pmm_state->lock ) goto pmm_fail_cleanup;
+
+ if( _mali_osk_atomic_init( &(pmm_state->messages_queued), 0 ) != _MALI_OSK_ERR_OK )
+ {
+ goto pmm_fail_cleanup;
+ }
+
+ MALIPMM_DEBUG_PRINT( ("PMM: subsystem created, policy=%d\n", pmm_state->policy) );
+
+ MALI_SUCCESS;
+
+pmm_fail_cleanup:
+ MALI_PRINT_ERROR( ("PMM: subsystem failed to be created\n") );
+ if( pmm_state )
+ {
+ _mali_osk_resource_type_t t = PMU;
+ if( pmm_state->lock ) _mali_osk_lock_term( pmm_state->lock );
+ if( pmm_state->irq ) _mali_osk_irq_term( pmm_state->irq );
+ if( pmm_state->queue ) _mali_osk_notification_queue_term( pmm_state->queue );
+ if( pmm_state->iqueue ) _mali_osk_notification_queue_term( pmm_state->iqueue );
+ if( pmm_state->pmu_initialized ) ( mali_platform_deinit(&t) );
+ _mali_osk_free(pmm_state);
+ pmm_state = NULL;
+ }
+ MALI_ERROR( _MALI_OSK_ERR_FAULT );
+}
+
+_mali_osk_errcode_t malipmm_kernel_load_complete( mali_kernel_subsystem_identifier id )
+{
+ _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR;
+ MALI_DEBUG_ASSERT_POINTER(pmm);
+
+ MALIPMM_DEBUG_PRINT( ("PMM: subsystem loaded, policy initializing\n") );
+
+#if PMM_OS_TEST
+ power_test_start();
+#endif
+
+ /* Initialize the profile now the system has loaded - so that cores are
+ * not turned off during start up
+ */
+ return pmm_policy_init( pmm );
+}
+
+void malipmm_kernel_subsystem_terminate( mali_kernel_subsystem_identifier id )
+{
+ /* Check this is the right system */
+ MALI_DEBUG_ASSERT( id == mali_subsystem_pmm_id );
+ MALI_DEBUG_ASSERT_POINTER(pmm_state);
+
+ if( pmm_state )
+ {
+ _mali_osk_resource_type_t t = PMU;
+#if PMM_OS_TEST
+ power_test_end();
+#endif
+ /* Get the lock so we can shutdown */
+ MALI_PMM_LOCK(pmm_state);
+#if MALI_STATE_TRACKING
+ pmm_state->mali_pmm_lock_acquired = 1;
+#endif /* MALI_STATE_TRACKING */
+ pmm_state->status = MALI_PMM_STATUS_OFF;
+#if MALI_STATE_TRACKING
+ pmm_state->mali_pmm_lock_acquired = 0;
+#endif /* MALI_STATE_TRACKING */
+ MALI_PMM_UNLOCK(pmm_state);
+ pmm_policy_term(pmm_state);
+ _mali_osk_irq_term( pmm_state->irq );
+ _mali_osk_notification_queue_term( pmm_state->queue );
+ _mali_osk_notification_queue_term( pmm_state->iqueue );
+ if( pmm_state->pmu_initialized ) mali_platform_deinit(&t);
+ _mali_osk_atomic_term( &(pmm_state->messages_queued) );
+ MALI_PMM_LOCK_TERM(pmm_state);
+ _mali_osk_free(pmm_state);
+ pmm_state = NULL;
+ }
+
+ MALIPMM_DEBUG_PRINT( ("PMM: subsystem terminated\n") );
+}
+
+_mali_osk_errcode_t malipmm_core_register( mali_pmm_core_id core )
+{
+ _mali_osk_errcode_t err;
+ _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR;
+
+ if( pmm == NULL )
+ {
+ /* PMM state has not been created, this is because the PMU resource has not been
+ * created yet.
+ * This probably means that the PMU resource has not been specfied as the first
+ * resource in the config file
+ */
+ MALI_PRINT_ERROR( ("PMM: Cannot register core %s because the PMU resource has not been\n initialized. Please make sure the PMU resource is the first resource in the\n resource configuration.\n",
+ pmm_trace_get_core_name(core)) );
+ MALI_ERROR(_MALI_OSK_ERR_FAULT);
+ }
+
+ MALI_PMM_LOCK(pmm);
+
+#if MALI_STATE_TRACKING
+ pmm->mali_pmm_lock_acquired = 1;
+#endif /* MALI_STATE_TRACKING */
+
+
+ /* Check if the core is registered more than once in PMM */
+ MALI_DEBUG_ASSERT( (pmm->cores_registered & core) == 0 );
+
+ MALIPMM_DEBUG_PRINT( ("PMM: core registered: (0x%x) %s\n", core, pmm_trace_get_core_name(core)) );
+
+#if !MALI_PMM_NO_PMU
+ /* Make sure the core is powered up */
+ err = mali_platform_powerup( core );
+#else
+ err = _MALI_OSK_ERR_OK;
+#endif
+ if( _MALI_OSK_ERR_OK == err )
+ {
+#if MALI_PMM_TRACE
+ mali_pmm_core_mask old_power = pmm->cores_powered;
+#endif
+ /* Assume a registered core is now powered up and idle */
+ pmm->cores_registered |= core;
+ pmm->cores_idle |= core;
+ pmm->cores_powered |= core;
+ pmm_update_system_state( pmm );
+
+#if MALI_PMM_TRACE
+ _mali_pmm_trace_hardware_change( old_power, pmm->cores_powered );
+#endif
+ }
+ else
+ {
+ MALI_PRINT_ERROR( ("PMM: Error(%d) powering up registered core: (0x%x) %s\n",
+ err, core, pmm_trace_get_core_name(core)) );
+ }
+
+#if MALI_STATE_TRACKING
+ pmm->mali_pmm_lock_acquired = 0;
+#endif /* MALI_STATE_TRACKING */
+
+ MALI_PMM_UNLOCK(pmm);
+
+ return err;
+}
+
+void malipmm_core_unregister( mali_pmm_core_id core )
+{
+ _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR;
+ MALI_DEBUG_ASSERT_POINTER(pmm);
+
+ MALI_PMM_LOCK(pmm);
+#if MALI_STATE_TRACKING
+ pmm->mali_pmm_lock_acquired = 1;
+#endif /* MALI_STATE_TRACKING */
+
+
+ /* Check if the core is registered in PMM */
+ MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, core );
+
+ MALIPMM_DEBUG_PRINT( ("PMM: core unregistered: (0x%x) %s\n", core, pmm_trace_get_core_name(core)) );
+
+ {
+#if MALI_PMM_TRACE
+ mali_pmm_core_mask old_power = pmm->cores_powered;
+#endif
+
+#if !MALI_PMM_NO_PMU
+ /* Turn off the core */
+ if( mali_platform_powerdown( core ) != _MALI_OSK_ERR_OK )
+ {
+ MALI_PRINT_ERROR( ("PMM: Error powering down unregistered core: (0x%x) %s\n",
+ core, pmm_trace_get_core_name(core)) );
+ }
+#endif
+
+ /* Remove the core from the system */
+ pmm->cores_registered &= (~core);
+ pmm->cores_idle &= (~core);
+ pmm->cores_powered &= (~core);
+ pmm->cores_pend_down &= (~core);
+ pmm->cores_pend_up &= (~core);
+ pmm->cores_ack_down &= (~core);
+ pmm->cores_ack_up &= (~core);
+
+ pmm_update_system_state( pmm );
+
+#if MALI_PMM_TRACE
+ _mali_pmm_trace_hardware_change( old_power, pmm->cores_powered );
+#endif
+ }
+
+#if MALI_STATE_TRACKING
+ pmm->mali_pmm_lock_acquired = 0;
+#endif /* MALI_STATE_TRACKING */
+
+ MALI_PMM_UNLOCK(pmm);
+}
+void malipmm_core_power_down_okay( mali_pmm_core_id core )
+{
+ _mali_uk_pmm_message_s event = {
+ NULL,
+ MALI_PMM_EVENT_INTERNAL_POWER_DOWN_ACK,
+ 0 };
+
+ event.data = core;
+
+ _mali_ukk_pmm_event_message( &event );
+}
+
+void malipmm_set_policy_check()
+{
+ _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR;
+ MALI_DEBUG_ASSERT_POINTER(pmm);
+ pmm->check_policy = MALI_TRUE;
+
+ /* To check the policy we need to schedule some work */
+ _mali_osk_irq_schedulework( pmm->irq );
+}
+
+_mali_osk_errcode_t malipmm_irq_uhandler(void *data)
+{
+ MALIPMM_DEBUG_PRINT( ("PMM: uhandler - not expected to be used\n") );
+
+ MALI_SUCCESS;
+}
+
+void malipmm_irq_bhandler(void *data)
+{
+ _mali_pmm_internal_state_t *pmm;
+ pmm = (_mali_pmm_internal_state_t *)data;
+ MALI_DEBUG_ASSERT_POINTER(pmm);
+
+#if PMM_OS_TEST
+ if( power_test_check() ) return;
+#endif
+
+ MALI_PMM_LOCK(pmm);
+#ifdef MALI_STATE_TRACKING
+ pmm->mali_pmm_lock_acquired = 1;
+#endif /* MALI_STATE_TRACKING */
+
+ /* Quick out when we are shutting down */
+ if( pmm->status == MALI_PMM_STATUS_OFF )
+ {
+
+ #if MALI_STATE_TRACKING
+ pmm->mali_pmm_lock_acquired = 0;
+ #endif /* MALI_STATE_TRACKING */
+
+ MALI_PMM_UNLOCK(pmm);
+ return;
+ }
+
+ MALIPMM_DEBUG_PRINT( ("PMM: bhandler - Processing event\n") );
+
+ if( pmm->missed > 0 )
+ {
+ MALI_PRINT_ERROR( ("PMM: Failed to send %d events", pmm->missed) );
+ pmm_fatal_reset( pmm );
+ }
+
+ if( pmm->check_policy )
+ {
+ pmm->check_policy = MALI_FALSE;
+ pmm_policy_check_policy(pmm);
+ }
+ else
+ {
+ /* Perform event processing */
+ pmm_event_process();
+ if( pmm->fatal_power_err )
+ {
+ /* Try a reset */
+ pmm_fatal_reset( pmm );
+ }
+ }
+
+#if MALI_STATE_TRACKING
+ pmm->mali_pmm_lock_acquired = 0;
+#endif /* MALI_STATE_TRACKING */
+
+ MALI_PMM_UNLOCK(pmm);
+}
+
+static void pmm_event_process( void )
+{
+ _mali_osk_errcode_t err = _MALI_OSK_ERR_OK;
+ _mali_osk_notification_t *msg = NULL;
+ _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR;
+ mali_pmm_message_t *event;
+ u32 process_messages;
+
+ MALI_DEBUG_ASSERT_POINTER(pmm);
+
+
+ /* Max number of messages to process before exiting - as we shouldn't stay
+ * processing the messages for a long time
+ */
+ process_messages = _mali_osk_atomic_read( &(pmm->messages_queued) );
+
+ while( process_messages > 0 )
+ {
+ /* Check internal message queue first */
+ err = _mali_osk_notification_queue_dequeue( pmm->iqueue, &msg );
+
+ if( err != _MALI_OSK_ERR_OK )
+ {
+ if( pmm->status == MALI_PMM_STATUS_IDLE || pmm->status == MALI_PMM_STATUS_OS_WAITING || pmm->status == MALI_PMM_STATUS_DVFS_PAUSE)
+ {
+ if( pmm->waiting > 0 ) pmm->waiting--;
+
+ /* We aren't busy changing state, so look at real events */
+ err = _mali_osk_notification_queue_dequeue( pmm->queue, &msg );
+
+ if( err != _MALI_OSK_ERR_OK )
+ {
+ pmm->no_events++;
+ MALIPMM_DEBUG_PRINT( ("PMM: event_process - No message to process\n") );
+ /* Nothing to do - so return */
+ return;
+ }
+ else
+ {
+ #if (MALI_PMM_TRACE || MALI_STATE_TRACKING)
+ pmm->messages_received++;
+ #endif
+ }
+ }
+ else
+ {
+ /* Waiting for an internal message */
+ pmm->waiting++;
+ MALIPMM_DEBUG_PRINT( ("PMM: event_process - Waiting for internal message, messages queued=%d\n", pmm->waiting) );
+ return;
+ }
+ }
+ else
+ {
+ #if (MALI_PMM_TRACE || MALI_STATE_TRACKING)
+ pmm->imessages_received++;
+ #endif
+ }
+
+ MALI_DEBUG_ASSERT_POINTER( msg );
+ /* Check the message type matches */
+ MALI_DEBUG_ASSERT( msg->notification_type == MALI_PMM_NOTIFICATION_TYPE );
+
+ event = msg->result_buffer;
+
+ _mali_osk_atomic_dec( &(pmm->messages_queued) );
+ process_messages--;
+
+ #if MALI_PMM_TRACE
+ /* Trace before we process the event in case we have an error */
+ _mali_pmm_trace_event_message( event, MALI_TRUE );
+ #endif
+ err = pmm_policy_process( pmm, event );
+
+
+ if( err != _MALI_OSK_ERR_OK )
+ {
+ MALI_PRINT_ERROR( ("PMM: Error(%d) in policy %d when processing event message with id: %d",
+ err, pmm->policy, event->id) );
+ }
+
+ /* Delete notification */
+ _mali_osk_notification_delete ( msg );
+
+ if( pmm->fatal_power_err )
+ {
+ /* Nothing good has happened - exit */
+ return;
+ }
+
+
+ #if MALI_PMM_TRACE
+ MALI_PRINT( ("PMM Trace: Event processed, msgs (sent/read) = %d/%d, int msgs (sent/read) = %d/%d, no events = %d, waiting = %d\n",
+ pmm->messages_sent, pmm->messages_received, pmm->imessages_sent, pmm->imessages_received, pmm->no_events, pmm->waiting) );
+ #endif
+ }
+
+ if( pmm->status == MALI_PMM_STATUS_IDLE && pmm->waiting > 0 )
+ {
+ /* For events we ignored whilst we were busy, add a new
+ * scheduled time to look at them */
+ _mali_osk_irq_schedulework( pmm->irq );
+ }
+}
+
+#if MALI_STATE_TRACKING
+void malipmm_subsystem_dump_state(void)
+{
+ malipmm_state_dump();
+}
+#endif
+
+#if (defined(DEBUG) || MALI_STATE_TRACKING)
+void malipmm_state_dump()
+{
+ _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR;
+
+ if( !pmm )
+ {
+ MALI_PRINT(("PMM: Null state\n"));
+ }
+ else
+ {
+ MALI_PRINT(("Locks::\nPMM_LOCK_STATUS=%ld",pmm->mali_pmm_lock_acquired));
+ MALI_PRINT(("PMM state:\nPrevious_status=%d\nstatus=%d\nCurrent_event=%d\npolicy=%d\ncheck_policy=%d\nstate=%d\n", pmm->mali_last_pmm_status,pmm->status, pmm->mali_new_event_status, pmm->policy, pmm->check_policy, pmm->state));
+ MALI_PRINT(("PMM cores:\ncores_registered=%d\ncores_powered=%d\ncores_idle=%d\ncores_pend_down=%d\ncores_pend_up=%d\ncores_ack_down=%d\ncores_ack_up=%d\n", pmm->cores_registered, pmm->cores_powered, pmm->cores_idle, pmm->cores_pend_down, pmm->cores_pend_up, pmm->cores_ack_down, pmm->cores_ack_up));
+ MALI_PRINT(("PMM misc:\npmu_init=%d\nmessages_queued=%d\nwaiting=%d\nno_events=%d\nmissed=%d\nfatal_power_err=%d\n", pmm->pmu_initialized, _mali_osk_atomic_read( &(pmm->messages_queued) ), pmm->waiting, pmm->no_events, pmm->missed, pmm->fatal_power_err));
+ }
+}
+#endif
+
+#endif /* USING_MALI_PMM */
diff --git a/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm.h b/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm.h
new file mode 100644
index 00000000000..fe7a046cb47
--- /dev/null
+++ b/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm.h
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2010-2011 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * @file mali_pmm.h
+ * Defines the power management module for the kernel device driver
+ */
+
+#ifndef __MALI_PMM_H__
+#define __MALI_PMM_H__
+
+/* For mali_pmm_message_data and MALI_PMM_EVENT_UK_* defines */
+#include "mali_uk_types.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * @defgroup pmmapi Power Management Module APIs
+ *
+ * @{
+ */
+
+/** OS event tester */
+#define PMM_OS_TEST 0
+
+/** @brief Compile option to turn on/off tracing */
+#define MALI_PMM_TRACE 0
+#define MALI_PMM_TRACE_SENT_EVENTS 0
+
+/** @brief Compile option to switch between always on or job control PMM policy */
+#define MALI_PMM_ALWAYS_ON 0
+
+/** @brief Overrides hardware PMU and uses software simulation instead
+ * @note This even stops intialization of PMU and cores being powered on at start up
+ */
+#define MALI_PMM_NO_PMU 0
+
+/** @brief PMM debug print to control debug message level */
+#define MALIPMM_DEBUG_PRINT(args) \
+ MALI_DEBUG_PRINT(3, args)
+
+
+/** @brief power management event message identifiers.
+ */
+/* These must match up with the pmm_trace_events & pmm_trace_events_internal
+ * arrays
+ */
+typedef enum mali_pmm_event_id
+{
+ MALI_PMM_EVENT_OS_POWER_UP = 0, /**< OS power up event */
+ MALI_PMM_EVENT_OS_POWER_DOWN = 1, /**< OS power down event */
+ MALI_PMM_EVENT_JOB_SCHEDULED = 2, /**< Job scheduled to run event */
+ MALI_PMM_EVENT_JOB_QUEUED = 3, /**< Job queued (but not run) event */
+ MALI_PMM_EVENT_JOB_FINISHED = 4, /**< Job finished event */
+ MALI_PMM_EVENT_TIMEOUT = 5, /**< Time out timer has expired */
+ MALI_PMM_EVENT_DVFS_PAUSE = 6, /**< Mali device pause event */
+ MALI_PMM_EVENT_DVFS_RESUME = 7, /**< Mali device resume event */
+
+ MALI_PMM_EVENT_UKS = 200, /**< Events from the user-side start here */
+ MALI_PMM_EVENT_UK_EXAMPLE = _MALI_PMM_EVENT_UK_EXAMPLE,
+
+ MALI_PMM_EVENT_INTERNALS = 1000,
+ MALI_PMM_EVENT_INTERNAL_POWER_UP_ACK = 1001, /**< Internal power up acknowledgement */
+ MALI_PMM_EVENT_INTERNAL_POWER_DOWN_ACK = 1002, /**< Internal power down acknowledgment */
+} mali_pmm_event_id;
+
+
+/** @brief Use this when the power up/down callbacks do not need any OS data. */
+#define MALI_PMM_NO_OS_DATA 1
+
+
+/* @brief Geometry and pixel processor identifiers for the PMM
+ *
+ * @note these match the ARM Mali 400 PMU hardware definitions, apart from the "SYSTEM"
+ */
+typedef enum mali_pmm_core_id_tag
+{
+ MALI_PMM_CORE_SYSTEM = 0x00000000, /**< All of the Mali hardware */
+ MALI_PMM_CORE_GP = 0x00000001, /**< Mali GP2 */
+ MALI_PMM_CORE_L2 = 0x00000002, /**< Level 2 cache */
+ MALI_PMM_CORE_PP0 = 0x00000004, /**< Mali 200 pixel processor 0 */
+ MALI_PMM_CORE_PP1 = 0x00000008, /**< Mali 200 pixel processor 1 */
+ MALI_PMM_CORE_PP2 = 0x00000010, /**< Mali 200 pixel processor 2 */
+ MALI_PMM_CORE_PP3 = 0x00000020, /**< Mali 200 pixel processor 3 */
+ MALI_PMM_CORE_PP_ALL = 0x0000003C /**< Mali 200 pixel processors 0-3 */
+} mali_pmm_core_id;
+
+/* @brief PMM bitmask of mali_pmm_core_ids
+ */
+typedef u32 mali_pmm_core_mask;
+
+/* @brief PMM event timestamp type
+ */
+typedef u32 mali_pmm_timestamp;
+
+/** @brief power management event message struct
+ */
+typedef struct _mali_pmm_message
+{
+ mali_pmm_event_id id; /**< event id */
+ mali_pmm_message_data data; /**< specific data associated with the event */
+ mali_pmm_timestamp ts; /**< timestamp the event was placed in the event queue */
+} mali_pmm_message_t;
+
+
+
+/** @brief the state of the power management module.
+ */
+/* These must match up with the pmm_trace_state array */
+typedef enum mali_pmm_state_tag
+{
+ MALI_PMM_STATE_UNAVAILABLE = 0, /**< PMM is not available */
+ MALI_PMM_STATE_SYSTEM_ON = 1, /**< All of the Mali hardware is on */
+ MALI_PMM_STATE_SYSTEM_OFF = 2, /**< All of the Mali hardware is off */
+ MALI_PMM_STATE_SYSTEM_TRANSITION = 3 /**< System is changing state */
+} mali_pmm_state;
+
+
+/** @brief a power management policy.
+ */
+/* These must match up with the pmm_trace_policy array */
+typedef enum mali_pmm_policy_tag
+{
+ MALI_PMM_POLICY_NONE = 0, /**< No policy */
+ MALI_PMM_POLICY_ALWAYS_ON = 1, /**< Always on policy */
+ MALI_PMM_POLICY_JOB_CONTROL = 2, /**< Job control policy */
+ MALI_PMM_POLICY_RUNTIME_JOB_CONTROL = 3 /**< Run time power management control policy */
+} mali_pmm_policy;
+
+/** @brief Function to report to the OS when the power down has finished
+ *
+ * @param data The event message data that initiated the power down
+ */
+void _mali_osk_pmm_power_down_done(mali_pmm_message_data data);
+
+/** @brief Function to report to the OS when the power up has finished
+ *
+ * @param data The event message data that initiated the power up
+ */
+void _mali_osk_pmm_power_up_done(mali_pmm_message_data data);
+
+/** @brief Function to report that DVFS operation done
+ *
+ * @param data The event message data
+ */
+void _mali_osk_pmm_dvfs_operation_done(mali_pmm_message_data data);
+
+#if MALI_POWER_MGMT_TEST_SUITE
+/** @brief Function to notify power management events
+ *
+ * @param data The event message data
+ */
+void _mali_osk_pmm_policy_events_notifications(mali_pmm_event_id event_id);
+
+#endif
+
+/** @brief Function to report the OS that device is idle
+ *
+ * @note inform the OS that device is idle
+ */
+_mali_osk_errcode_t _mali_osk_pmm_dev_idle( void );
+
+/** @brief Function to report the OS to activate device
+ *
+ * @note inform the os that device needs to be activated
+ */
+void _mali_osk_pmm_dev_activate( void );
+
+/** @brief Queries the current state of the PMM software
+ *
+ * @note the state of the PMM can change after this call has returned
+ *
+ * @return the current PMM state value
+ */
+mali_pmm_state _mali_pmm_state( void );
+
+/** @brief List of cores that are registered with the PMM
+ *
+ * This will return the cores that have been currently registered with the PMM,
+ * which is a bitwise OR of the mali_pmm_core_id_tags. A value of 0x0 means that
+ * there are no cores registered.
+ *
+ * @note the list of cores can change after this call has returned
+ *
+ * @return a bit mask representing all the cores that have been registered with the PMM
+ */
+mali_pmm_core_mask _mali_pmm_cores_list( void );
+
+/** @brief List of cores that are powered up in the PMM
+ *
+ * This will return the subset of the cores that can be listed using mali_pmm_cores_
+ * list, that have power. It is a bitwise OR of the mali_pmm_core_id_tags. A value of
+ * 0x0 means that none of the cores registered are powered.
+ *
+ * @note the list of cores can change after this call has returned
+ *
+ * @return a bit mask representing all the cores that are powered up
+ */
+mali_pmm_core_mask _mali_pmm_cores_powered( void );
+
+
+/** @brief List of power management policies that are supported by the PMM
+ *
+ * Given an empty array of policies - policy_list - which contains the number
+ * of entries as specified by - policy_list_size, this function will populate
+ * the list with the available policies. If the policy_list is too small for
+ * all the policies then only policy_list_size entries will be returned. If the
+ * policy_list is bigger than the number of available policies then, the extra
+ * entries will be set to MALI_PMM_POLICY_NONE.
+ * The function will also update available_policies with the number of policies
+ * that are available, even if it exceeds the policy_list_size.
+ * The function will succeed if all policies could be returned, else it will
+ * fail if none or only a subset of policies could be returned.
+ * The function will also fail if no policy_list is supplied, though
+ * available_policies is optional.
+ *
+ * @note this is a STUB function and is not yet implemented
+ *
+ * @param policy_list_size is the number of policies that can be returned in
+ * the policy_list argument
+ * @param policy_list is an array of policies that should be populated with
+ * the list of policies that are supported by the PMM
+ * @param policies_available optional argument, if non-NULL will be set to the
+ * number of policies available
+ * @return _MALI_OSK_ERR_OK if the policies could be listed, or a suitable
+ * _mali_osk_errcode_t otherwise.
+ */
+_mali_osk_errcode_t _mali_pmm_list_policies(
+ u32 policy_list_size,
+ mali_pmm_policy *policy_list,
+ u32 *policies_available );
+
+/** @brief Set the power management policy in the PMM
+ *
+ * Given a valid supported policy, this function will change the PMM to use
+ * this new policy
+ * The function will fail if the policy given is invalid or unsupported.
+ *
+ * @note this is a STUB function and is not yet implemented
+ *
+ * @param policy the new policy to be set
+ * @return _MALI_OSK_ERR_OK if the policy could be set, or a suitable
+ * _mali_osk_errcode_t otherwise.
+ */
+_mali_osk_errcode_t _mali_pmm_set_policy( mali_pmm_policy policy );
+
+/** @brief Get the current power management policy in the PMM
+ *
+ * Given a pointer to a policy data type, this function will return the current
+ * policy that is in effect for the PMM. This maybe out of date if there is a
+ * pending set policy call that has not been serviced.
+ * The function will fail if the policy given is NULL.
+ *
+ * @note the policy of the PMM can change after this call has returned
+ *
+ * @param policy a pointer to a policy that can be updated to the current
+ * policy
+ * @return _MALI_OSK_ERR_OK if the policy could be returned, or a suitable
+ * _mali_osk_errcode_t otherwise.
+ */
+_mali_osk_errcode_t _mali_pmm_get_policy( mali_pmm_policy *policy );
+
+#if MALI_PMM_TRACE
+
+/** @brief Indicates when a hardware state change occurs in the PMM
+ *
+ * @param old a mask of the cores indicating the previous state of the cores
+ * @param newstate a mask of the cores indicating the new current state of the cores
+ */
+void _mali_pmm_trace_hardware_change( mali_pmm_core_mask old, mali_pmm_core_mask newstate );
+
+/** @brief Indicates when a state change occurs in the PMM
+ *
+ * @param old the previous state for the PMM
+ * @param newstate the new current state of the PMM
+ */
+void _mali_pmm_trace_state_change( mali_pmm_state old, mali_pmm_state newstate );
+
+/** @brief Indicates when a policy change occurs in the PMM
+ *
+ * @param old the previous policy for the PMM
+ * @param newpolicy the new current policy of the PMM
+ */
+void _mali_pmm_trace_policy_change( mali_pmm_policy old, mali_pmm_policy newpolicy );
+
+/** @brief Records when an event message is read by the event system
+ *
+ * @param event the message details
+ * @param received MALI_TRUE when the message is received by the PMM, else it is being sent
+ */
+void _mali_pmm_trace_event_message( mali_pmm_message_t *event, mali_bool received );
+
+#endif /* MALI_PMM_TRACE */
+
+/** @brief Dumps the current state of OS PMM thread
+ */
+#if MALI_STATE_TRACKING
+void mali_pmm_dump_os_thread_state( void );
+#endif /* MALI_STATE_TRACKING */
+
+#if (defined(DEBUG) || MALI_STATE_TRACKING)
+/** @brief Dumps the current state of the PMM
+ */
+void malipmm_state_dump( void );
+#endif
+
+/** @} */ /* end group pmmapi */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MALI_PMM_H__ */
diff --git a/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm_policy.c b/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm_policy.c
new file mode 100644
index 00000000000..327e8b4c853
--- /dev/null
+++ b/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm_policy.c
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2010-2011 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * @file mali_pmm_policy.c
+ * Implementation of the common routines for power management module
+ * policies
+ */
+
+#if USING_MALI_PMM
+
+#include "mali_ukk.h"
+#include "mali_kernel_common.h"
+
+#include "mali_pmm.h"
+#include "mali_pmm_system.h"
+#include "mali_pmm_state.h"
+#include "mali_pmm_policy.h"
+
+#include "mali_pmm_policy_alwayson.h"
+#include "mali_pmm_policy_jobcontrol.h"
+
+/* Call back function for timer expiration */
+static void pmm_policy_timer_callback( void *arg );
+
+_mali_osk_errcode_t pmm_policy_timer_init( _pmm_policy_timer_t *pptimer, u32 timeout, mali_pmm_event_id id )
+{
+ MALI_DEBUG_ASSERT_POINTER(pptimer);
+
+ /* All values get 0 as default */
+ _mali_osk_memset(pptimer, 0, sizeof(*pptimer));
+
+ pptimer->timer = _mali_osk_timer_init();
+ if( pptimer->timer )
+ {
+ _mali_osk_timer_setcallback( pptimer->timer, pmm_policy_timer_callback, (void *)pptimer );
+ pptimer->timeout = timeout;
+ pptimer->event_id = id;
+ MALI_SUCCESS;
+ }
+
+ return _MALI_OSK_ERR_FAULT;
+}
+
+static void pmm_policy_timer_callback( void *arg )
+{
+ _pmm_policy_timer_t *pptimer = (_pmm_policy_timer_t *)arg;
+
+ MALI_DEBUG_ASSERT_POINTER(pptimer);
+ MALI_DEBUG_ASSERT( pptimer->set );
+
+ /* Set timer expired and flag there is a policy to check */
+ pptimer->expired = MALI_TRUE;
+ malipmm_set_policy_check();
+}
+
+
+void pmm_policy_timer_term( _pmm_policy_timer_t *pptimer )
+{
+ MALI_DEBUG_ASSERT_POINTER(pptimer);
+
+ _mali_osk_timer_del( pptimer->timer );
+ _mali_osk_timer_term( pptimer->timer );
+ pptimer->timer = NULL;
+}
+
+mali_bool pmm_policy_timer_start( _pmm_policy_timer_t *pptimer )
+{
+ MALI_DEBUG_ASSERT_POINTER(pptimer);
+ MALI_DEBUG_ASSERT_POINTER(pptimer->timer);
+
+ if( !(pptimer->set) )
+ {
+ pptimer->set = MALI_TRUE;
+ pptimer->expired = MALI_FALSE;
+ pptimer->start = _mali_osk_time_tickcount();
+ _mali_osk_timer_add( pptimer->timer, pptimer->timeout );
+ return MALI_TRUE;
+ }
+
+ return MALI_FALSE;
+}
+
+mali_bool pmm_policy_timer_stop( _pmm_policy_timer_t *pptimer )
+{
+ MALI_DEBUG_ASSERT_POINTER(pptimer);
+ MALI_DEBUG_ASSERT_POINTER(pptimer->timer);
+
+ if( pptimer->set )
+ {
+ _mali_osk_timer_del( pptimer->timer );
+ pptimer->set = MALI_FALSE;
+ pptimer->expired = MALI_FALSE;
+ return MALI_TRUE;
+ }
+
+ return MALI_FALSE;
+}
+
+mali_bool pmm_policy_timer_raise_event( _pmm_policy_timer_t *pptimer )
+{
+ MALI_DEBUG_ASSERT_POINTER(pptimer);
+
+ if( pptimer->expired )
+ {
+ _mali_uk_pmm_message_s event = {
+ NULL,
+ MALI_PMM_EVENT_TIMEOUT, /* Assume timeout id, but set it below */
+ 0 };
+
+ event.id = pptimer->event_id;
+ event.data = (mali_pmm_message_data)pptimer->start;
+
+ /* Don't need to do any other notification with this timer */
+ pptimer->expired = MALI_FALSE;
+ /* Unset timer so it is free to be set again */
+ pptimer->set = MALI_FALSE;
+
+ _mali_ukk_pmm_event_message( &event );
+
+ return MALI_TRUE;
+ }
+
+ return MALI_FALSE;
+}
+
+mali_bool pmm_policy_timer_valid( u32 timer_start, u32 other_start )
+{
+ return (_mali_osk_time_after( other_start, timer_start ) == 0);
+}
+
+
+_mali_osk_errcode_t pmm_policy_init(_mali_pmm_internal_state_t *pmm)
+{
+ _mali_osk_errcode_t err;
+
+ MALI_DEBUG_ASSERT_POINTER(pmm);
+
+ switch( pmm->policy )
+ {
+ case MALI_PMM_POLICY_ALWAYS_ON:
+ {
+ err = pmm_policy_init_always_on();
+ }
+ break;
+
+ case MALI_PMM_POLICY_JOB_CONTROL:
+ {
+ err = pmm_policy_init_job_control(pmm);
+ }
+ break;
+
+ case MALI_PMM_POLICY_NONE:
+ default:
+ err = _MALI_OSK_ERR_FAULT;
+ }
+
+ return err;
+}
+
+void pmm_policy_term(_mali_pmm_internal_state_t *pmm)
+{
+ MALI_DEBUG_ASSERT_POINTER(pmm);
+
+ switch( pmm->policy )
+ {
+ case MALI_PMM_POLICY_ALWAYS_ON:
+ {
+ pmm_policy_term_always_on();
+ }
+ break;
+
+ case MALI_PMM_POLICY_JOB_CONTROL:
+ {
+ pmm_policy_term_job_control();
+ }
+ break;
+
+ case MALI_PMM_POLICY_NONE:
+ default:
+ MALI_PRINT_ERROR( ("PMM: Invalid policy terminated %d\n", pmm->policy) );
+ }
+}
+
+
+_mali_osk_errcode_t pmm_policy_process(_mali_pmm_internal_state_t *pmm, mali_pmm_message_t *event)
+{
+ _mali_osk_errcode_t err;
+
+ MALI_DEBUG_ASSERT_POINTER(pmm);
+ MALI_DEBUG_ASSERT_POINTER(event);
+
+ switch( pmm->policy )
+ {
+ case MALI_PMM_POLICY_ALWAYS_ON:
+ {
+ err = pmm_policy_process_always_on( pmm, event );
+ }
+ break;
+
+ case MALI_PMM_POLICY_JOB_CONTROL:
+ {
+ err = pmm_policy_process_job_control( pmm, event );
+ }
+ break;
+
+ case MALI_PMM_POLICY_NONE:
+ default:
+ err = _MALI_OSK_ERR_FAULT;
+ }
+
+ return err;
+}
+
+
+void pmm_policy_check_policy( _mali_pmm_internal_state_t *pmm )
+{
+ MALI_DEBUG_ASSERT_POINTER(pmm);
+
+ switch( pmm->policy )
+ {
+ case MALI_PMM_POLICY_JOB_CONTROL:
+ {
+ pmm_policy_check_job_control();
+ }
+ break;
+
+ default:
+ /* Nothing needs to be done */
+ break;
+ }
+}
+
+
+#endif /* USING_MALI_PMM */
+
diff --git a/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm_policy.h b/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm_policy.h
new file mode 100644
index 00000000000..83cb7f29a92
--- /dev/null
+++ b/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm_policy.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2010-2011 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * @file mali_pmm_policy.h
+ * Defines the power management module policies
+ */
+
+#ifndef __MALI_PMM_POLICY_H__
+#define __MALI_PMM_POLICY_H__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * @addtogroup pmmapi Power Management Module APIs
+ *
+ * @{
+ *
+ * @defgroup pmmapi_policy Power Management Module Policies
+ *
+ * @{
+ */
+
+/** @brief Generic timer for use with policies
+ */
+typedef struct _pmm_policy_timer
+{
+ u32 timeout; /**< Timeout for this timer in ticks */
+ mali_pmm_event_id event_id; /**< Event id that will be raised when timer expires */
+ _mali_osk_timer_t *timer; /**< Timer */
+ mali_bool set; /**< Timer set */
+ mali_bool expired; /**< Timer expired - event needs to be raised */
+ u32 start; /**< Timer start ticks */
+} _pmm_policy_timer_t;
+
+/** @brief Policy timer initialization
+ *
+ * This will create a timer for use in policies, but won't start it
+ *
+ * @param pptimer An empty timer structure to be initialized
+ * @param timeout Timeout in ticks for the timer
+ * @param id Event id that will be raised on timeout
+ * @return _MALI_OSK_ERR_OK if the policy could be initialized, or a suitable
+ * _mali_osk_errcode_t otherwise.
+ */
+_mali_osk_errcode_t pmm_policy_timer_init( _pmm_policy_timer_t *pptimer, u32 timeout, mali_pmm_event_id id );
+
+/** @brief Policy timer termination
+ *
+ * This will clean up a timer that was previously used in policies, it
+ * will also stop it if started
+ *
+ * @param pptimer An initialized timer structure to be terminated
+ */
+void pmm_policy_timer_term( _pmm_policy_timer_t *pptimer );
+
+/** @brief Policy timer start
+ *
+ * This will start a previously created timer for use in policies
+ * When the timer expires after the initialized timeout it will raise
+ * a PMM event of the event id given on initialization
+ * As data for the event it will pass the start time of the timer
+ *
+ * @param pptimer A previously initialized policy timer
+ * @return MALI_TRUE if the timer was started, MALI_FALSE if it is already started
+ */
+mali_bool pmm_policy_timer_start( _pmm_policy_timer_t *pptimer );
+
+/** @brief Policy timer stop
+ *
+ * This will stop a previously created timer for use in policies
+ *
+ * @param pptimer A previously started policy timer
+ * @return MALI_TRUE if the timer was stopped, MALI_FALSE if it is already stopped
+ */
+mali_bool pmm_policy_timer_stop( _pmm_policy_timer_t *pptimer );
+
+/** @brief Policy timer stop
+ *
+ * This raise an event for an expired timer
+ *
+ * @param pptimer An expired policy timer
+ * @return MALI_TRUE if an event was raised, else MALI_FALSE
+ */
+mali_bool pmm_policy_timer_raise_event( _pmm_policy_timer_t *pptimer );
+
+/** @brief Policy timer valid checker
+ *
+ * This will check that a timer was started after a given time
+ *
+ * @param timer_start Time the timer was started
+ * @param other_start Time when another event or action occurred
+ * @return MALI_TRUE if the timer was started after the other time, else MALI_FALSE
+ */
+mali_bool pmm_policy_timer_valid( u32 timer_start, u32 other_start );
+
+
+/** @brief Common policy initialization
+ *
+ * This will initialize the current policy
+ *
+ * @note Any previously initialized policy should be terminated first
+ *
+ * @return _MALI_OSK_ERR_OK if the policy could be initialized, or a suitable
+ * _mali_osk_errcode_t otherwise.
+ */
+_mali_osk_errcode_t pmm_policy_init( _mali_pmm_internal_state_t *pmm );
+
+/** @brief Common policy termination
+ *
+ * This will terminate the current policy.
+ * @note This can be called when a policy has not been initialized
+ */
+void pmm_policy_term( _mali_pmm_internal_state_t *pmm );
+
+/** @brief Common policy state changer
+ *
+ * Given the next available event message, this routine passes it to
+ * the current policy for processing
+ *
+ * @param pmm internal PMM state
+ * @param event PMM event to process
+ * @return _MALI_OSK_ERR_OK if the policy state completed okay, or a suitable
+ * _mali_osk_errcode_t otherwise.
+ */
+_mali_osk_errcode_t pmm_policy_process( _mali_pmm_internal_state_t *pmm, mali_pmm_message_t *event );
+
+
+/** @brief Common policy checker
+ *
+ * If a policy timer fires then this function will be called to
+ * allow the policy to take the correct action
+ *
+ * @param pmm internal PMM state
+ */
+void pmm_policy_check_policy( _mali_pmm_internal_state_t *pmm );
+
+/** @} */ /* End group pmmapi_policy */
+/** @} */ /* End group pmmapi */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MALI_PMM_POLICY_H__ */
diff --git a/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm_policy_alwayson.c b/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm_policy_alwayson.c
new file mode 100644
index 00000000000..643bb04553b
--- /dev/null
+++ b/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm_policy_alwayson.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2010-2011 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * @file mali_pmm_policy_alwayson.c
+ * Implementation of the power management module policy - always on
+ */
+
+#if USING_MALI_PMM
+
+#include "mali_ukk.h"
+#include "mali_kernel_common.h"
+
+#include "mali_pmm.h"
+#include "mali_pmm_system.h"
+#include "mali_pmm_state.h"
+#include "mali_pmm_policy.h"
+#include "mali_pmm_policy_alwayson.h"
+
+_mali_osk_errcode_t pmm_policy_init_always_on(void)
+{
+ /* Nothing to set up */
+ MALI_SUCCESS;
+}
+
+void pmm_policy_term_always_on(void)
+{
+ /* Nothing to tear down */
+}
+
+_mali_osk_errcode_t pmm_policy_process_always_on( _mali_pmm_internal_state_t *pmm, mali_pmm_message_t *event )
+{
+ MALI_DEBUG_ASSERT_POINTER(pmm);
+ MALI_DEBUG_ASSERT_POINTER(event);
+
+ switch( event->id )
+ {
+ case MALI_PMM_EVENT_OS_POWER_DOWN:
+ /* We aren't going to do anything, but signal so we don't block the OS
+ * NOTE: This may adversely affect any jobs Mali is currently running
+ */
+ _mali_osk_pmm_power_down_done( event->data );
+ break;
+
+ case MALI_PMM_EVENT_INTERNAL_POWER_UP_ACK:
+ case MALI_PMM_EVENT_INTERNAL_POWER_DOWN_ACK:
+ /* Not expected in this policy */
+ MALI_DEBUG_ASSERT( MALI_FALSE );
+ break;
+
+ case MALI_PMM_EVENT_OS_POWER_UP:
+ /* Nothing to do */
+ _mali_osk_pmm_power_up_done( event->data );
+ break;
+
+ case MALI_PMM_EVENT_JOB_SCHEDULED:
+ case MALI_PMM_EVENT_JOB_QUEUED:
+ case MALI_PMM_EVENT_JOB_FINISHED:
+ /* Nothing to do - we are always on */
+ break;
+
+ case MALI_PMM_EVENT_TIMEOUT:
+ /* Not expected in this policy */
+ MALI_DEBUG_ASSERT( MALI_FALSE );
+ break;
+
+ default:
+ MALI_ERROR(_MALI_OSK_ERR_ITEM_NOT_FOUND);
+ }
+
+ MALI_SUCCESS;
+}
+
+#endif
diff --git a/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm_policy_alwayson.h b/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm_policy_alwayson.h
new file mode 100644
index 00000000000..a158b09f610
--- /dev/null
+++ b/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm_policy_alwayson.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2010-2011 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * @file mali_pmm_policy_alwayson.h
+ * Defines the power management module policy for always on
+ */
+
+#ifndef __MALI_PMM_POLICY_ALWAYSON_H__
+#define __MALI_PMM_POLICY_ALWAYSON_H__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * @addtogroup pmmapi_policy Power Management Module Policies
+ *
+ * @{
+ */
+
+/** @brief Always on policy initialization
+ *
+ * @return _MALI_OSK_ERR_OK if the policy could be initialized, or a suitable
+ * _mali_osk_errcode_t otherwise.
+ */
+_mali_osk_errcode_t pmm_policy_init_always_on(void);
+
+/** @brief Always on policy termination
+ */
+void pmm_policy_term_always_on(void);
+
+/** @brief Always on policy state changer
+ *
+ * Given the next available event message, this routine processes it
+ * for the policy and changes state as needed.
+ *
+ * Always on policy will ignore all events and keep the Mali cores on
+ * all the time
+ *
+ * @param pmm internal PMM state
+ * @param event PMM event to process
+ * @return _MALI_OSK_ERR_OK if the policy state completed okay, or a suitable
+ * _mali_osk_errcode_t otherwise.
+ */
+_mali_osk_errcode_t pmm_policy_process_always_on( _mali_pmm_internal_state_t *pmm, mali_pmm_message_t *event );
+
+/** @} */ /* End group pmmapi_policies */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MALI_PMM_POLICY_ALWAYSON_H__ */
diff --git a/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm_policy_jobcontrol.c b/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm_policy_jobcontrol.c
new file mode 100644
index 00000000000..8450bd722f4
--- /dev/null
+++ b/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm_policy_jobcontrol.c
@@ -0,0 +1,461 @@
+/*
+ * Copyright (C) 2010-2011 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * @file mali_pmm_policy_jobcontrol.c
+ * Implementation of the power management module policy - job control
+ */
+
+#if USING_MALI_PMM
+
+#include "mali_ukk.h"
+#include "mali_kernel_common.h"
+#include "mali_platform.h"
+
+#include "mali_pmm.h"
+#include "mali_pmm_system.h"
+#include "mali_pmm_state.h"
+#include "mali_pmm_policy.h"
+#include "mali_pmm_policy_jobcontrol.h"
+
+typedef struct _pmm_policy_data_job_control
+{
+ _pmm_policy_timer_t latency; /**< Latency timeout timer for all cores */
+ u32 core_active_start; /**< Last time a core was set to active */
+ u32 timeout; /**< Timeout in ticks for latency timer */
+} _pmm_policy_data_job_control_t;
+
+
+/* @ brief Local data for this policy
+ */
+static _pmm_policy_data_job_control_t *data_job_control = NULL;
+
+/* @brief Set up the timeout if it hasn't already been set and if there are active cores */
+static void job_control_timeout_setup( _mali_pmm_internal_state_t *pmm, _pmm_policy_timer_t *pptimer )
+{
+ MALI_DEBUG_ASSERT_POINTER(pmm);
+ MALI_DEBUG_ASSERT_POINTER(pptimer);
+
+ /* Do we have an inactivity time out and some powered cores? */
+ if( pptimer->timeout > 0 && pmm->cores_powered != 0 )
+ {
+ /* Is the system idle and all the powered cores are idle? */
+ if( pmm->status == MALI_PMM_STATUS_IDLE && pmm->cores_idle == pmm->cores_powered )
+ {
+ if( pmm_policy_timer_start(pptimer) )
+ {
+ MALIPMM_DEBUG_PRINT( ("PMM policy - Job control: Setting in-activity latency timer\n") );
+ }
+ }
+ else
+ {
+ /* We are not idle so there is no need for an inactivity timer
+ */
+ if( pmm_policy_timer_stop(pptimer) )
+ {
+ MALIPMM_DEBUG_PRINT( ("PMM policy - Job control: Removing in-activity latency timer\n") );
+ }
+ }
+ }
+}
+
+/* @brief Check the validity of the timeout - and if there is one set */
+static mali_bool job_control_timeout_valid( _mali_pmm_internal_state_t *pmm, _pmm_policy_timer_t *pptimer, u32 timer_start )
+{
+ MALI_DEBUG_ASSERT_POINTER(pmm);
+ MALI_DEBUG_ASSERT_POINTER(pptimer);
+
+ /* Not a valid timer! */
+ if( pptimer->timeout == 0 ) return MALI_FALSE;
+
+ /* Are some cores powered and are they all idle? */
+ if( (pmm->cores_powered != 0) && (pmm->cores_idle == pmm->cores_powered) )
+ {
+ /* Has latency timeout started after the last core was active? */
+ if( pmm_policy_timer_valid( timer_start, data_job_control->core_active_start ) )
+ {
+ return MALI_TRUE;
+ }
+ else
+ {
+ MALIPMM_DEBUG_PRINT( ("PMM: In-activity latency time out ignored - out of date\n") );
+ }
+ }
+ else
+ {
+ if( pmm->cores_powered == 0 )
+ {
+ MALIPMM_DEBUG_PRINT( ("PMM: In-activity latency time out ignored - cores already off\n") );
+ }
+ else
+ {
+ MALIPMM_DEBUG_PRINT( ("PMM: In-activity latency time out ignored - cores active\n") );
+ }
+ }
+
+ return MALI_FALSE;
+}
+
+_mali_osk_errcode_t pmm_policy_init_job_control( _mali_pmm_internal_state_t *pmm )
+{
+ _mali_osk_errcode_t err;
+ MALI_DEBUG_ASSERT_POINTER( pmm );
+ MALI_DEBUG_ASSERT( data_job_control == NULL );
+
+ data_job_control = (_pmm_policy_data_job_control_t *) _mali_osk_malloc(sizeof(*data_job_control));
+ MALI_CHECK_NON_NULL( data_job_control, _MALI_OSK_ERR_NOMEM );
+
+ data_job_control->core_active_start = _mali_osk_time_tickcount();
+ data_job_control->timeout = MALI_PMM_POLICY_JOBCONTROL_INACTIVITY_TIMEOUT;
+
+ err = pmm_policy_timer_init( &data_job_control->latency, data_job_control->timeout, MALI_PMM_EVENT_TIMEOUT );
+ if( err != _MALI_OSK_ERR_OK )
+ {
+ _mali_osk_free( data_job_control );
+ data_job_control = NULL;
+ return err;
+ }
+
+ /* Start the latency timeout */
+ job_control_timeout_setup( pmm, &data_job_control->latency );
+
+ MALI_SUCCESS;
+}
+
+void pmm_policy_term_job_control(void)
+{
+ if( data_job_control != NULL )
+ {
+ pmm_policy_timer_term( &data_job_control->latency );
+ _mali_osk_free( data_job_control );
+ data_job_control = NULL;
+ }
+}
+
+static void pmm_policy_job_control_job_queued( _mali_pmm_internal_state_t *pmm )
+{
+ mali_pmm_core_mask cores;
+ mali_pmm_core_mask cores_subset;
+
+ /* Make sure that all cores are powered in this
+ * simple policy
+ */
+ cores = pmm->cores_registered;
+ cores_subset = pmm_cores_to_power_up( pmm, cores );
+ if( cores_subset != 0 )
+ {
+ /* There are some cores that need powering up */
+ if( !pmm_invoke_power_up( pmm ) )
+ {
+ /* Need to wait until finished */
+ pmm->status = MALI_PMM_STATUS_POLICY_POWER_UP;
+ }
+ }
+}
+
+_mali_osk_errcode_t pmm_policy_process_job_control( _mali_pmm_internal_state_t *pmm, mali_pmm_message_t *event )
+{
+ mali_pmm_core_mask cores;
+ mali_pmm_core_mask cores_subset;
+ MALI_DEBUG_ASSERT_POINTER(pmm);
+ MALI_DEBUG_ASSERT_POINTER(event);
+ MALI_DEBUG_ASSERT_POINTER(data_job_control);
+
+ MALIPMM_DEBUG_PRINT( ("PMM: Job control policy process start - status=%d\n", pmm->status) );
+
+ /* Mainly the data is the cores */
+ cores = pmm_cores_from_event_data( pmm, event );
+
+#if MALI_STATE_TRACKING
+ pmm->mali_last_pmm_status = pmm->status;
+#endif /* MALI_STATE_TRACKING */
+
+ switch( pmm->status )
+ {
+ /**************** IDLE ****************/
+ case MALI_PMM_STATUS_IDLE:
+ switch( event->id )
+ {
+ case MALI_PMM_EVENT_OS_POWER_UP:
+ /* Not expected in this state */
+ break;
+
+ case MALI_PMM_EVENT_JOB_SCHEDULED:
+
+ /* Update idle cores to indicate active - remove these! */
+ pmm_cores_set_active( pmm, cores );
+ /* Remember when this happened */
+ data_job_control->core_active_start = event->ts;
+#if MALI_POWER_MGMT_TEST_SUITE
+ _mali_osk_pmm_policy_events_notifications(MALI_PMM_EVENT_JOB_SCHEDULED);
+#endif
+
+ /*** FALL THROUGH to QUEUED to check POWER UP ***/
+
+ case MALI_PMM_EVENT_JOB_QUEUED:
+
+ pmm_policy_job_control_job_queued( pmm );
+#if MALI_POWER_MGMT_TEST_SUITE
+ _mali_osk_pmm_policy_events_notifications(MALI_PMM_EVENT_JOB_QUEUED);
+#endif
+ break;
+
+ case MALI_PMM_EVENT_DVFS_PAUSE:
+
+ cores_subset = pmm_cores_to_power_down( pmm, cores, MALI_FALSE );
+ if ( cores_subset != 0 )
+ {
+ if ( !pmm_power_down_okay( pmm ) )
+ {
+ pmm->is_dvfs_active = 1;
+ pmm->status = MALI_PMM_STATUS_OS_POWER_DOWN;
+ pmm_save_os_event_data( pmm, event->data );
+ break;
+ }
+ }
+ pmm->status = MALI_PMM_STATUS_DVFS_PAUSE;
+ _mali_osk_pmm_dvfs_operation_done(0);
+ break;
+
+ case MALI_PMM_EVENT_OS_POWER_DOWN:
+
+ /* Need to power down all cores even if we need to wait for them */
+ cores_subset = pmm_cores_to_power_down( pmm, cores, MALI_FALSE );
+ if( cores_subset != 0 )
+ {
+ /* There are some cores that need powering down */
+ if( !pmm_invoke_power_down( pmm ) )
+ {
+ /* We need to wait until they are idle */
+
+ pmm->status = MALI_PMM_STATUS_OS_POWER_DOWN;
+ /* Save the OS data to respond later */
+ pmm_save_os_event_data( pmm, event->data );
+ /* Exit this case - as we have to wait */
+ break;
+ }
+ }
+ /* Set waiting status */
+ pmm->status = MALI_PMM_STATUS_OS_WAITING;
+ /* All cores now down - respond to OS power event */
+ _mali_osk_pmm_power_down_done( event->data );
+ break;
+
+ case MALI_PMM_EVENT_JOB_FINISHED:
+
+ /* Update idle cores - add these! */
+ pmm_cores_set_idle( pmm, cores );
+#if MALI_POWER_MGMT_TEST_SUITE
+ _mali_osk_pmm_policy_events_notifications(MALI_PMM_EVENT_JOB_FINISHED);
+#endif
+ if( data_job_control->timeout > 0 )
+ {
+ /* Wait for time out to fire */
+ break;
+ }
+ /* For job control policy - turn off all cores */
+ cores = pmm->cores_powered;
+
+ /*** FALL THROUGH to TIMEOUT TEST as NO TIMEOUT ***/
+
+ case MALI_PMM_EVENT_TIMEOUT:
+
+ /* Main job control policy - turn off cores after inactivity */
+ if( job_control_timeout_valid( pmm, &data_job_control->latency, (u32)event->data ) )
+ {
+ /* Valid timeout of inactivity - so find out if we can power down
+ * immedately - if we can't then this means the cores are still in fact
+ * active
+ */
+ cores_subset = pmm_cores_to_power_down( pmm, cores, MALI_TRUE );
+ if( cores_subset != 0 )
+ {
+ /* Check if we can really power down, if not then we are not
+ * really in-active
+ */
+ if( !pmm_invoke_power_down( pmm ) )
+ {
+ pmm_power_down_cancel( pmm );
+ }
+ }
+ /* else there are no cores powered up! */
+ }
+#if MALI_POWER_MGMT_TEST_SUITE
+ _mali_osk_pmm_policy_events_notifications(MALI_PMM_EVENT_TIMEOUT);
+#endif
+ break;
+
+ default:
+ /* Unexpected event */
+ MALI_ERROR(_MALI_OSK_ERR_ITEM_NOT_FOUND);
+ }
+ break;
+
+ /******************DVFS PAUSE**************/
+ case MALI_PMM_STATUS_DVFS_PAUSE:
+ switch ( event->id )
+ {
+ case MALI_PMM_EVENT_DVFS_RESUME:
+
+ if ( pmm->cores_powered != 0 )
+ {
+ pmm->cores_ack_down =0;
+ pmm_power_down_cancel( pmm );
+ pmm->status = MALI_PMM_STATUS_IDLE;
+ }
+ else
+ {
+ pmm_policy_job_control_job_queued( pmm );
+ }
+ _mali_osk_pmm_dvfs_operation_done( 0 );
+ break;
+
+ case MALI_PMM_EVENT_OS_POWER_DOWN:
+ /* Set waiting status */
+ pmm->status = MALI_PMM_STATUS_OS_WAITING;
+ if ( pmm->cores_powered != 0 )
+ {
+ if ( pmm_invoke_power_down( pmm ) )
+ {
+ _mali_osk_pmm_power_down_done( 0 );
+ break;
+ }
+ }
+ _mali_osk_pmm_power_down_done( 0 );
+ break;
+ default:
+ break;
+ }
+ break;
+
+ /**************** POWER UP ****************/
+ case MALI_PMM_STATUS_OS_POWER_UP:
+ case MALI_PMM_STATUS_POLICY_POWER_UP:
+ switch( event->id )
+ {
+ case MALI_PMM_EVENT_INTERNAL_POWER_UP_ACK:
+ /* Make sure cores powered off equal what we expect */
+ MALI_DEBUG_ASSERT( cores == pmm->cores_pend_up );
+ pmm_cores_set_up_ack( pmm, cores );
+
+ if( pmm_invoke_power_up( pmm ) )
+ {
+ if( pmm->status == MALI_PMM_STATUS_OS_POWER_UP )
+ {
+ /* Get the OS data and respond to the power up */
+ _mali_osk_pmm_power_up_done( pmm_retrieve_os_event_data( pmm ) );
+ }
+ pmm->status = MALI_PMM_STATUS_IDLE;
+ }
+ break;
+
+ default:
+ /* Unexpected event */
+ MALI_ERROR(_MALI_OSK_ERR_ITEM_NOT_FOUND);
+ }
+ break;
+
+ /**************** POWER DOWN ****************/
+ case MALI_PMM_STATUS_OS_POWER_DOWN:
+ case MALI_PMM_STATUS_POLICY_POWER_DOWN:
+ switch( event->id )
+ {
+
+ case MALI_PMM_EVENT_INTERNAL_POWER_DOWN_ACK:
+
+ pmm_cores_set_down_ack( pmm, cores );
+
+ if ( pmm->is_dvfs_active == 1 )
+ {
+ if( pmm_power_down_okay( pmm ) )
+ {
+ pmm->is_dvfs_active = 0;
+ pmm->status = MALI_PMM_STATUS_DVFS_PAUSE;
+ _mali_osk_pmm_dvfs_operation_done( pmm_retrieve_os_event_data( pmm ) );
+ }
+ break;
+ }
+
+ /* Now check if we can power down */
+ if( pmm_invoke_power_down( pmm ) )
+ {
+ if( pmm->status == MALI_PMM_STATUS_OS_POWER_DOWN )
+ {
+ /* Get the OS data and respond to the power down */
+ _mali_osk_pmm_power_down_done( pmm_retrieve_os_event_data( pmm ) );
+ }
+ pmm->status = MALI_PMM_STATUS_OS_WAITING;
+ }
+ break;
+
+ default:
+ /* Unexpected event */
+ MALI_ERROR(_MALI_OSK_ERR_ITEM_NOT_FOUND);
+ }
+ break;
+
+ case MALI_PMM_STATUS_OS_WAITING:
+ switch( event->id )
+ {
+ case MALI_PMM_EVENT_OS_POWER_UP:
+ cores_subset = pmm_cores_to_power_up( pmm, cores );
+ if( cores_subset != 0 )
+ {
+ /* There are some cores that need powering up */
+ if( !pmm_invoke_power_up( pmm ) )
+ {
+ /* Need to wait until power up complete */
+ pmm->status = MALI_PMM_STATUS_OS_POWER_UP;
+ /* Save the OS data to respond later */
+ pmm_save_os_event_data( pmm, event->data );
+ /* Exit this case - as we have to wait */
+ break;
+ }
+ }
+ pmm->status = MALI_PMM_STATUS_IDLE;
+ /* All cores now up - respond to OS power up event */
+ _mali_osk_pmm_power_up_done( event->data );
+ break;
+
+ default:
+ /* All other messages are ignored in this state */
+ break;
+ }
+ break;
+
+ default:
+ /* Unexpected state */
+ MALI_ERROR(_MALI_OSK_ERR_FAULT);
+ }
+
+ /* Set in-activity latency timer - if required */
+ job_control_timeout_setup( pmm, &data_job_control->latency );
+
+ /* Update the PMM state */
+ pmm_update_system_state( pmm );
+#if MALI_STATE_TRACKING
+ pmm->mali_new_event_status = event->id;
+#endif /* MALI_STATE_TRACKING */
+
+ MALIPMM_DEBUG_PRINT( ("PMM: Job control policy process end - status=%d and event=%d\n", pmm->status,event->id) );
+
+ MALI_SUCCESS;
+}
+
+void pmm_policy_check_job_control()
+{
+ MALI_DEBUG_ASSERT_POINTER(data_job_control);
+
+ /* Latency timer must have expired raise the event */
+ pmm_policy_timer_raise_event(&data_job_control->latency);
+}
+
+
+#endif /* USING_MALI_PMM */
diff --git a/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm_policy_jobcontrol.h b/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm_policy_jobcontrol.h
new file mode 100644
index 00000000000..455234b80bc
--- /dev/null
+++ b/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm_policy_jobcontrol.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2010-2011 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * @file mali_pmm_policy.h
+ * Defines the power management module policies
+ */
+
+#ifndef __MALI_PMM_POLICY_JOBCONTROL_H__
+#define __MALI_PMM_POLICY_JOBCONTROL_H__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * @addtogroup pmmapi_policy Power Management Module Policies
+ *
+ * @{
+ */
+
+/** @brief The jobcontrol policy inactivity latency timeout (in ticks)
+ * before the hardware is switched off
+ *
+ * @note Setting this low whilst tracing or producing debug output can
+ * cause alot of timeouts to fire which can affect the PMM behaviour
+ */
+#define MALI_PMM_POLICY_JOBCONTROL_INACTIVITY_TIMEOUT 50
+
+/** @brief Job control policy initialization
+ *
+ * @return _MALI_OSK_ERR_OK if the policy could be initialized, or a suitable
+ * _mali_osk_errcode_t otherwise.
+ */
+_mali_osk_errcode_t pmm_policy_init_job_control(_mali_pmm_internal_state_t *pmm);
+
+/** @brief Job control policy termination
+ */
+void pmm_policy_term_job_control(void);
+
+/** @brief Job control policy state changer
+ *
+ * Given the next available event message, this routine processes it
+ * for the policy and changes state as needed.
+ *
+ * Job control policy depends on events from the Mali cores, and will
+ * power down all cores after an inactivity latency timeout. It will
+ * power the cores back on again when a job is scheduled to run.
+ *
+ * @param pmm internal PMM state
+ * @param event PMM event to process
+ * @return _MALI_OSK_ERR_OK if the policy state completed okay, or a suitable
+ * _mali_osk_errcode_t otherwise.
+ */
+_mali_osk_errcode_t pmm_policy_process_job_control( _mali_pmm_internal_state_t *pmm, mali_pmm_message_t *event );
+
+/** @brief Job control policy checker
+ *
+ * The latency timer has fired and we need to raise the correct event to
+ * handle it
+ *
+ * @param pmm internal PMM state
+ */
+void pmm_policy_check_job_control(void);
+
+/** @} */ /* End group pmmapi_policy */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MALI_PMM_POLICY_JOBCONTROL_H__ */
diff --git a/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm_state.c b/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm_state.c
new file mode 100644
index 00000000000..a0ac1c7790c
--- /dev/null
+++ b/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm_state.c
@@ -0,0 +1,718 @@
+/*
+ * Copyright (C) 2010-2011 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * @file mali_pmm_state.c
+ * Implementation of the power management module internal state
+ */
+
+#if USING_MALI_PMM
+
+#include "mali_ukk.h"
+#include "mali_kernel_common.h"
+#include "mali_kernel_subsystem.h"
+
+#include "mali_pmm.h"
+#include "mali_pmm_state.h"
+#include "mali_pmm_system.h"
+
+#include "mali_kernel_core.h"
+#include "mali_platform.h"
+
+#define SIZEOF_CORES_LIST 6
+
+/* NOTE: L2 *MUST* be first on the list so that it
+ * is correctly powered on first and powered off last
+ */
+static mali_pmm_core_id cores_list[] = { MALI_PMM_CORE_L2,
+ MALI_PMM_CORE_GP,
+ MALI_PMM_CORE_PP0,
+ MALI_PMM_CORE_PP1,
+ MALI_PMM_CORE_PP2,
+ MALI_PMM_CORE_PP3 };
+
+
+
+void pmm_update_system_state( _mali_pmm_internal_state_t *pmm )
+{
+ mali_pmm_state state;
+
+ MALI_DEBUG_ASSERT_POINTER(pmm);
+
+ if( pmm->cores_registered == 0 )
+ {
+ state = MALI_PMM_STATE_UNAVAILABLE;
+ }
+ else if( pmm->cores_powered == 0 )
+ {
+ state = MALI_PMM_STATE_SYSTEM_OFF;
+ }
+ else if( pmm->cores_powered == pmm->cores_registered )
+ {
+ state = MALI_PMM_STATE_SYSTEM_ON;
+ }
+ else
+ {
+ /* Some other state where not everything is on or off */
+ state = MALI_PMM_STATE_SYSTEM_TRANSITION;
+ }
+
+#if MALI_PMM_TRACE
+ _mali_pmm_trace_state_change( pmm->state, state );
+#endif
+ pmm->state = state;
+}
+
+mali_pmm_core_mask pmm_cores_from_event_data( _mali_pmm_internal_state_t *pmm, mali_pmm_message_t *event )
+{
+ mali_pmm_core_mask cores;
+ MALI_DEBUG_ASSERT_POINTER(pmm);
+ MALI_DEBUG_ASSERT_POINTER(event);
+
+ switch( event->id )
+ {
+ case MALI_PMM_EVENT_OS_POWER_UP:
+ case MALI_PMM_EVENT_OS_POWER_DOWN:
+ /* All cores - the system */
+ cores = pmm->cores_registered;
+ break;
+
+ case MALI_PMM_EVENT_JOB_SCHEDULED:
+ case MALI_PMM_EVENT_JOB_QUEUED:
+ case MALI_PMM_EVENT_JOB_FINISHED:
+ case MALI_PMM_EVENT_INTERNAL_POWER_UP_ACK:
+ case MALI_PMM_EVENT_INTERNAL_POWER_DOWN_ACK:
+ /* Currently the main event data is only the cores
+ * for these messages
+ */
+ cores = (mali_pmm_core_mask)event->data;
+ if( cores == MALI_PMM_CORE_SYSTEM )
+ {
+ cores = pmm->cores_registered;
+ }
+ else if( cores == MALI_PMM_CORE_PP_ALL )
+ {
+ /* Get the subset of registered PP cores */
+ cores = (pmm->cores_registered & MALI_PMM_CORE_PP_ALL);
+ }
+ MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, cores );
+ break;
+
+ default:
+ /* Assume timeout messages - report cores still powered */
+ cores = pmm->cores_powered;
+ break;
+ }
+
+ return cores;
+}
+
+mali_pmm_core_mask pmm_cores_to_power_up( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores )
+{
+ mali_pmm_core_mask cores_subset;
+ MALI_DEBUG_ASSERT_POINTER(pmm);
+ MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, cores );
+
+ /* Check that cores aren't pending power down when asked for power up */
+ MALI_DEBUG_ASSERT( pmm->cores_pend_down == 0 );
+
+ cores_subset = (~(pmm->cores_powered) & cores);
+ if( cores_subset != 0 )
+ {
+ /* There are some cores that need powering up */
+ pmm->cores_pend_up = cores_subset;
+ }
+
+ return cores_subset;
+}
+
+mali_pmm_core_mask pmm_cores_to_power_down( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores, mali_bool immediate_only )
+{
+ mali_pmm_core_mask cores_subset;
+ _mali_osk_errcode_t err;
+ MALI_DEBUG_ASSERT_POINTER(pmm);
+ MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, cores );
+
+ /* Check that cores aren't pending power up when asked for power down */
+ MALI_DEBUG_ASSERT( pmm->cores_pend_up == 0 );
+
+ cores_subset = (pmm->cores_powered & cores);
+ if( cores_subset != 0 )
+ {
+ int n;
+ volatile mali_pmm_core_mask *ppowered = &(pmm->cores_powered);
+
+ /* There are some cores that need powering up, but we may
+ * need to wait until they are idle
+ */
+ for( n = SIZEOF_CORES_LIST-1; n >= 0; n-- )
+ {
+ if( (cores_list[n] & cores_subset) != 0 )
+ {
+ /* Core is to be powered down */
+ pmm->cores_pend_down |= cores_list[n];
+
+ /* Can't hold the power lock, when acessing subsystem mutex via
+ * the core power call.
+ * Due to terminatation of driver requiring a subsystem mutex
+ * and then power lock held to unregister a core.
+ * This does mean that the following function could fail
+ * as the core is unregistered before we tell it to power
+ * down, but it does not matter as we are terminating
+ */
+#if MALI_STATE_TRACKING
+ pmm->mali_pmm_lock_acquired = 0;
+#endif /* MALI_STATE_TRACKING */
+
+ MALI_PMM_UNLOCK(pmm);
+ /* Signal the core to power down
+ * If it is busy (not idle) it will set a pending power down flag
+ * (as long as we don't want to only immediately power down).
+ * If it isn't busy it will move out of the idle queue right
+ * away
+ */
+ err = mali_core_signal_power_down( cores_list[n], immediate_only );
+ MALI_PMM_LOCK(pmm);
+
+#if MALI_STATE_TRACKING
+ pmm->mali_pmm_lock_acquired = 1;
+#endif /* MALI_STATE_TRACKING */
+
+
+ /* Re-read cores_subset in case it has changed */
+ cores_subset = (*ppowered & cores);
+
+ if( err == _MALI_OSK_ERR_OK )
+ {
+ /* We moved an idle core to the power down queue
+ * which means it is now acknowledged (if it is still
+ * registered)
+ */
+ pmm->cores_ack_down |= (cores_list[n] & cores_subset);
+ }
+ else
+ {
+ MALI_DEBUG_ASSERT( err == _MALI_OSK_ERR_BUSY ||
+ (err == _MALI_OSK_ERR_FAULT &&
+ (*ppowered & cores_list[n]) == 0) );
+ /* If we didn't move a core - it must be active, so
+ * leave it pending, so we get an acknowledgement (when
+ * not in immediate only mode)
+ * Alternatively we are shutting down and the core has
+ * been unregistered
+ */
+ }
+ }
+ }
+ }
+
+ return cores_subset;
+}
+
+void pmm_power_down_cancel( _mali_pmm_internal_state_t *pmm )
+{
+ int n;
+ mali_pmm_core_mask pd, ad;
+ _mali_osk_errcode_t err;
+ volatile mali_pmm_core_mask *pregistered;
+
+ MALI_DEBUG_ASSERT_POINTER(pmm);
+
+ MALIPMM_DEBUG_PRINT( ("PMM: Cancelling power down\n") );
+
+ pd = pmm->cores_pend_down;
+ ad = pmm->cores_ack_down;
+ /* Clear the pending cores so that they don't move to the off
+ * queue if they haven't already
+ */
+ pmm->cores_pend_down = 0;
+ pmm->cores_ack_down = 0;
+ pregistered = &(pmm->cores_registered);
+
+ /* Power up all the pending power down cores - just so
+ * we make sure the system is in a known state, as a
+ * pending core might have sent an acknowledged message
+ * which hasn't been read yet.
+ */
+ for( n = 0; n < SIZEOF_CORES_LIST; n++ )
+ {
+ if( (cores_list[n] & pd) != 0 )
+ {
+ /* Can't hold the power lock, when acessing subsystem mutex via
+ * the core power call.
+ * Due to terminatation of driver requiring a subsystem mutex
+ * and then power lock held to unregister a core.
+ * This does mean that the following power up function could fail
+ * as the core is unregistered before we tell it to power
+ * up, but it does not matter as we are terminating
+ */
+#if MALI_STATE_TRACKING
+ pmm->mali_pmm_lock_acquired = 0;
+#endif /* MALI_STATE_TRACKING */
+
+ MALI_PMM_UNLOCK(pmm);
+ /* As we are cancelling - only move the cores back to the queue -
+ * no reset needed
+ */
+ err = mali_core_signal_power_up( cores_list[n], MALI_TRUE );
+ MALI_PMM_LOCK(pmm);
+#if MALI_STATE_TRACKING
+ pmm->mali_pmm_lock_acquired = 1;
+#endif /* MALI_STATE_TRACKING */
+
+ /* Update pending list with the current registered cores */
+ pd &= (*pregistered);
+
+ if( err != _MALI_OSK_ERR_OK )
+ {
+ MALI_DEBUG_ASSERT( (err == _MALI_OSK_ERR_BUSY &&
+ ((cores_list[n] & ad) == 0)) ||
+ (err == _MALI_OSK_ERR_FAULT &&
+ (*pregistered & cores_list[n]) == 0) );
+ /* If we didn't power up a core - it must be active and
+ * hasn't actually tried to power down - this is expected
+ * for cores that haven't acknowledged
+ * Alternatively we are shutting down and the core has
+ * been unregistered
+ */
+ }
+ }
+ }
+ /* Only used in debug builds */
+ MALI_IGNORE(ad);
+}
+
+
+mali_bool pmm_power_down_okay( _mali_pmm_internal_state_t *pmm )
+{
+ MALI_DEBUG_ASSERT_POINTER(pmm);
+
+ return ( pmm->cores_pend_down == pmm->cores_ack_down ? MALI_TRUE : MALI_FALSE );
+}
+
+mali_bool pmm_invoke_power_down( _mali_pmm_internal_state_t *pmm )
+{
+ _mali_osk_errcode_t err;
+ MALI_DEBUG_ASSERT_POINTER(pmm);
+
+ /* Check that cores are pending power down during power down invoke */
+ MALI_DEBUG_ASSERT( pmm->cores_pend_down != 0 );
+ /* Check that cores are not pending power up during power down invoke */
+ MALI_DEBUG_ASSERT( pmm->cores_pend_up == 0 );
+
+ if( !pmm_power_down_okay( pmm ) )
+ {
+ MALIPMM_DEBUG_PRINT( ("PMM: Waiting for cores to go idle for power off - 0x%08x / 0x%08x\n",
+ pmm->cores_pend_down, pmm->cores_ack_down) );
+ return MALI_FALSE;
+ }
+ else
+ {
+#if !MALI_PMM_NO_PMU
+ err = mali_platform_powerdown( pmm->cores_pend_down );
+#else
+ err = _MALI_OSK_ERR_OK;
+#endif
+
+ if( err == _MALI_OSK_ERR_OK )
+ {
+#if MALI_PMM_TRACE
+ mali_pmm_core_mask old_power = pmm->cores_powered;
+#endif
+ /* Remove powered down cores from idle and powered list */
+ pmm->cores_powered &= ~(pmm->cores_pend_down);
+ pmm->cores_idle &= ~(pmm->cores_pend_down);
+ /* Reset pending/acknowledged status */
+ pmm->cores_pend_down = 0;
+ pmm->cores_ack_down = 0;
+#if MALI_PMM_TRACE
+ _mali_pmm_trace_hardware_change( old_power, pmm->cores_powered );
+#endif
+ }
+ else
+ {
+ MALI_PRINT_ERROR( ("PMM: Failed to get PMU to power down cores - (0x%x) %s",
+ pmm->cores_pend_down, pmm_trace_get_core_name(pmm->cores_pend_down)) );
+ pmm->fatal_power_err = MALI_TRUE;
+ }
+ }
+
+ return MALI_TRUE;
+}
+
+
+mali_bool pmm_power_up_okay( _mali_pmm_internal_state_t *pmm )
+{
+ MALI_DEBUG_ASSERT_POINTER(pmm);
+
+ return ( pmm->cores_pend_up == pmm->cores_ack_up ? MALI_TRUE : MALI_FALSE );
+}
+
+
+mali_bool pmm_invoke_power_up( _mali_pmm_internal_state_t *pmm )
+{
+ _mali_osk_errcode_t err;
+
+ MALI_DEBUG_ASSERT_POINTER(pmm);
+
+ /* Check that cores are pending power up during power up invoke */
+ MALI_DEBUG_ASSERT( pmm->cores_pend_up != 0 );
+ /* Check that cores are not pending power down during power up invoke */
+ MALI_DEBUG_ASSERT( pmm->cores_pend_down == 0 );
+
+ if( pmm_power_up_okay( pmm ) )
+ {
+ /* Power up has completed - sort out subsystem core status */
+
+ int n;
+ /* Use volatile to access, so that it is updated if any cores are unregistered */
+ volatile mali_pmm_core_mask *ppendup = &(pmm->cores_pend_up);
+#if MALI_PMM_TRACE
+ mali_pmm_core_mask old_power = pmm->cores_powered;
+#endif
+ /* Move cores into idle queues */
+ for( n = 0; n < SIZEOF_CORES_LIST; n++ )
+ {
+ if( (cores_list[n] & (*ppendup)) != 0 )
+ {
+ /* Can't hold the power lock, when acessing subsystem mutex via
+ * the core power call.
+ * Due to terminatation of driver requiring a subsystem mutex
+ * and then power lock held to unregister a core.
+ * This does mean that the following function could fail
+ * as the core is unregistered before we tell it to power
+ * up, but it does not matter as we are terminating
+ */
+#if MALI_STATE_TRACKING
+ pmm->mali_pmm_lock_acquired = 0;
+#endif /* MALI_STATE_TRACKING */
+
+ MALI_PMM_UNLOCK(pmm);
+ err = mali_core_signal_power_up( cores_list[n], MALI_FALSE );
+ MALI_PMM_LOCK(pmm);
+
+#if MALI_STATE_TRACKING
+ pmm->mali_pmm_lock_acquired = 1;
+#endif /* MALI_STATE_TRACKING */
+
+
+ if( err != _MALI_OSK_ERR_OK )
+ {
+ MALI_DEBUG_ASSERT( (err == _MALI_OSK_ERR_FAULT &&
+ (*ppendup & cores_list[n]) == 0) );
+ /* We only expect this to fail when we are shutting down
+ * and the core has been unregistered
+ */
+ }
+ }
+ }
+ /* Finished power up - add cores to idle and powered list */
+ pmm->cores_powered |= (*ppendup);
+ pmm->cores_idle |= (*ppendup);
+ /* Reset pending/acknowledge status */
+ pmm->cores_pend_up = 0;
+ pmm->cores_ack_up = 0;
+
+#if MALI_PMM_TRACE
+ _mali_pmm_trace_hardware_change( old_power, pmm->cores_powered );
+#endif
+ return MALI_TRUE;
+ }
+ else
+ {
+#if !MALI_PMM_NO_PMU
+ /* Power up must now be done */
+ err = mali_platform_powerup( pmm->cores_pend_up );
+#else
+ err = _MALI_OSK_ERR_OK;
+#endif
+ if( err != _MALI_OSK_ERR_OK )
+ {
+ MALI_PRINT_ERROR( ("PMM: Failed to get PMU to power up cores - (0x%x) %s",
+ pmm->cores_pend_up, pmm_trace_get_core_name(pmm->cores_pend_up)) );
+ pmm->fatal_power_err = MALI_TRUE;
+ }
+ else
+ {
+ /* TBD - Update core status immediately rather than use event message */
+ _mali_uk_pmm_message_s event = {
+ NULL,
+ MALI_PMM_EVENT_INTERNAL_POWER_UP_ACK,
+ 0 };
+ /* All the cores that were pending power up, have now completed power up */
+ event.data = pmm->cores_pend_up;
+ _mali_ukk_pmm_event_message( &event );
+ MALIPMM_DEBUG_PRINT( ("PMM: Sending ACK to power up") );
+ }
+ }
+
+ /* Always return false, as we need an interrupt to acknowledge
+ * when power up is complete
+ */
+ return MALI_FALSE;
+}
+
+mali_pmm_core_mask pmm_cores_set_active( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores )
+{
+ MALI_DEBUG_ASSERT_POINTER(pmm);
+ MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, cores );
+
+ pmm->cores_idle &= (~cores);
+ return pmm->cores_idle;
+}
+
+mali_pmm_core_mask pmm_cores_set_idle( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores )
+{
+ MALI_DEBUG_ASSERT_POINTER(pmm);
+ MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, cores );
+
+ pmm->cores_idle |= (cores);
+ return pmm->cores_idle;
+}
+
+mali_pmm_core_mask pmm_cores_set_down_ack( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores )
+{
+ MALI_DEBUG_ASSERT_POINTER(pmm);
+ MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, cores );
+
+ /* Check core is not pending a power down */
+ MALI_DEBUG_ASSERT( (pmm->cores_pend_down & cores) != 0 );
+ /* Check core has not acknowledged power down more than once */
+ MALI_DEBUG_ASSERT( (pmm->cores_ack_down & cores) == 0 );
+
+ pmm->cores_ack_down |= (cores);
+
+ return pmm->cores_ack_down;
+}
+
+void pmm_fatal_reset( _mali_pmm_internal_state_t *pmm )
+{
+ _mali_osk_errcode_t err = _MALI_OSK_ERR_OK;
+ _mali_osk_notification_t *msg = NULL;
+ mali_pmm_status status;
+ MALI_DEBUG_ASSERT_POINTER(pmm);
+ MALIPMM_DEBUG_PRINT( ("PMM: Fatal Reset called") );
+
+ MALI_DEBUG_ASSERT( pmm->status != MALI_PMM_STATUS_OFF );
+
+ /* Reset the common status */
+ pmm->waiting = 0;
+ pmm->missed = 0;
+ pmm->fatal_power_err = MALI_FALSE;
+ pmm->no_events = 0;
+ pmm->check_policy = MALI_FALSE;
+ pmm->cores_pend_down = 0;
+ pmm->cores_pend_up = 0;
+ pmm->cores_ack_down = 0;
+ pmm->cores_ack_up = 0;
+ pmm->is_dvfs_active = 0;
+#if MALI_PMM_TRACE
+ pmm->messages_sent = 0;
+ pmm->messages_received = 0;
+ pmm->imessages_sent = 0;
+ pmm->imessages_received = 0;
+ MALI_PRINT( ("PMM Trace: *** Fatal reset occurred ***") );
+#endif
+
+ /* Set that we are unavailable whilst resetting */
+ pmm->state = MALI_PMM_STATE_UNAVAILABLE;
+ status = pmm->status;
+ pmm->status = MALI_PMM_STATUS_OFF;
+
+ /* We want all cores powered */
+ pmm->cores_powered = pmm->cores_registered;
+ /* The cores may not be idle, but this state will be rectified later */
+ pmm->cores_idle = pmm->cores_registered;
+
+ /* So power on any cores that are registered */
+ if( pmm->cores_registered != 0 )
+ {
+ int n;
+ volatile mali_pmm_core_mask *pregistered = &(pmm->cores_registered);
+#if !MALI_PMM_NO_PMU
+ err = mali_platform_powerup( pmm->cores_registered );
+#endif
+ if( err != _MALI_OSK_ERR_OK )
+ {
+ /* This is very bad as we can't even be certain the cores are now
+ * powered up
+ */
+ MALI_PRINT_ERROR( ("PMM: Failed to perform PMM reset!\n") );
+ /* TBD driver exit? */
+ }
+
+ for( n = SIZEOF_CORES_LIST-1; n >= 0; n-- )
+ {
+ if( (cores_list[n] & (*pregistered)) != 0 )
+ {
+#if MALI_STATE_TRACKING
+ pmm->mali_pmm_lock_acquired = 0;
+#endif /* MALI_STATE_TRACKING */
+
+ MALI_PMM_UNLOCK(pmm);
+ /* Core is now active - so try putting it in the idle queue */
+ err = mali_core_signal_power_up( cores_list[n], MALI_FALSE );
+ MALI_PMM_LOCK(pmm);
+#if MALI_STATE_TRACKING
+ pmm->mali_pmm_lock_acquired = 1;
+#endif /* MALI_STATE_TRACKING */
+
+ /* We either succeeded, or we were not off anyway, or we have
+ * just be deregistered
+ */
+ MALI_DEBUG_ASSERT( (err == _MALI_OSK_ERR_OK) ||
+ (err == _MALI_OSK_ERR_BUSY) ||
+ (err == _MALI_OSK_ERR_FAULT &&
+ (*pregistered & cores_list[n]) == 0) );
+ }
+ }
+ }
+
+ /* Unblock any pending OS event */
+ if( status == MALI_PMM_STATUS_OS_POWER_UP )
+ {
+ /* Get the OS data and respond to the power up */
+ _mali_osk_pmm_power_up_done( pmm_retrieve_os_event_data( pmm ) );
+ }
+ if( status == MALI_PMM_STATUS_OS_POWER_DOWN )
+ {
+ /* Get the OS data and respond to the power down
+ * NOTE: We are not powered down at this point due to power problems,
+ * so we are lying to the system, but something bad has already
+ * happened and we are trying unstick things
+ * TBD - Add busy loop to power down cores?
+ */
+ _mali_osk_pmm_power_down_done( pmm_retrieve_os_event_data( pmm ) );
+ }
+
+ /* Purge the event queues */
+ do
+ {
+ if( _mali_osk_notification_queue_dequeue( pmm->iqueue, &msg ) == _MALI_OSK_ERR_OK )
+ {
+ _mali_osk_notification_delete ( msg );
+ break;
+ }
+ } while (MALI_TRUE);
+
+ do
+ {
+ if( _mali_osk_notification_queue_dequeue( pmm->queue, &msg ) == _MALI_OSK_ERR_OK )
+ {
+ _mali_osk_notification_delete ( msg );
+ break;
+ }
+ } while (MALI_TRUE);
+
+ /* Return status/state to normal */
+ pmm->status = MALI_PMM_STATUS_IDLE;
+ pmm_update_system_state(pmm);
+}
+
+mali_pmm_core_mask pmm_cores_set_up_ack( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores )
+{
+ MALI_DEBUG_ASSERT_POINTER(pmm);
+ MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, cores );
+
+ /* Check core is not pending a power up */
+ MALI_DEBUG_ASSERT( (pmm->cores_pend_up & cores) != 0 );
+ /* Check core has not acknowledged power up more than once */
+ MALI_DEBUG_ASSERT( (pmm->cores_ack_up & cores) == 0 );
+
+ pmm->cores_ack_up |= (cores);
+
+ return pmm->cores_ack_up;
+}
+
+void pmm_save_os_event_data(_mali_pmm_internal_state_t *pmm, mali_pmm_message_data data)
+{
+ MALI_DEBUG_ASSERT_POINTER(pmm);
+ /* Check that there is no saved data */
+ MALI_DEBUG_ASSERT( pmm->os_data == 0 );
+ /* Can't store zero data - as retrieve check will fail */
+ MALI_DEBUG_ASSERT( data != 0 );
+
+ pmm->os_data = data;
+}
+
+mali_pmm_message_data pmm_retrieve_os_event_data(_mali_pmm_internal_state_t *pmm)
+{
+ mali_pmm_message_data data;
+
+ MALI_DEBUG_ASSERT_POINTER(pmm);
+ /* Check that there is saved data */
+ MALI_DEBUG_ASSERT( pmm->os_data != 0 );
+
+ /* Get data, and clear the saved version */
+ data = pmm->os_data;
+ pmm->os_data = 0;
+
+ return data;
+}
+
+/* Create list of core names to look up
+ * We are doing it this way to overcome the need for
+ * either string allocation, or stack space, so we
+ * use constant strings instead
+ */
+typedef struct pmm_trace_corelist
+{
+ mali_pmm_core_mask id;
+ const char *name;
+} pmm_trace_corelist_t;
+
+static pmm_trace_corelist_t pmm_trace_cores[] = {
+ { MALI_PMM_CORE_SYSTEM, "SYSTEM" },
+ { MALI_PMM_CORE_GP, "GP" },
+ { MALI_PMM_CORE_L2, "L2" },
+ { MALI_PMM_CORE_PP0, "PP0" },
+ { MALI_PMM_CORE_PP1, "PP1" },
+ { MALI_PMM_CORE_PP2, "PP2" },
+ { MALI_PMM_CORE_PP3, "PP3" },
+ { MALI_PMM_CORE_PP_ALL, "PP (all)" },
+ { (MALI_PMM_CORE_GP | MALI_PMM_CORE_L2 | MALI_PMM_CORE_PP0),
+ "GP+L2+PP0" },
+ { (MALI_PMM_CORE_GP | MALI_PMM_CORE_PP0),
+ "GP+PP0" },
+ { (MALI_PMM_CORE_GP | MALI_PMM_CORE_L2 | MALI_PMM_CORE_PP0 | MALI_PMM_CORE_PP1),
+ "GP+L2+PP0+PP1" },
+ { (MALI_PMM_CORE_GP | MALI_PMM_CORE_PP0 | MALI_PMM_CORE_PP1),
+ "GP+PP0+PP1" },
+ { 0, NULL } /* Terminator of list */
+};
+
+const char *pmm_trace_get_core_name( mali_pmm_core_mask cores )
+{
+ const char *dname = NULL;
+ int cl;
+
+ /* Look up name in corelist */
+ cl = 0;
+ while( pmm_trace_cores[cl].name != NULL )
+ {
+ if( pmm_trace_cores[cl].id == cores )
+ {
+ dname = pmm_trace_cores[cl].name;
+ break;
+ }
+ cl++;
+ }
+
+ if( dname == NULL )
+ {
+ /* We don't know a good short-hand for the configuration */
+ dname = "[multi-core]";
+ }
+
+ return dname;
+}
+
+#endif /* USING_MALI_PMM */
+
diff --git a/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm_state.h b/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm_state.h
new file mode 100644
index 00000000000..3c8c31f066d
--- /dev/null
+++ b/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm_state.h
@@ -0,0 +1,296 @@
+/*
+ * Copyright (C) 2010-2011 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * @file mali_pmm_state.h
+ * Defines the internal power management module state
+ */
+
+#ifndef __MALI_PMM_STATE_H__
+#define __MALI_PMM_STATE_H__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * @addtogroup pmmapi Power Management Module APIs
+ *
+ * @{
+ *
+ * @defgroup pmmapi_state Power Management Module State
+ *
+ * @{
+ */
+
+/* Check that the subset is really a subset of cores */
+#define MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( cores, subset ) \
+ MALI_DEBUG_ASSERT( ((~(cores)) & (subset)) == 0 )
+
+
+/* Locking macros */
+#define MALI_PMM_LOCK(pmm) \
+ _mali_osk_lock_wait( pmm->lock, _MALI_OSK_LOCKMODE_RW )
+#define MALI_PMM_UNLOCK(pmm) \
+ _mali_osk_lock_signal( pmm->lock, _MALI_OSK_LOCKMODE_RW )
+#define MALI_PMM_LOCK_TERM(pmm) \
+ _mali_osk_lock_term( pmm->lock )
+
+/* Notification type for messages */
+#define MALI_PMM_NOTIFICATION_TYPE 0
+
+/** @brief Status of the PMM state machine
+ */
+typedef enum mali_pmm_status_tag
+{
+ MALI_PMM_STATUS_IDLE, /**< PMM is waiting next event */
+ MALI_PMM_STATUS_POLICY_POWER_DOWN, /**< Policy initiated power down */
+ MALI_PMM_STATUS_POLICY_POWER_UP, /**< Policy initiated power down */
+ MALI_PMM_STATUS_OS_WAITING, /**< PMM is waiting for OS power up */
+ MALI_PMM_STATUS_OS_POWER_DOWN, /**< OS initiated power down */
+ MALI_PMM_STATUS_RUNTIME_IDLE_IN_PROGRESS,
+ MALI_PMM_STATUS_DVFS_PAUSE, /**< PMM DVFS Status Pause */
+ MALI_PMM_STATUS_OS_POWER_UP, /**< OS initiated power up */
+ MALI_PMM_STATUS_OFF, /**< PMM is not active */
+} mali_pmm_status;
+
+
+/** @brief Internal state of the PMM
+ */
+typedef struct _mali_pmm_internal_state
+{
+ mali_pmm_status status; /**< PMM state machine */
+ mali_pmm_policy policy; /**< PMM policy */
+ mali_bool check_policy; /**< PMM policy needs checking */
+ mali_pmm_state state; /**< PMM state */
+ mali_pmm_core_mask cores_registered; /**< Bitmask of cores registered */
+ mali_pmm_core_mask cores_powered; /**< Bitmask of cores powered up */
+ mali_pmm_core_mask cores_idle; /**< Bitmask of cores idle */
+ mali_pmm_core_mask cores_pend_down; /**< Bitmask of cores pending power down */
+ mali_pmm_core_mask cores_pend_up; /**< Bitmask of cores pending power up */
+ mali_pmm_core_mask cores_ack_down; /**< Bitmask of cores acknowledged power down */
+ mali_pmm_core_mask cores_ack_up; /**< Bitmask of cores acknowledged power up */
+
+ _mali_osk_notification_queue_t *queue; /**< PMM event queue */
+ _mali_osk_notification_queue_t *iqueue; /**< PMM internal event queue */
+ _mali_osk_irq_t *irq; /**< PMM irq handler */
+ _mali_osk_lock_t *lock; /**< PMM lock */
+
+ mali_pmm_message_data os_data; /**< OS data sent via the OS events */
+
+ mali_bool pmu_initialized; /**< PMU initialized */
+
+ _mali_osk_atomic_t messages_queued; /**< PMM event messages queued */
+ u32 waiting; /**< PMM waiting events - due to busy */
+ u32 no_events; /**< PMM called to process when no events */
+
+ u32 missed; /**< PMM missed events due to OOM */
+ mali_bool fatal_power_err; /**< PMM has had a fatal power error? */
+ u32 is_dvfs_active; /**< PMM DVFS activity */
+
+#if (defined(DEBUG) || MALI_STATE_TRACKING)
+ u32 mali_last_pmm_status;
+ u32 mali_new_event_status;
+ u32 mali_pmm_lock_acquired;
+#endif
+
+#if (MALI_PMM_TRACE || MALI_STATE_TRACKING)
+ u32 messages_sent; /**< Total event messages sent */
+ u32 messages_received; /**< Total event messages received */
+ u32 imessages_sent; /**< Total event internal messages sent */
+ u32 imessages_received; /**< Total event internal messages received */
+#endif
+} _mali_pmm_internal_state_t;
+
+/** @brief Sets that a policy needs a check before processing events
+ *
+ * A timer or something has expired that needs dealing with
+ */
+void malipmm_set_policy_check(void);
+
+/** @brief Update the PMM externally viewable state depending on the current PMM internal state
+ *
+ * @param pmm internal PMM state
+ * @return MALI_TRUE if the timeout is valid, else MALI_FALSE
+ */
+void pmm_update_system_state( _mali_pmm_internal_state_t *pmm );
+
+/** @brief Returns the core mask from the event data - if applicable
+ *
+ * @param pmm internal PMM state
+ * @param event event message to get the core mask from
+ * @return mask of cores that is relevant to this event message
+ */
+mali_pmm_core_mask pmm_cores_from_event_data( _mali_pmm_internal_state_t *pmm, mali_pmm_message_t *event );
+
+/** @brief Sort out which cores need to be powered up from the given core mask
+ *
+ * All cores that can be powered up will be put into a pending state
+ *
+ * @param pmm internal PMM state
+ * @param cores mask of cores to check if they need to be powered up
+ * @return mask of cores that need to be powered up, this can be 0 if all cores
+ * are powered up already
+ */
+mali_pmm_core_mask pmm_cores_to_power_up( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores );
+
+/** @brief Sort out which cores need to be powered down from the given core mask
+ *
+ * All cores that can be powered down will be put into a pending state. If they
+ * can be powered down immediately they will also be acknowledged that they can be
+ * powered down. If the immediate_only flag is set, then only those cores that
+ * can be acknowledged for power down will be put into a pending state.
+ *
+ * @param pmm internal PMM state
+ * @param cores mask of cores to check if they need to be powered down
+ * @param immediate_only MALI_TRUE means that only cores that can power down now will
+ * be put into a pending state
+ * @return mask of cores that need to be powered down, this can be 0 if all cores
+ * are powered down already
+ */
+mali_pmm_core_mask pmm_cores_to_power_down( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores, mali_bool immediate_only );
+
+/** @brief Cancel an invokation to power down (pmm_invoke_power_down)
+ *
+ * @param pmm internal PMM state
+ */
+void pmm_power_down_cancel( _mali_pmm_internal_state_t *pmm );
+
+/** @brief Check if a call to invoke power down should succeed, or fail
+ *
+ * This will report MALI_FALSE if some of the cores are still active and need
+ * to acknowledge that they are ready to power down
+ *
+ * @param pmm internal PMM state
+ * @return MALI_TRUE if the pending cores to power down have acknowledged they
+ * can power down, else MALI_FALSE
+ */
+mali_bool pmm_power_down_okay( _mali_pmm_internal_state_t *pmm );
+
+/** @brief Try to make all the pending cores power down
+ *
+ * If all the pending cores have acknowledged they can power down, this will call the
+ * PMU power down function to turn them off
+ *
+ * @param pmm internal PMM state
+ * @return MALI_TRUE if the pending cores have been powered down, else MALI_FALSE
+ */
+mali_bool pmm_invoke_power_down( _mali_pmm_internal_state_t *pmm );
+
+/** @brief Check if all the pending cores to power up have done so
+ *
+ * This will report MALI_FALSE if some of the cores are still powered off
+ * and have not acknowledged that they have powered up
+ *
+ * @param pmm internal PMM state
+ * @return MALI_TRUE if the pending cores to power up have acknowledged they
+ * are now powered up, else MALI_FALSE
+ */
+mali_bool pmm_power_up_okay( _mali_pmm_internal_state_t *pmm );
+
+/** @brief Try to make all the pending cores power up
+ *
+ * If all the pending cores have acknowledged they have powered up, this will
+ * make the cores start processing jobs again, else this will call the PMU
+ * power up function to turn them on, and the PMM is then expected to wait for an
+ * interrupt to acknowledge the power up
+ *
+ * @param pmm internal PMM state
+ * @return MALI_TRUE if the pending cores have been powered up, else MALI_FALSE
+ */
+mali_bool pmm_invoke_power_up( _mali_pmm_internal_state_t *pmm );
+
+/** @brief Set the cores that are now active in the system
+ *
+ * Updates which cores are active and returns which cores are still idle
+ *
+ * @param pmm internal PMM state
+ * @param cores mask of cores to set to active
+ * @return mask of all the cores that are idle
+ */
+mali_pmm_core_mask pmm_cores_set_active( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores );
+
+/** @brief Set the cores that are now idle in the system
+ *
+ * Updates which cores are idle and returns which cores are still idle
+ *
+ * @param pmm internal PMM state
+ * @param cores mask of cores to set to idle
+ * @return mask of all the cores that are idle
+ */
+mali_pmm_core_mask pmm_cores_set_idle( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores );
+
+/** @brief Set the cores that have acknowledged a pending power down
+ *
+ * Updates which cores have acknowledged the pending power down and are now ready
+ * to be turned off
+ *
+ * @param pmm internal PMM state
+ * @param cores mask of cores that have acknowledged the pending power down
+ * @return mask of all the cores that have acknowledged the power down
+ */
+mali_pmm_core_mask pmm_cores_set_down_ack( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores );
+
+/** @brief Set the cores that have acknowledged a pending power up
+ *
+ * Updates which cores have acknowledged the pending power up and are now
+ * fully powered and ready to run jobs
+ *
+ * @param pmm internal PMM state
+ * @param cores mask of cores that have acknowledged the pending power up
+ * @return mask of all the cores that have acknowledged the power up
+ */
+mali_pmm_core_mask pmm_cores_set_up_ack( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores );
+
+
+/** @brief Tries to reset the PMM and PMU hardware to a known state after any fatal issues
+ *
+ * This will try and make all the cores powered up and reset the PMM state
+ * to its initial state after core registration - all cores powered but not
+ * pending or active.
+ * All events in the event queues will be thrown away.
+ *
+ * @note: Any pending power down will be cancelled including the OS calling for power down
+ */
+void pmm_fatal_reset( _mali_pmm_internal_state_t *pmm );
+
+/** @brief Save the OS specific data for an OS power up/down event
+ *
+ * @param pmm internal PMM state
+ * @param data OS specific event data
+ */
+void pmm_save_os_event_data(_mali_pmm_internal_state_t *pmm, mali_pmm_message_data data);
+
+/** @brief Retrieve the OS specific data for an OS power up/down event
+ *
+ * This will clear the stored OS data, as well as return it.
+ *
+ * @param pmm internal PMM state
+ * @return OS specific event data that was saved previously
+ */
+mali_pmm_message_data pmm_retrieve_os_event_data(_mali_pmm_internal_state_t *pmm);
+
+
+/** @brief Get a human readable name for the cores in a core mask
+ *
+ * @param core the core mask
+ * @return string containing a name relating to the given core mask
+ */
+const char *pmm_trace_get_core_name( mali_pmm_core_mask core );
+
+/** @} */ /* End group pmmapi_state */
+/** @} */ /* End group pmmapi */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MALI_PMM_STATE_H__ */
diff --git a/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm_system.h b/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm_system.h
new file mode 100644
index 00000000000..f5106479e33
--- /dev/null
+++ b/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/pmm/mali_pmm_system.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2010-2011 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * @file mali_pmm_system.h
+ * Defines the power management module system functions
+ */
+
+#ifndef __MALI_PMM_SYSTEM_H__
+#define __MALI_PMM_SYSTEM_H__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * @addtogroup pmmapi Power Management Module APIs
+ *
+ * @{
+ *
+ * @defgroup pmmapi_system Power Management Module System Functions
+ *
+ * @{
+ */
+
+extern struct mali_kernel_subsystem mali_subsystem_pmm;
+
+/** @brief Register a core with the PMM, which will power up
+ * the core
+ *
+ * @param core the core to register with the PMM
+ * @return error if the core cannot be powered up
+ */
+_mali_osk_errcode_t malipmm_core_register( mali_pmm_core_id core );
+
+/** @brief Unregister a core with the PMM
+ *
+ * @param core the core to unregister with the PMM
+ */
+void malipmm_core_unregister( mali_pmm_core_id core );
+
+/** @brief Acknowledge that a power down is okay to happen
+ *
+ * A core should not be running a job, or be in the idle queue when this
+ * is called.
+ *
+ * @param core the core that can now be powered down
+ */
+void malipmm_core_power_down_okay( mali_pmm_core_id core );
+
+/** @} */ /* End group pmmapi_system */
+/** @} */ /* End group pmmapi */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MALI_PMM_H__ */