2 * Copyright (C) 2010-2014 ARM Limited. All rights reserved.
4 * This program is free software and is provided to you under the terms of the GNU General Public License version 2
5 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
7 * A copy of the licence is included with the program, and can also be obtained from Free Software
8 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
13 * Mali driver functions for Mali 400 PMU hardware
15 #include "mali_hw_core.h"
18 #include "mali_kernel_common.h"
21 #include "mali_osk_mali.h"
23 struct mali_pmu_core *mali_global_pmu_core = NULL;
25 static _mali_osk_errcode_t mali_pmu_wait_for_command_finish(
26 struct mali_pmu_core *pmu);
28 struct mali_pmu_core *mali_pmu_create(_mali_osk_resource_t *resource)
30 struct mali_pmu_core *pmu;
32 MALI_DEBUG_ASSERT(NULL == mali_global_pmu_core);
33 MALI_DEBUG_PRINT(2, ("Mali PMU: Creating Mali PMU core\n"));
35 pmu = (struct mali_pmu_core *)_mali_osk_malloc(
36 sizeof(struct mali_pmu_core));
38 pmu->registered_cores_mask = 0; /* to be set later */
40 if (_MALI_OSK_ERR_OK == mali_hw_core_create(&pmu->hw_core,
41 resource, PMU_REGISTER_ADDRESS_SPACE_SIZE)) {
43 pmu->switch_delay = _mali_osk_get_pmu_switch_delay();
45 mali_global_pmu_core = pmu;
55 void mali_pmu_delete(struct mali_pmu_core *pmu)
57 MALI_DEBUG_ASSERT_POINTER(pmu);
58 MALI_DEBUG_ASSERT(pmu == mali_global_pmu_core);
60 MALI_DEBUG_PRINT(2, ("Mali PMU: Deleting Mali PMU core\n"));
62 mali_global_pmu_core = NULL;
64 mali_hw_core_delete(&pmu->hw_core);
68 void mali_pmu_set_registered_cores_mask(struct mali_pmu_core *pmu, u32 mask)
70 pmu->registered_cores_mask = mask;
73 void mali_pmu_reset(struct mali_pmu_core *pmu)
75 MALI_DEBUG_ASSERT_POINTER(pmu);
76 MALI_DEBUG_ASSERT(pmu->registered_cores_mask != 0);
78 /* Setup the desired defaults */
79 mali_hw_core_register_write_relaxed(&pmu->hw_core,
80 PMU_REG_ADDR_MGMT_INT_MASK, 0);
81 mali_hw_core_register_write_relaxed(&pmu->hw_core,
82 PMU_REG_ADDR_MGMT_SW_DELAY, pmu->switch_delay);
85 void mali_pmu_power_up_all(struct mali_pmu_core *pmu)
89 MALI_DEBUG_ASSERT_POINTER(pmu);
90 MALI_DEBUG_ASSERT(pmu->registered_cores_mask != 0);
96 /* Now simply power up the domains which are marked as powered down */
97 stat = mali_hw_core_register_read(&pmu->hw_core,
98 PMU_REG_ADDR_MGMT_STATUS);
99 mali_pmu_power_up(pmu, stat);
101 mali_pm_exec_unlock();
104 void mali_pmu_power_down_all(struct mali_pmu_core *pmu)
108 MALI_DEBUG_ASSERT_POINTER(pmu);
109 MALI_DEBUG_ASSERT(pmu->registered_cores_mask != 0);
113 /* Now simply power down the domains which are marked as powered up */
114 stat = mali_hw_core_register_read(&pmu->hw_core,
115 PMU_REG_ADDR_MGMT_STATUS);
116 mali_pmu_power_down(pmu, (~stat) & pmu->registered_cores_mask);
118 mali_pm_exec_unlock();
121 _mali_osk_errcode_t mali_pmu_power_down(struct mali_pmu_core *pmu, u32 mask)
124 _mali_osk_errcode_t err;
126 MALI_DEBUG_ASSERT_POINTER(pmu);
127 MALI_DEBUG_ASSERT(pmu->registered_cores_mask != 0);
128 MALI_DEBUG_ASSERT(mask <= pmu->registered_cores_mask);
129 MALI_DEBUG_ASSERT(0 == (mali_hw_core_register_read(&pmu->hw_core,
130 PMU_REG_ADDR_MGMT_INT_RAWSTAT) &
134 ("PMU power down: ...................... [%s]\n",
135 mali_pm_mask_to_string(mask)));
137 stat = mali_hw_core_register_read(&pmu->hw_core,
138 PMU_REG_ADDR_MGMT_STATUS);
141 * Assert that we are not powering down domains which are already
144 MALI_DEBUG_ASSERT(0 == (stat & mask));
146 if (0 == mask || 0 == ((~stat) & mask)) return _MALI_OSK_ERR_OK;
148 mali_hw_core_register_write(&pmu->hw_core,
149 PMU_REG_ADDR_MGMT_POWER_DOWN, mask);
152 * Do not wait for interrupt on Mali-300/400 if all domains are
153 * powered off by our power down command, because the HW will simply
154 * not generate an interrupt in this case.
156 if (mali_is_mali450() || pmu->registered_cores_mask != (mask | stat)) {
157 err = mali_pmu_wait_for_command_finish(pmu);
158 if (_MALI_OSK_ERR_OK != err) {
162 mali_hw_core_register_write(&pmu->hw_core,
163 PMU_REG_ADDR_MGMT_INT_CLEAR, PMU_REG_VAL_IRQ);
166 return _MALI_OSK_ERR_OK;
169 _mali_osk_errcode_t mali_pmu_power_up(struct mali_pmu_core *pmu, u32 mask)
172 _mali_osk_errcode_t err;
173 #if !defined(CONFIG_MALI_PMU_PARALLEL_POWER_UP)
177 MALI_DEBUG_ASSERT_POINTER(pmu);
178 MALI_DEBUG_ASSERT(pmu->registered_cores_mask != 0);
179 MALI_DEBUG_ASSERT(mask <= pmu->registered_cores_mask);
180 MALI_DEBUG_ASSERT(0 == (mali_hw_core_register_read(&pmu->hw_core,
181 PMU_REG_ADDR_MGMT_INT_RAWSTAT) &
185 ("PMU power up: ........................ [%s]\n",
186 mali_pm_mask_to_string(mask)));
188 stat = mali_hw_core_register_read(&pmu->hw_core,
189 PMU_REG_ADDR_MGMT_STATUS);
190 stat &= pmu->registered_cores_mask;
191 if (0 == mask || 0 == (stat & mask)) return _MALI_OSK_ERR_OK;
194 * Assert that we are only powering up domains which are currently
197 MALI_DEBUG_ASSERT(mask == (stat & mask));
199 #if defined(CONFIG_MALI_PMU_PARALLEL_POWER_UP)
200 mali_hw_core_register_write(&pmu->hw_core,
201 PMU_REG_ADDR_MGMT_POWER_UP, mask);
203 err = mali_pmu_wait_for_command_finish(pmu);
204 if (_MALI_OSK_ERR_OK != err) {
208 for (current_domain = 1;
209 current_domain <= pmu->registered_cores_mask;
210 current_domain <<= 1) {
211 if (current_domain & mask & stat) {
212 mali_hw_core_register_write(&pmu->hw_core,
213 PMU_REG_ADDR_MGMT_POWER_UP,
216 err = mali_pmu_wait_for_command_finish(pmu);
217 if (_MALI_OSK_ERR_OK != err) {
224 return _MALI_OSK_ERR_OK;
227 static _mali_osk_errcode_t mali_pmu_wait_for_command_finish(
228 struct mali_pmu_core *pmu)
231 u32 timeout = MALI_REG_POLL_COUNT_SLOW;
233 MALI_DEBUG_ASSERT(pmu);
235 /* Wait for the command to complete */
237 rawstat = mali_hw_core_register_read(&pmu->hw_core,
238 PMU_REG_ADDR_MGMT_INT_RAWSTAT);
240 } while (0 == (rawstat & PMU_REG_VAL_IRQ) && 0 < timeout);
242 MALI_DEBUG_ASSERT(0 < timeout);
245 return _MALI_OSK_ERR_TIMEOUT;
248 mali_hw_core_register_write(&pmu->hw_core,
249 PMU_REG_ADDR_MGMT_INT_CLEAR, PMU_REG_VAL_IRQ);
251 return _MALI_OSK_ERR_OK;