3 * (C) COPYRIGHT 2010-2015 ARM Limited. All rights reserved.
5 * This program is free software and is provided to you under the terms of the
6 * GNU General Public License version 2 as published by the Free Software
7 * Foundation, and any use by you of this program is subject to the terms
10 * A copy of the licence is included with the program, and can also be obtained
11 * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
12 * Boston, MA 02110-1301, USA.
21 * @file mali_kbase_pm.c
22 * Base kernel power management APIs
24 #include <mali_kbase.h>
25 #include <mali_midg_regmap.h>
26 #include <mali_kbase_config_defaults.h>
27 #include <mali_kbase_instr.h>
29 #include <mali_kbase_pm.h>
31 int kbase_pm_powerup(struct kbase_device *kbdev, unsigned int flags)
33 return kbase_hwaccess_pm_powerup(kbdev, flags);
36 void kbase_pm_halt(struct kbase_device *kbdev)
38 kbase_hwaccess_pm_halt(kbdev);
41 void kbase_pm_context_active(struct kbase_device *kbdev)
43 (void)kbase_pm_context_active_handle_suspend(kbdev, KBASE_PM_SUSPEND_HANDLER_NOT_POSSIBLE);
46 int kbase_pm_context_active_handle_suspend(struct kbase_device *kbdev, enum kbase_pm_suspend_handler suspend_handler)
48 struct kbasep_js_device_data *js_devdata = &kbdev->js_data;
52 KBASE_DEBUG_ASSERT(kbdev != NULL);
54 /* Trace timeline information about how long it took to handle the decision
55 * to powerup. Sometimes the event might be missed due to reading the count
56 * outside of mutex, but this is necessary to get the trace timing
58 old_count = kbdev->pm.active_count;
60 kbase_timeline_pm_send_event(kbdev, KBASE_TIMELINE_PM_EVENT_GPU_ACTIVE);
62 mutex_lock(&js_devdata->runpool_mutex);
63 mutex_lock(&kbdev->pm.lock);
64 if (kbase_pm_is_suspending(kbdev)) {
65 switch (suspend_handler) {
66 case KBASE_PM_SUSPEND_HANDLER_DONT_REACTIVATE:
67 if (kbdev->pm.active_count != 0)
70 case KBASE_PM_SUSPEND_HANDLER_DONT_INCREASE:
71 mutex_unlock(&kbdev->pm.lock);
72 mutex_unlock(&js_devdata->runpool_mutex);
74 kbase_timeline_pm_handle_event(kbdev, KBASE_TIMELINE_PM_EVENT_GPU_ACTIVE);
77 case KBASE_PM_SUSPEND_HANDLER_NOT_POSSIBLE:
80 KBASE_DEBUG_ASSERT_MSG(false, "unreachable");
84 c = ++kbdev->pm.active_count;
85 KBASE_TIMELINE_CONTEXT_ACTIVE(kbdev, c);
86 KBASE_TRACE_ADD_REFCOUNT(kbdev, PM_CONTEXT_ACTIVE, NULL, NULL, 0u, c);
88 /* Trace the event being handled */
90 kbase_timeline_pm_handle_event(kbdev, KBASE_TIMELINE_PM_EVENT_GPU_ACTIVE);
93 /* First context active: Power on the GPU and any cores requested by
95 kbase_hwaccess_pm_gpu_active(kbdev);
97 mutex_unlock(&kbdev->pm.lock);
98 mutex_unlock(&js_devdata->runpool_mutex);
103 KBASE_EXPORT_TEST_API(kbase_pm_context_active);
105 void kbase_pm_context_idle(struct kbase_device *kbdev)
107 struct kbasep_js_device_data *js_devdata = &kbdev->js_data;
111 KBASE_DEBUG_ASSERT(kbdev != NULL);
113 /* Trace timeline information about how long it took to handle the decision
114 * to powerdown. Sometimes the event might be missed due to reading the
115 * count outside of mutex, but this is necessary to get the trace timing
117 old_count = kbdev->pm.active_count;
119 kbase_timeline_pm_send_event(kbdev, KBASE_TIMELINE_PM_EVENT_GPU_IDLE);
121 mutex_lock(&js_devdata->runpool_mutex);
122 mutex_lock(&kbdev->pm.lock);
124 c = --kbdev->pm.active_count;
125 KBASE_TIMELINE_CONTEXT_ACTIVE(kbdev, c);
126 KBASE_TRACE_ADD_REFCOUNT(kbdev, PM_CONTEXT_IDLE, NULL, NULL, 0u, c);
128 KBASE_DEBUG_ASSERT(c >= 0);
130 /* Trace the event being handled */
132 kbase_timeline_pm_handle_event(kbdev, KBASE_TIMELINE_PM_EVENT_GPU_IDLE);
135 /* Last context has gone idle */
136 kbase_hwaccess_pm_gpu_idle(kbdev);
138 /* Wake up anyone waiting for this to become 0 (e.g. suspend). The
139 * waiters must synchronize with us by locking the pm.lock after
141 wake_up(&kbdev->pm.zero_active_count_wait);
144 mutex_unlock(&kbdev->pm.lock);
145 mutex_unlock(&js_devdata->runpool_mutex);
148 KBASE_EXPORT_TEST_API(kbase_pm_context_idle);
150 void kbase_pm_suspend(struct kbase_device *kbdev)
152 KBASE_DEBUG_ASSERT(kbdev);
154 mutex_lock(&kbdev->pm.lock);
155 KBASE_DEBUG_ASSERT(!kbase_pm_is_suspending(kbdev));
156 kbdev->pm.suspending = true;
157 mutex_unlock(&kbdev->pm.lock);
159 /* From now on, the active count will drop towards zero. Sometimes, it'll
160 * go up briefly before going down again. However, once it reaches zero it
161 * will stay there - guaranteeing that we've idled all pm references */
163 /* Suspend job scheduler and associated components, so that it releases all
164 * the PM active count references */
165 kbasep_js_suspend(kbdev);
167 /* Suspend any counter collection that might be happening */
168 kbase_instr_hwcnt_suspend(kbdev);
170 /* Wait for the active count to reach zero. This is not the same as
171 * waiting for a power down, since not all policies power down when this
173 wait_event(kbdev->pm.zero_active_count_wait, kbdev->pm.active_count == 0);
175 /* NOTE: We synchronize with anything that was just finishing a
176 * kbase_pm_context_idle() call by locking the pm.lock below */
178 kbase_hwaccess_pm_suspend(kbdev);
181 void kbase_pm_resume(struct kbase_device *kbdev)
183 /* MUST happen before any pm_context_active calls occur */
184 kbase_hwaccess_pm_resume(kbdev);
186 /* Initial active call, to power on the GPU/cores if needed */
187 kbase_pm_context_active(kbdev);
189 /* Re-enable instrumentation, if it was previously disabled */
190 kbase_instr_hwcnt_resume(kbdev);
192 /* Resume any blocked atoms (which may cause contexts to be scheduled in
193 * and dependent atoms to run) */
194 kbase_resume_suspended_soft_jobs(kbdev);
196 /* Resume the Job Scheduler and associated components, and start running
198 kbasep_js_resume(kbdev);
200 /* Matching idle call, to power off the GPU/cores if we didn't actually
201 * need it and the policy doesn't want it on */
202 kbase_pm_context_idle(kbdev);